@mdfriday/foundry
Version:
The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.
113 lines • 4.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IntegrityClient = void 0;
const crypto_1 = require("crypto");
const resources_1 = require("../../../domain/resources");
const DEFAULT_HASH_ALGO = 'sha256';
/**
* IntegrityClient provides fingerprinting and integrity generation for resources
* This implements the Fingerprint operation
*/
class IntegrityClient {
async fingerprint(resource, algo = DEFAULT_HASH_ALGO) {
const transformation = new FingerprintTransformation(algo);
return resource.transform(transformation);
}
generateIntegrity(content) {
const hash = (0, crypto_1.createHash)('sha256').update(content, 'utf8').digest('base64');
return `sha256-${hash}`;
}
// Additional integrity methods
generateSHA384(content) {
const hash = (0, crypto_1.createHash)('sha384').update(content, 'utf8').digest('base64');
return `sha384-${hash}`;
}
generateSHA512(content) {
const hash = (0, crypto_1.createHash)('sha512').update(content, 'utf8').digest('base64');
return `sha512-${hash}`;
}
// Verify integrity
verifyIntegrity(content, integrity) {
const [algorithm, expectedHash] = integrity.split('-', 2);
let actualHash;
switch (algorithm) {
case 'sha256':
actualHash = (0, crypto_1.createHash)('sha256').update(content, 'utf8').digest('base64');
break;
case 'sha384':
actualHash = (0, crypto_1.createHash)('sha384').update(content, 'utf8').digest('base64');
break;
case 'sha512':
actualHash = (0, crypto_1.createHash)('sha512').update(content, 'utf8').digest('base64');
break;
default:
return false;
}
return actualHash === expectedHash;
}
}
exports.IntegrityClient = IntegrityClient;
class FingerprintTransformation {
constructor(algo) {
this.algo = algo;
}
key() {
return resources_1.ResourceTransformationKey.newResourceTransformationKey('fingerprint', this.algo);
}
async transform(ctx) {
const hash = this.newHash(this.algo);
// Read from source and calculate hash
let content = '';
const chunks = [];
ctx.source.from.on('data', (chunk) => {
hash.update(chunk);
chunks.push(chunk);
content += chunk.toString();
});
await new Promise((resolve, reject) => {
ctx.source.from.on('end', () => {
try {
const digest = hash.digest();
const hexDigest = digest.toString('hex');
// Set integrity data
ctx.data['Integrity'] = this.integrity(this.algo, digest);
// Add hash to filename using the standard mechanism
// Use only first 12 characters for shorter filenames
const shortHash = hexDigest.substring(0, 12);
ctx.addOutPathIdentifier('.' + shortHash);
// Write content to target
for (const chunk of chunks) {
ctx.target.to.write(chunk);
}
ctx.target.to.end();
resolve();
}
catch (error) {
reject(error);
}
});
ctx.source.from.on('error', reject);
});
}
newHash(algo) {
switch (algo) {
case 'md5':
return (0, crypto_1.createHash)('md5');
case 'sha256':
return (0, crypto_1.createHash)('sha256');
case 'sha384':
return (0, crypto_1.createHash)('sha384');
case 'sha512':
return (0, crypto_1.createHash)('sha512');
default:
throw new Error(`Unsupported hash algorithm: "${algo}", use either md5, sha256, sha384 or sha512`);
}
}
// Create integrity string for Subresource Integrity
// See https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
integrity(algo, digest) {
const encoded = digest.toString('base64');
return `${algo}-${encoded}`;
}
}
//# sourceMappingURL=integrity.js.map