77 lines
4.9 KiB
TypeScript
Executable File
77 lines
4.9 KiB
TypeScript
Executable File
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { execFileSync } from 'node:child_process';
|
|
|
|
function run(code: string) {
|
|
return JSON.parse(execFileSync(process.execPath, ['--experimental-strip-types', '--input-type=module', '-e', code], {
|
|
env: { ...process.env, WIKIDECK_NETWORK: 'pilot' }, encoding: 'utf8', timeout: 30_000,
|
|
}).trim());
|
|
}
|
|
|
|
const requestFixture = `
|
|
import { generateKeyPairSync, sign } from 'node:crypto';
|
|
import { address } from './server/testnet/consensus.ts';
|
|
import { CHAIN_ID } from './server/testnet/consensus.ts';
|
|
import { pilotMoneroDepositRequestMessage } from './shared/pilot-monero-deposit.ts';
|
|
import { validatePilotMoneroDepositRequest } from './server/market/pilot-monero-deposit-request.ts';
|
|
const pair=generateKeyPairSync('ec',{namedCurve:'prime256v1'});
|
|
const publicKey=pair.publicKey.export({type:'spki',format:'der'}).toString('base64');
|
|
const beneficiary=address(publicKey), now=1_800_000_000_000;
|
|
const identity={version:1,mode:'pilot-custody',policy:'pilot-custody-v1',marketNetwork:'wikideck-randomx-pilot-1',
|
|
marketChainId:CHAIN_ID,moneroNetwork:'mainnet',custodianId:'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa',
|
|
activationStatus:'identity-only',initializedAt:now-1};
|
|
const context={identity,walletGenerationId:'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb',
|
|
walletFingerprint:'c'.repeat(64),accountIndex:2,now:()=>now};
|
|
const unsigned={version:1,marketNetwork:'wikideck-randomx-pilot-1',marketChainId:CHAIN_ID,moneroNetwork:'mainnet',
|
|
custodianId:identity.custodianId,beneficiary,publicKey,requestId:'dddddddd-dddd-4ddd-8ddd-dddddddddddd',
|
|
walletGenerationId:context.walletGenerationId,walletFingerprint:context.walletFingerprint,accountIndex:2,expiresAt:now+60_000};
|
|
const signature=sign('sha256',Buffer.from(pilotMoneroDepositRequestMessage(unsigned)),
|
|
{key:pair.privateKey,dsaEncoding:'ieee-p1363'}).toString('base64');
|
|
const request={...unsigned,signature};
|
|
`;
|
|
|
|
test('pilot deposit authorization binds both networks and validates without allocating an address', () => {
|
|
const result = run(`${requestFixture}
|
|
const intent=validatePilotMoneroDepositRequest(context,request);
|
|
console.log(JSON.stringify({intent,hasAddress:Object.hasOwn(intent,'address'),hasAddressIndex:Object.hasOwn(intent,'addressIndex')}));`);
|
|
assert.equal(result.intent.marketNetwork, 'wikideck-randomx-pilot-1');
|
|
assert.match(result.intent.marketChainId, /^[a-f0-9]{64}$/);
|
|
assert.equal(result.intent.moneroNetwork, 'mainnet');
|
|
assert.equal(result.intent.beneficiary.length, 64);
|
|
assert.match(result.intent.requestDigest, /^[a-f0-9]{64}$/);
|
|
assert.equal(result.hasAddress, false);
|
|
assert.equal(result.hasAddressIndex, false);
|
|
});
|
|
|
|
test('pilot deposit authorization rejects domain, identity, wallet, signer, signature, and expiry mismatches', () => {
|
|
const result = run(`${requestFixture}
|
|
const rejected=[];
|
|
const check=(label,ctx,raw)=>{try{validatePilotMoneroDepositRequest(ctx,raw);rejected.push([label,false]);}
|
|
catch{rejected.push([label,true]);}};
|
|
check('market-network',context,{...request,marketNetwork:'wikideck-randomx-mainnet-1'});
|
|
check('monero-network',context,{...request,moneroNetwork:'stagenet'});
|
|
check('chain-id',context,{...request,marketChainId:'e'.repeat(64)});
|
|
check('custodian',context,{...request,custodianId:'eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee'});
|
|
check('wallet-generation',{...context,walletGenerationId:'ffffffff-ffff-4fff-8fff-ffffffffffff'},request);
|
|
check('wallet-fingerprint',{...context,walletFingerprint:'d'.repeat(64)},request);
|
|
check('account-index',{...context,accountIndex:3},request);
|
|
check('signer',context,{...request,beneficiary:'1'.repeat(64)});
|
|
check('signature',context,{...request,signature:'A'.repeat(88)});
|
|
check('expired',{...context,now:()=>request.expiresAt+1},request);
|
|
check('too-far-future',{...context,now:()=>request.expiresAt+1},{...request,expiresAt:request.expiresAt+10*60_000});
|
|
check('not-identity-only',{...context,identity:{...context.identity,activationStatus:'active'}},request);
|
|
console.log(JSON.stringify(rejected));`);
|
|
assert.deepEqual(result, [['market-network',true],['monero-network',true],['chain-id',true],['custodian',true],
|
|
['wallet-generation',true],['wallet-fingerprint',true],['account-index',true],['signer',true],['signature',true],
|
|
['expired',true],['too-far-future',true],['not-identity-only',true]]);
|
|
});
|
|
|
|
test('pilot deposit authorization rejects malformed and unknown fields', () => {
|
|
const result = run(`${requestFixture}
|
|
let malformed=false,unknown=false;
|
|
try{validatePilotMoneroDepositRequest(context,{...request,accountIndex:-1});}catch{malformed=true;}
|
|
try{validatePilotMoneroDepositRequest(context,{...request,address:'4'.repeat(95)});}catch{unknown=true;}
|
|
console.log(JSON.stringify({malformed,unknown}));`);
|
|
assert.deepEqual(result, { malformed: true, unknown: true });
|
|
});
|