mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-23 03:18:09 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
const {
|
||||
createLocalOwnerCredentialRecoveryService,
|
||||
} = require('../dist/credential-recovery');
|
||||
|
||||
test('issues a distinct credential and replays acknowledged completion', async () => {
|
||||
const previous = {
|
||||
credentialId: `own_${'a'.repeat(22)}`,
|
||||
version: 1,
|
||||
pepperKeyId: 'owner-key-1',
|
||||
state: 'active',
|
||||
subject: { type: 'user', id: `usr_${'b'.repeat(22)}` },
|
||||
subjectStatus: 'active',
|
||||
secretDigest: '1'.repeat(64),
|
||||
createdAtMs: 100,
|
||||
notBeforeAtMs: 100,
|
||||
expiresAtMs: 100000000,
|
||||
};
|
||||
let recovery = null;
|
||||
const credentials = {
|
||||
async resolve(credentialId) {
|
||||
return credentialId === previous.credentialId ? previous : null;
|
||||
},
|
||||
};
|
||||
const repository = {
|
||||
async resolve() {
|
||||
return recovery;
|
||||
},
|
||||
async issue(command) {
|
||||
recovery = {
|
||||
issueMutationId: command.mutationId,
|
||||
issueRequestId: command.requestId,
|
||||
subjectId: command.replacementCredential.subject.id,
|
||||
previousCredentialId: command.previousCredentialId,
|
||||
previousCredentialVersion: command.expectedPreviousVersion,
|
||||
replacementCredential: command.replacementCredential,
|
||||
state: 'issued',
|
||||
issuedAtMs: command.replacementCredential.createdAtMs,
|
||||
};
|
||||
return { status: 'inserted', recovery };
|
||||
},
|
||||
async acknowledge() {
|
||||
throw new Error('not used');
|
||||
},
|
||||
async complete(command) {
|
||||
assert.equal(recovery.state, 'acknowledged');
|
||||
recovery = {
|
||||
...recovery,
|
||||
state: 'completed',
|
||||
completeMutationId: command.mutationId,
|
||||
completeRequestId: command.requestId,
|
||||
revokedCredentialVersion: command.revokedCredential.version,
|
||||
completedAtMs: command.revokedCredential.createdAtMs,
|
||||
};
|
||||
return { status: 'inserted', recovery };
|
||||
},
|
||||
};
|
||||
let nowMs = 1000;
|
||||
const service = createLocalOwnerCredentialRecoveryService(
|
||||
repository,
|
||||
credentials,
|
||||
Buffer.alloc(32, 7).toString('base64url'),
|
||||
{
|
||||
pepperKeyId: 'owner-key-1',
|
||||
now: () => nowMs,
|
||||
randomBytes: (size) => Buffer.alloc(size, size),
|
||||
},
|
||||
);
|
||||
const issueMutationId = '00000000-0000-4000-8000-000000000801';
|
||||
const issued = await service.issue({
|
||||
mutationId: issueMutationId,
|
||||
requestId: 'recover-issue-801',
|
||||
previousCredentialId: previous.credentialId,
|
||||
expectedPreviousVersion: 1,
|
||||
});
|
||||
assert.equal(issued.status, 'inserted');
|
||||
assert.notEqual(issued.replacementCredentialId, previous.credentialId);
|
||||
assert.match(issued.replacementCredentialToken, /^ql3c_/);
|
||||
|
||||
recovery = {
|
||||
...recovery,
|
||||
state: 'acknowledged',
|
||||
deliveryDigest: '2'.repeat(64),
|
||||
acknowledgedAtMs: 1100,
|
||||
};
|
||||
nowMs = 1200;
|
||||
const completion = {
|
||||
issueMutationId,
|
||||
mutationId: '00000000-0000-4000-8000-000000000802',
|
||||
requestId: 'recover-complete-802',
|
||||
};
|
||||
assert.equal((await service.complete(completion)).status, 'inserted');
|
||||
assert.equal((await service.complete(completion)).status, 'existing');
|
||||
});
|
||||
Reference in New Issue
Block a user