open-webui/scripts/encryption/artifact.mjs
Timothy Jaeryang Baek 7dc91de86c refac
2026-10-15 17:08:00 +04:00

71 lines
2.4 KiB
JavaScript

// Normal builds only read committed files. No Rust or network required.
import { createHash } from 'node:crypto';
import { readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { join, relative } from 'node:path';
const root = new URL('../../', import.meta.url).pathname;
const source = 'crypto/encryption';
const artifact = 'src/lib/encryption/vendor';
const hash = (data) => createHash('sha256').update(data).digest('hex');
function files(dir) {
return readdirSync(join(root, dir), { withFileTypes: true })
.flatMap((e) => {
if (e.name === 'target' || e.name.startsWith('.')) return [];
const path = join(dir, e.name);
return e.isDirectory() ? files(path) : [path];
})
.sort();
}
const inputs = [
...files(source),
'scripts/encryption/build.py',
'scripts/encryption/artifact.mjs'
].sort();
const sourceFingerprint = hash(
inputs.map((p) => `${p}\0${hash(readFileSync(join(root, p)))}`).join('\n')
);
const manifestPath = join(root, artifact, 'manifest.json');
if (process.argv.includes('--write')) {
const metadata = JSON.parse(
readFileSync(process.argv[process.argv.indexOf('--metadata') + 1], 'utf8')
);
const checksums = Object.fromEntries(
files(artifact)
.filter((p) => !p.endsWith('/manifest.json'))
.map((p) => [relative(artifact, p), hash(readFileSync(join(root, p)))])
);
writeFileSync(
manifestPath,
JSON.stringify(
{
format: 1,
sourceFingerprint,
sourceRevision: process.env.CRYPTO_SOURCE_REVISION,
toolchain: '1.95.0',
wasmBindgen: '0.2.126',
dependencies: metadata.packages.map(({ name, version, license }) => ({
name,
version,
license
})),
checksums
},
null,
2
) + '\n'
);
} else {
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
if (manifest.sourceFingerprint !== sourceFingerprint)
throw Error('Encryption source changed: rebuild and review the artifact.');
const actual = files(artifact)
.filter((p) => !p.endsWith('/manifest.json'))
.map((p) => relative(artifact, p))
.sort();
if (JSON.stringify(actual) !== JSON.stringify(Object.keys(manifest.checksums).sort()))
throw Error('Unexpected crypto artifact files');
for (const [p, digest] of Object.entries(manifest.checksums)) {
if (hash(readFileSync(join(root, artifact, p))) !== digest)
throw Error(`Crypto artifact checksum mismatch: ${p}`);
}
console.log('Encryption artifact source and checksums verified');
}