import test from 'node:test'; import assert from 'node:assert/strict'; import { createHash, generateKeyPairSync, sign } from 'node:crypto'; import { createNodePossessionChallenge, nodePossessionChallengeSigningBytes, verifyNodePossessionResponse, } from './node-possession-proof.js'; import { nodeRegistrationClaimSigningBytes, parseNodeRegistrationEndpointRegistry, resolveNodeRegistrationEndpoint, verifyNodeRegistrationClaim, } from './node-registration.js'; const NOW = 1_786_291_200_000; const DOMAIN_ID = 'DOM-FIFTH-0001'; const NODE_ID = 'LOCAL-001'; const registrationKeys = generateKeyPairSync('ed25519'); const nodeKeys = generateKeyPairSync('ed25519'); const nodePublicKeyPem = nodeKeys.publicKey.export({ format: 'pem', type: 'spki' }).toString(); const fingerprint = createHash('sha256') .update(nodeKeys.publicKey.export({ format: 'der', type: 'spki' })) .digest('hex'); function verifiedRegistration() { const registry = parseNodeRegistrationEndpointRegistry({ endpoints: [{ algorithm: 'Ed25519', domainIds: [DOMAIN_ID], endpointId: 'GH-NODE-REG-001', nodeTypes: ['local-terminal'], publicKeyPem: registrationKeys.publicKey.export({ format: 'pem', type: 'spki' }).toString(), signerId: 'GH-NODE-REG-SIGNER-001', status: 'ACTIVE', url: 'https://guanghulab.com/api/ai/v1/node-registrations/claims', }], registryId: 'GH-AIOS-NODE-REGISTRATION-ENDPOINTS-001', schema: 'gh-aios.node-registration-endpoints/v1', state: 'CURRENT', version: '1.0.0', }, { repositoryId: 'REPO-012', sourceCommit: 'a'.repeat(40), sourceUrl: `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${'a'.repeat(40)}/routing/node-registration-endpoints.json`, }); const endpoint = resolveNodeRegistrationEndpoint(registry, { domainId: DOMAIN_ID, nodeType: 'local-terminal', }); assert.ok(endpoint); const payload = { accountId: 'bingshuo', claimId: 'NODE-CLAIM-001', domainId: DOMAIN_ID, endpointId: endpoint.endpointId, expiresAt: NOW + 120_000, issuedAt: NOW - 1_000, nodeId: NODE_ID, nodeKeyFingerprint: fingerprint, nodeType: 'local-terminal' as const, schema: 'gh-aios.node-registration-claim/v1' as const, signerId: endpoint.signerId, }; return verifyNodeRegistrationClaim({ ...payload, signature: sign(null, nodeRegistrationClaimSigningBytes(payload), registrationKeys.privateKey).toString('base64'), }, { accountId: payload.accountId, domainId: DOMAIN_ID, nodeId: NODE_ID, nodeType: 'local-terminal', }, endpoint, NOW); } function responseFor(challenge: ReturnType) { return { challengeId: challenge.challengeId, publicKeyPem: nodePublicKeyPem, schema: 'gh-aios.node-possession-response/v1', signature: sign(null, nodePossessionChallengeSigningBytes(challenge), nodeKeys.privateKey).toString('base64'), }; } test('verifies a fresh proof from the key fingerprint bound into the signed registration', () => { const registration = verifiedRegistration(); const challenge = createNodePossessionChallenge( registration, NOW, 'NODE-CHALLENGE-001', 'A'.repeat(43), ); const response = responseFor(challenge); assert.equal(verifyNodePossessionResponse(response, challenge, registration, NOW + 1), true); assert.throws(() => verifyNodePossessionResponse(response, challenge, registration, NOW + 2), /proof_invalid/); }); test('rejects a forged challenge that was not issued by the verifier', () => { const registration = verifiedRegistration(); const challenge = { ...createNodePossessionChallenge(registration, NOW, 'NODE-CHALLENGE-001', 'A'.repeat(43)), nonce: 'B'.repeat(43), }; assert.throws(() => verifyNodePossessionResponse(responseFor(challenge), challenge, registration, NOW + 1), /proof_invalid/); }); test('rejects a response signed by a different node key', () => { const registration = verifiedRegistration(); const challenge = createNodePossessionChallenge(registration, NOW, 'NODE-CHALLENGE-001', 'A'.repeat(43)); const otherKeys = generateKeyPairSync('ed25519'); const response = { challengeId: challenge.challengeId, publicKeyPem: otherKeys.publicKey.export({ format: 'pem', type: 'spki' }).toString(), schema: 'gh-aios.node-possession-response/v1', signature: sign(null, nodePossessionChallengeSigningBytes(challenge), otherKeys.privateKey).toString('base64'), }; assert.throws(() => verifyNodePossessionResponse(response, challenge, registration, NOW + 1), /proof_invalid/); }); test('rejects expired, replayed-to-another-challenge and unknown-field responses', () => { const registration = verifiedRegistration(); const first = createNodePossessionChallenge(registration, NOW, 'NODE-CHALLENGE-001', 'A'.repeat(43)); const second = createNodePossessionChallenge(registration, NOW, 'NODE-CHALLENGE-002', 'B'.repeat(43)); assert.throws(() => verifyNodePossessionResponse(responseFor(first), second, registration, NOW + 1), /proof_invalid/); assert.throws(() => verifyNodePossessionResponse({ ...responseFor(first), extra: true }, first, registration, NOW + 1), /proof_invalid/); assert.throws(() => verifyNodePossessionResponse(responseFor(first), first, registration, NOW + 60_000), /proof_invalid/); }); test('does not accept a structurally copied registration as verified provenance', () => { const copied = { ...verifiedRegistration() }; assert.throws(() => createNodePossessionChallenge(copied, NOW, 'NODE-CHALLENGE-001', 'A'.repeat(43)), /proof_invalid/); });