47 lines
2.0 KiB
JavaScript
47 lines
2.0 KiB
JavaScript
import { createHash } from 'node:crypto';
|
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
import { resolve } from 'node:path';
|
|
|
|
async function hasFiles(directory) {
|
|
const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
for (const entry of entries) {
|
|
if (entry.isFile()) return true;
|
|
if (entry.isDirectory() && await hasFiles(resolve(directory, entry.name))) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export async function validateLearningPlayerArtifact(directory) {
|
|
const root = resolve(directory);
|
|
const [artifactText, html] = await Promise.all([
|
|
readFile(resolve(root, 'artifact.json'), 'utf8'),
|
|
readFile(resolve(root, 'index.html')),
|
|
]).catch((error) => {
|
|
throw new Error(`Invalid learning player artifact at ${root}: ${error.message}`);
|
|
});
|
|
const artifact = JSON.parse(artifactText);
|
|
if (artifact.schemaVersion !== 1
|
|
|| artifact.entrypoint !== 'index.html'
|
|
|| typeof artifact.htmlSha256 !== 'string'
|
|
|| !/^[0-9a-f]{64}$/.test(artifact.htmlSha256)) {
|
|
throw new Error(`Invalid learning player artifact manifest at ${root}`);
|
|
}
|
|
const htmlSha256 = createHash('sha256').update(html).digest('hex');
|
|
if (htmlSha256 !== artifact.htmlSha256) {
|
|
throw new Error(`Learning player index hash mismatch at ${root}`);
|
|
}
|
|
if (!(await stat(resolve(root, '_next', 'static')).then((entry) => entry.isDirectory()).catch(() => false))
|
|
|| !await hasFiles(resolve(root, '_next', 'static'))) {
|
|
throw new Error(`Learning player static assets are missing at ${root}`);
|
|
}
|
|
if (!(await stat(resolve(root, 'avatars')).then((entry) => entry.isDirectory()).catch(() => false))
|
|
|| !await hasFiles(resolve(root, 'avatars'))) {
|
|
throw new Error(`Learning player avatars are missing at ${root}`);
|
|
}
|
|
if (!(await stat(resolve(root, 'public')).then((entry) => entry.isDirectory()).catch(() => false))
|
|
|| !await hasFiles(resolve(root, 'public'))) {
|
|
throw new Error(`Learning player public assets are missing at ${root}`);
|
|
}
|
|
return { root, artifact, htmlSha256 };
|
|
}
|