Standard Subresource Integrity library that parses, serializes, generates, and verifies integrity metadata according to the SRI spec.
—
Verify data integrity against existing SRI hashes with comprehensive error reporting. Supports both synchronous data verification and asynchronous stream verification with detailed error handling and algorithm selection.
Synchronously verifies string or Buffer data against integrity hashes with optional error throwing.
/**
* Verifies data against integrity string or object
* @param {string|Buffer} data - Data to verify
* @param {string|object} sri - Integrity string/object to verify against
* @param {object} opts - Optional configuration
* @param {boolean} opts.error - Throw error on mismatch instead of returning false
* @param {number} opts.size - Expected data size in bytes
* @param {function} opts.pickAlgorithm - Custom algorithm selection function
* @returns {Hash|false} Matching hash on success, false on failure
* @throws {Error} When opts.error is true and verification fails
*/
function checkData(data, sri, opts);Usage Examples:
const ssri = require('ssri');
const fs = require('fs');
// Basic verification
const data = fs.readFileSync('./package.json');
const integrity = 'sha512-abc123...';
const result = ssri.checkData(data, integrity);
if (result) {
console.log('Data verified with algorithm:', result.algorithm);
} else {
console.log('Verification failed!');
}
// Verification with error throwing
try {
const verified = ssri.checkData(data, integrity, { error: true });
console.log('Success:', verified.algorithm);
} catch (err) {
if (err.code === 'EINTEGRITY') {
console.error('Integrity check failed:', err.message);
console.error('Expected:', err.expected);
console.error('Found:', err.found);
} else if (err.code === 'EBADSIZE') {
console.error('Size mismatch:', err.message);
console.error('Expected size:', err.expected);
console.error('Actual size:', err.found);
}
}
// Size verification
const withSize = ssri.checkData(data, integrity, {
size: 1024,
error: true
});
// Multiple algorithm support
const multiIntegrity = 'sha256-def456 sha512-abc123';
const match = ssri.checkData(data, multiIntegrity);
// Returns the hash that matched (highest priority algorithm)
// Custom algorithm picker
const customMatch = ssri.checkData(data, multiIntegrity, {
pickAlgorithm: (alg1, alg2) => alg1 === 'sha256' ? alg1 : alg2
});Asynchronously verifies stream data against integrity hashes, consuming the entire stream.
/**
* Verifies stream contents against integrity string or object
* @param {ReadableStream} stream - Stream to verify (will be consumed)
* @param {string|object} sri - Integrity string/object to verify against
* @param {object} opts - Optional configuration (same as checkData)
* @returns {Promise<Hash>} Promise resolving to matching hash on success
* @throws {Error} Promise rejected with detailed error on failure
*/
function checkStream(stream, sri, opts);Usage Examples:
const ssri = require('ssri');
const fs = require('fs');
const https = require('https');
// File stream verification
const fileStream = fs.createReadStream('./download.zip');
const expectedIntegrity = 'sha384-def789...';
ssri.checkStream(fileStream, expectedIntegrity)
.then(hash => {
console.log('File verified successfully:', hash.algorithm);
})
.catch(err => {
if (err.code === 'EINTEGRITY') {
console.error('File corruption detected!');
console.error('Expected:', err.expected.toString());
console.error('Actual:', err.found.toString());
}
});
// HTTP stream verification
https.get('https://cdn.example.com/library.js', (response) => {
const cdnIntegrity = 'sha384-abc123...';
ssri.checkStream(response, cdnIntegrity, {
size: parseInt(response.headers['content-length'])
})
.then(result => {
console.log('CDN resource verified:', result.algorithm);
})
.catch(err => {
console.error('CDN verification failed:', err.message);
// Handle compromised or corrupted CDN resource
});
});
// Pipe and verify pattern
const input = fs.createReadStream('./input.dat');
const output = fs.createWriteStream('./output.dat');
input.pipe(output);
ssri.checkStream(input, knownIntegrity)
.then(() => console.log('Stream processed and verified'))
.catch(err => {
// Clean up output file on verification failure
fs.unlinkSync('./output.dat');
throw err;
});Creates a transform stream for real-time integrity generation and optional verification during data processing.
/**
* Creates IntegrityStream for generation and verification
* @param {object} opts - Optional configuration
* @param {string[]} opts.algorithms - Algorithms for generation (default: ['sha512'])
* @param {string|object} opts.integrity - Integrity to verify against
* @param {number} opts.size - Expected stream size
* @param {boolean} opts.single - Return single Hash instead of Integrity
* @param {function} opts.pickAlgorithm - Custom algorithm selection
* @returns {IntegrityStream} Transform stream instance
*/
function integrityStream(opts);
class IntegrityStream extends Minipass {
// Events:
// - 'size': Emitted with total byte count
// - 'integrity': Emitted with calculated Integrity object
// - 'verified': Emitted with matching hash if verification succeeds
// - 'error': Emitted on verification failure or size mismatch
}Usage Examples:
const ssri = require('ssri');
const fs = require('fs');
// Generate integrity while processing
const input = fs.createReadStream('./source.txt');
const output = fs.createWriteStream('./dest.txt');
const integrityStream = ssri.integrityStream({
algorithms: ['sha256', 'sha512']
});
input.pipe(integrityStream).pipe(output);
integrityStream.on('integrity', (integrity) => {
console.log('Generated integrity:', integrity.toString());
// Save integrity for later verification
fs.writeFileSync('./dest.txt.integrity', integrity.toString());
});
integrityStream.on('size', (size) => {
console.log('Processed bytes:', size);
});
// Verify while processing
const verifyingStream = ssri.integrityStream({
integrity: 'sha512-expected...',
size: 1024
});
input.pipe(verifyingStream).pipe(output);
verifyingStream.on('verified', (hash) => {
console.log('Stream verified:', hash.algorithm);
});
verifyingStream.on('error', (err) => {
if (err.code === 'EINTEGRITY') {
console.error('Stream integrity failure:', err.message);
} else if (err.code === 'EBADSIZE') {
console.error('Stream size mismatch:', err.message);
}
// Stop processing and clean up
output.destroy();
});
// Concurrent generation and verification
const dualStream = ssri.integrityStream({
algorithms: ['sha384'], // Generate new integrity
integrity: knownIntegrity, // Verify against existing
});
input.pipe(dualStream).pipe(output);
dualStream.on('integrity', (generated) => {
console.log('Generated:', generated.toString());
});
dualStream.on('verified', (verified) => {
console.log('Verified against existing integrity');
});interface VerificationOptions {
/** Throw detailed errors instead of returning false/rejected promises */
error?: boolean;
/** Expected data size in bytes for additional validation */
size?: number;
/** Custom function to select algorithm from multiple options */
pickAlgorithm?: (algorithm1: string, algorithm2: string) => string;
}// Default algorithm priority (strongest to weakest)
// Note: Higher index = stronger algorithm
const DEFAULT_PRIORITY = [
'md5', 'whirlpool', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
'sha3', 'sha3-256', 'sha3-384', 'sha3-512', 'sha3_256', 'sha3_384', 'sha3_512'
// Filtered to algorithms available in current Node.js via crypto.getHashes()
];
// Custom algorithm picker
const customPicker = (alg1, alg2) => {
// Always prefer SHA-512 if available
if (alg1 === 'sha512') return alg1;
if (alg2 === 'sha512') return alg2;
// Fall back to default priority
return DEFAULT_PRIORITY.indexOf(alg1) >= DEFAULT_PRIORITY.indexOf(alg2)
? alg1 : alg2;
};
ssri.checkData(data, multiIntegrity, { pickAlgorithm: customPicker });// Integrity verification failure
try {
ssri.checkData(data, integrity, { error: true });
} catch (err) {
if (err.code === 'EINTEGRITY') {
console.error('Integrity check failed');
console.error('Algorithm used:', err.algorithm);
console.error('Expected integrity:', err.expected.toString());
console.error('Actual integrity:', err.found.toString());
console.error('Data size:', err.sri ? 'included' : 'not included');
}
}// Size verification failure
try {
ssri.checkData(data, integrity, { size: 1000, error: true });
} catch (err) {
if (err.code === 'EBADSIZE') {
console.error('Size mismatch detected');
console.error('Expected size:', err.expected);
console.error('Actual size:', err.found);
console.error('Integrity used:', err.sri.toString());
}
}// Comprehensive stream error handling
ssri.checkStream(stream, integrity, { size: 2048 })
.then(hash => {
console.log('Stream verification successful:', hash);
})
.catch(err => {
switch (err.code) {
case 'EINTEGRITY':
console.error('Stream data corrupted or modified');
// Notify monitoring systems, retry download, etc.
break;
case 'EBADSIZE':
console.error('Stream size unexpected, possible incomplete download');
// Retry with resume capability if supported
break;
default:
console.error('Stream error:', err.message);
// Handle network errors, file system errors, etc.
}
});// npm package verification pattern
async function verifyPackage(packagePath, packageLock) {
const packageData = fs.readFileSync(packagePath);
const expectedIntegrity = packageLock.packages[packageName].integrity;
try {
const result = ssri.checkData(packageData, expectedIntegrity, {
error: true
});
console.log(`Package ${packageName} verified with ${result.algorithm}`);
return true;
} catch (err) {
console.error(`Package ${packageName} failed verification:`, err.message);
return false;
}
}// Browser-style CDN verification
async function verifyCDNResource(url, expectedIntegrity) {
const response = await fetch(url);
const data = await response.text();
const result = ssri.checkData(data, expectedIntegrity);
if (!result) {
throw new Error(`CDN resource ${url} failed integrity check`);
}
return { data, algorithm: result.algorithm };
}// CI/CD build verification
function verifyBuildArtifacts(artifactDir, integrityManifest) {
const results = {};
Object.entries(integrityManifest).forEach(([file, expectedIntegrity]) => {
const filePath = path.join(artifactDir, file);
if (!fs.existsSync(filePath)) {
results[file] = { status: 'missing' };
return;
}
try {
const data = fs.readFileSync(filePath);
const verified = ssri.checkData(data, expectedIntegrity, { error: true });
results[file] = {
status: 'verified',
algorithm: verified.algorithm
};
} catch (err) {
results[file] = {
status: 'failed',
error: err.message,
code: err.code
};
}
});
return results;
}// Real-time processing with verification
function createVerifiedPipeline(input, output, expectedIntegrity) {
const verifier = ssri.integrityStream({
integrity: expectedIntegrity,
algorithms: ['sha256'] // Also generate new integrity
});
const pipeline = input.pipe(verifier).pipe(output);
verifier.on('verified', (hash) => {
console.log('Pipeline data verified:', hash.algorithm);
});
verifier.on('integrity', (newIntegrity) => {
console.log('New integrity generated:', newIntegrity.toString());
});
verifier.on('error', (err) => {
console.error('Pipeline verification failed:', err.message);
// Cleanup and abort pipeline
pipeline.destroy();
output.destroy();
});
return pipeline;
}Install with Tessl CLI
npx tessl i tessl/npm-ssri