CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ssri

Standard Subresource Integrity library that parses, serializes, generates, and verifies integrity metadata according to the SRI spec.

Pending
Overview
Eval results
Files

verification.mddocs/

Integrity Verification

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.

Capabilities

Check Data Function

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
});

Check Stream Function

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;
  });

Integrity Stream Function

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');
});

Verification Options

Error Handling Configuration

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;
}

Algorithm Selection

// 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 });

Error Types and Handling

EINTEGRITY Errors

// 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');
  }
}

EBADSIZE Errors

// 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());
  }
}

Stream Error Handling

// 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.
    }
  });

Verification Patterns

Package Manager Verification

// 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;
  }
}

CDN Resource Verification

// 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 };
}

Build Artifact Verification

// 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;
}

Streaming Pipeline Verification

// 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

docs

generation.md

index.md

parsing-serialization.md

verification.md

tile.json