85 lines
2.6 KiB
JavaScript
85 lines
2.6 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import crypto from 'node:crypto'
|
|
import fsp from 'node:fs/promises'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
import { pathToFileURL } from 'node:url'
|
|
import { build } from 'esbuild'
|
|
import {
|
|
DEFAULT_BASE_URL,
|
|
DEFAULT_PUBLIC_KEY,
|
|
REPO_ROOT,
|
|
generateEd25519KeyPair,
|
|
normalizeBaseUrl,
|
|
readPublicKey,
|
|
signPayload
|
|
} from './lib.mjs'
|
|
|
|
async function main() {
|
|
const temporary = await fsp.mkdtemp(path.join(os.tmpdir(), 'ycode-contract-selftest-'))
|
|
try {
|
|
const bundlePath = path.join(temporary, 'manifest.mjs')
|
|
await build({
|
|
entryPoints: [path.join(REPO_ROOT, 'src', 'main', 'updates', 'manifest.ts')],
|
|
bundle: true,
|
|
platform: 'node',
|
|
format: 'esm',
|
|
outfile: bundlePath,
|
|
logLevel: 'silent'
|
|
})
|
|
const backend = await import(`${pathToFileURL(bundlePath).href}?v=${Date.now()}`)
|
|
assert.equal(typeof backend.verifySignedManifest, 'function')
|
|
|
|
const trustAnchor = await readPublicKey(DEFAULT_PUBLIC_KEY)
|
|
const trustKey = crypto.createPublicKey(trustAnchor)
|
|
assert.equal(trustKey.asymmetricKeyType, 'ed25519')
|
|
|
|
const keys = generateEd25519KeyPair()
|
|
const baseUrl = normalizeBaseUrl(DEFAULT_BASE_URL)
|
|
const payload = {
|
|
schemaVersion: 1,
|
|
version: '9.9.9',
|
|
publishedAt: '2026-10-20T10:00:00.000Z',
|
|
notes: { zh: '契约自测', en: 'Contract self-test' },
|
|
platforms: {
|
|
'windows-x64': {
|
|
url: `${baseUrl}versions/9.9.9/YCode-9.9.9-Setup-x64.exe`,
|
|
size: 123,
|
|
sha256: 'a'.repeat(64)
|
|
}
|
|
}
|
|
}
|
|
const document = {
|
|
payload,
|
|
signature: signPayload(payload, keys.privatePem)
|
|
}
|
|
const raw = Buffer.from(`${JSON.stringify(document)}\n`, 'utf8')
|
|
const verified = backend.verifySignedManifest(raw, {
|
|
manifestUrl: `${baseUrl}latest.json`,
|
|
publicKeyPem: keys.publicPem
|
|
})
|
|
assert.equal(verified.payload.version, payload.version)
|
|
assert.equal(verified.asset.url, payload.platforms['windows-x64'].url)
|
|
|
|
const tampered = structuredClone(document)
|
|
tampered.payload.notes.en = 'tampered'
|
|
assert.throws(
|
|
() => backend.verifySignedManifest(Buffer.from(JSON.stringify(tampered), 'utf8'), {
|
|
manifestUrl: `${baseUrl}latest.json`,
|
|
publicKeyPem: keys.publicPem
|
|
}),
|
|
/签名验证失败/
|
|
)
|
|
|
|
console.log('Release manifest matches update_backend parser/signature/path policy.')
|
|
console.log('Repository public key is a valid Ed25519 SPKI PEM trust anchor.')
|
|
} finally {
|
|
await fsp.rm(temporary, { recursive: true, force: true })
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error)
|
|
process.exitCode = 1
|
|
})
|