@agentunion/fastaun 0.5.21 → 0.5.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -1
- package/_packed_docs/CHANGELOG.md +58 -1
- package/_packed_docs/INDEX.md +469 -453
- package/_packed_docs/KITE_DOCS_GUIDE.md +169 -164
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
- package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
- package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
- package/_packed_docs/sdk/INDEX.md +255 -239
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
- package/dist/agent-md.d.ts +16 -2
- package/dist/agent-md.js +59 -23
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +1 -0
- package/dist/aid-store.js +43 -8
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts +7 -0
- package/dist/auth.js +222 -70
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +28 -0
- package/dist/client/delivery.js +399 -44
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +3 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.js +28 -2
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +109 -39
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +114 -26
- package/dist/client.js.map +1 -1
- package/dist/group-fs.d.ts +1 -0
- package/dist/group-fs.js +37 -19
- package/dist/group-fs.js.map +1 -1
- package/dist/org-protocol.d.ts +11 -0
- package/dist/org-protocol.js +154 -19
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +21 -3
- package/dist/ownership-v21.js +135 -37
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +7 -2
- package/dist/ownership-workflow.js +173 -17
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/storage/lowlevel.d.ts +6 -0
- package/dist/storage/lowlevel.js +24 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +70 -0
- package/dist/storage/read-cache.js +625 -0
- package/dist/storage/read-cache.js.map +1 -0
- package/dist/storage/vfs.d.ts +2 -0
- package/dist/storage/vfs.js +50 -15
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +21 -1
- package/dist/tools/cross-sdk-agent.js +301 -19
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.js +6 -2
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ export declare class AUNClient {
|
|
|
90
90
|
private _ownershipWorkflow;
|
|
91
91
|
private _getOwnershipStorage;
|
|
92
92
|
private _getOwnershipFiles;
|
|
93
|
+
private _createOwnershipFiles;
|
|
93
94
|
private _getOwnershipWorkflow;
|
|
94
95
|
private _persistOwnershipRecords;
|
|
95
96
|
private _restoreOwnershipRecords;
|
|
@@ -98,6 +99,7 @@ export declare class AUNClient {
|
|
|
98
99
|
private _credentialRenewalTimer;
|
|
99
100
|
private _credentialRenewalAbort;
|
|
100
101
|
private _credentialRenewalScan;
|
|
102
|
+
private _nextCredentialRevocationSyncAt;
|
|
101
103
|
private _getCredentialRenewal;
|
|
102
104
|
_assertCredentialNotRevoked(credential: JsonObject, proofChain?: JsonObject[]): () => void;
|
|
103
105
|
private _credentialRenewalSigner;
|
|
@@ -274,6 +276,7 @@ export declare class AUNClient {
|
|
|
274
276
|
releaseSubaid(subAid: string): Promise<OwnershipTaskResult>;
|
|
275
277
|
transferSubaid(subAid: string, newOwnerAid: string): Promise<OwnershipTaskResult>;
|
|
276
278
|
checkOwnershipConsensus(subAid?: string): Promise<OwnershipConsensusResult>;
|
|
279
|
+
private _checkOwnershipConsensusFresh;
|
|
277
280
|
bindAid(subjectAid: string, options?: {
|
|
278
281
|
subjectType?: string;
|
|
279
282
|
subject_type?: string;
|
package/dist/client.js
CHANGED
|
@@ -48,7 +48,7 @@ import { isJsonObject, ConnectionState, STATE_TO_PUBLIC, } from './types.js';
|
|
|
48
48
|
import { AID } from './aid.js';
|
|
49
49
|
import { certFingerprint, certMatchesFingerprint, normalizeFingerprintHex, publicKeyMatchesFingerprint } from './cert-utils.js';
|
|
50
50
|
import { validateAgentMdCertificate, validateAgentMdDocument } from './agent-md-schema.js';
|
|
51
|
-
import { OwnershipFiles, OwnershipStorageAdapter, ownershipFailure } from './ownership-v21.js';
|
|
51
|
+
import { OwnershipFiles, OwnershipStorageAdapter, ownershipAid, ownershipFailure } from './ownership-v21.js';
|
|
52
52
|
import { OwnershipWorkflow } from './ownership-workflow.js';
|
|
53
53
|
import { canonicalJson, createCredential, createMemberCredential, signMembershipBinding, digest, validateMembershipBinding, verifyMembershipBinding, verifyCredentialSignature, createRepresentationProof, verifyServiceEvent, buildRequestBinding, validateRequestBinding, CredentialRenewal } from './org-protocol.js';
|
|
54
54
|
function isPromiseLike(value) {
|
|
@@ -489,16 +489,19 @@ export class AUNClient {
|
|
|
489
489
|
return this._ownershipStorage ??= new OwnershipStorageAdapter({ currentAid: () => this._aid, call: (method, params) => this.call(method, params), httpPut: (url, data, headers) => this.storage.lowlevel.httpPut(url, data, headers) });
|
|
490
490
|
}
|
|
491
491
|
_getOwnershipFiles() {
|
|
492
|
-
return this._ownershipFiles ??=
|
|
492
|
+
return this._ownershipFiles ??= this._createOwnershipFiles((subAid) => this._agentMdManager.readOwnershipFresh(subAid));
|
|
493
|
+
}
|
|
494
|
+
_createOwnershipFiles(readAgentMdFresh) {
|
|
495
|
+
return new OwnershipFiles({
|
|
493
496
|
currentAid: () => { if (!this._currentAid)
|
|
494
497
|
throw ownershipFailure('forbidden', 'ownership requires a loaded identity'); return this._currentAid; },
|
|
495
498
|
currentType: () => this.getType(),
|
|
496
499
|
now: () => Math.trunc(Date.now() / 1000),
|
|
497
|
-
readAgentMdFresh
|
|
498
|
-
submitAgentMdRaw: (subAid, raw, condition, assertActive) => this._agentMdManager.submitOwnershipRaw(subAid, raw, condition, assertActive),
|
|
500
|
+
readAgentMdFresh,
|
|
501
|
+
submitAgentMdRaw: (subAid, raw, condition, assertActive, stage) => this._agentMdManager.submitOwnershipRaw(subAid, raw, condition, assertActive, stage),
|
|
499
502
|
readOwnerMd: (ownerAid, subAid) => this._getOwnershipStorage().readOwnerMd(ownerAid, subAid),
|
|
500
503
|
writeOwnerMd: (ownerAid, subAid, raw, original, assertActive) => this._getOwnershipStorage().writeOwnerMd(ownerAid, subAid, raw, original, assertActive),
|
|
501
|
-
deleteOwnerMd: (ownerAid, subAid) => this._getOwnershipStorage().deleteOwnerMd(ownerAid, subAid),
|
|
504
|
+
deleteOwnerMd: (ownerAid, subAid, expectedVersion) => this._getOwnershipStorage().deleteOwnerMd(ownerAid, subAid, expectedVersion),
|
|
502
505
|
resolveCertificate: async (aid, fingerprint, purpose) => this._auth.resolveOwnershipCertificate(await this._resolveOwnershipCertificateGateway(aid), aid, fingerprint, purpose),
|
|
503
506
|
});
|
|
504
507
|
}
|
|
@@ -506,7 +509,7 @@ export class AUNClient {
|
|
|
506
509
|
return this._ownershipWorkflow ??= new OwnershipWorkflow({
|
|
507
510
|
currentAid: () => this._aid, store: this._tokenStore, files: this._getOwnershipFiles(),
|
|
508
511
|
currentType: () => this.getType(),
|
|
509
|
-
send: (to, payload) => this.call('message.send', { to, encrypt: true, payload: payload }),
|
|
512
|
+
send: (to, payload, messageId) => this.call('message.send', { to, encrypt: true, message_id: messageId, payload: payload }),
|
|
510
513
|
emit: (event, payload) => this._dispatcher.enqueue(event, payload),
|
|
511
514
|
});
|
|
512
515
|
}
|
|
@@ -554,9 +557,11 @@ export class AUNClient {
|
|
|
554
557
|
_credentialRenewalTimer = null;
|
|
555
558
|
_credentialRenewalAbort = null;
|
|
556
559
|
_credentialRenewalScan = Promise.resolve();
|
|
560
|
+
_nextCredentialRevocationSyncAt = 0;
|
|
557
561
|
_getCredentialRenewal() {
|
|
558
562
|
return this._credentialRenewal ??= new CredentialRenewal({
|
|
559
563
|
currentAid: () => this._aid ?? '',
|
|
564
|
+
queryContext: () => JSON.stringify([this._serviceEventIdentityVersion, this._gatewayUrl, this._transport?._connectionGeneration, this._transport?._workerGeneration]),
|
|
560
565
|
atomicCheckpointSave: () => this._tokenStore instanceof LocalTokenStore,
|
|
561
566
|
load: (aid) => (this._tokenStore._loadMetadataStrict?.(aid) ?? this._tokenStore.loadMetadata?.(aid))?.credential_renewals_v1 ?? {},
|
|
562
567
|
...(typeof this._tokenStore._loadMetadataStrict === 'function' ? {
|
|
@@ -630,6 +635,7 @@ export class AUNClient {
|
|
|
630
635
|
if (aid === this._aid && this._identity) {
|
|
631
636
|
this._identity.cert = identity.certPem;
|
|
632
637
|
this._currentAid = identity;
|
|
638
|
+
this._auth.setIdentity(this._identity);
|
|
633
639
|
}
|
|
634
640
|
}
|
|
635
641
|
return identity;
|
|
@@ -647,11 +653,11 @@ export class AUNClient {
|
|
|
647
653
|
_credentialCurrent(input) {
|
|
648
654
|
return this._getCredentialRenewal().current(input);
|
|
649
655
|
}
|
|
650
|
-
async _resumeCredentialRenewalAfterConnect(guard) {
|
|
656
|
+
async _resumeCredentialRenewalAfterConnect(guard, syncRevocations = false) {
|
|
651
657
|
if (!this._aid || (guard && !guard.current()))
|
|
652
658
|
return;
|
|
653
659
|
await this._safeAsync(guard ? this._credentialRenewalSigner(this._aid, guard) : this._credentialRenewalSigner(this._aid));
|
|
654
|
-
if (!guard || guard.current())
|
|
660
|
+
if (syncRevocations && (!guard || guard.current()))
|
|
655
661
|
await this._safeAsync(this._getCredentialRenewal()._syncRevocations?.(guard) ?? Promise.resolve());
|
|
656
662
|
if (!guard || guard.current())
|
|
657
663
|
await this._getCredentialRenewal().resume(guard);
|
|
@@ -665,11 +671,15 @@ export class AUNClient {
|
|
|
665
671
|
this._credentialRenewalAbort = abort;
|
|
666
672
|
const current = () => this._credentialRenewalAbort === abort && !abort.signal.aborted && aid === this._aid && version === this._serviceEventIdentityVersion && ['ready', 'connected'].includes(this._state) && !this._closing && !this._disconnecting;
|
|
667
673
|
const guard = { current, signal: abort.signal };
|
|
674
|
+
this._nextCredentialRevocationSyncAt ||= Date.now() + 3_600_000;
|
|
668
675
|
const scan = async () => {
|
|
669
676
|
const task = this._credentialRenewalScan.then(async () => {
|
|
670
677
|
if (!current())
|
|
671
678
|
return;
|
|
672
|
-
|
|
679
|
+
const syncRevocations = Date.now() >= this._nextCredentialRevocationSyncAt;
|
|
680
|
+
if (syncRevocations)
|
|
681
|
+
this._nextCredentialRevocationSyncAt = Date.now() + 3_600_000;
|
|
682
|
+
await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
|
|
673
683
|
});
|
|
674
684
|
this._credentialRenewalScan = task.catch(() => { });
|
|
675
685
|
await this._safeAsync(task);
|
|
@@ -701,10 +711,18 @@ export class AUNClient {
|
|
|
701
711
|
const version = this._serviceEventIdentityVersion;
|
|
702
712
|
const signal = this._serviceEventIdentityAbort.signal;
|
|
703
713
|
const expiresAt = Number(payload?.expires_at);
|
|
704
|
-
const
|
|
714
|
+
const transport = this._transport, connectionGeneration = transport?._connectionGeneration, workerGeneration = transport?._workerGeneration;
|
|
715
|
+
const current = () => version === this._serviceEventIdentityVersion && targetAid === (this._identity?.aid ?? '') && transport === this._transport && connectionGeneration === this._transport?._connectionGeneration && workerGeneration === this._transport?._workerGeneration && Date.now() / 1000 < expiresAt;
|
|
705
716
|
const verified = await verifyServiceEvent(event, payload, { targetAid, resolveEventCertificate: (aid, fingerprint) => this._fetchServiceEventCertificate(aid, fingerprint), resolveCredentialService: this.resolveCredentialService });
|
|
706
717
|
if (!current())
|
|
707
718
|
throw new ValidationError('service event receiver identity changed');
|
|
719
|
+
const eventName = event.replace(/^event\//, '');
|
|
720
|
+
if (eventName.startsWith('org.') || ['credential.revoked', 'credential.revocationList'].includes(eventName)) {
|
|
721
|
+
this._getCredentialRenewal().invalidateQueries?.();
|
|
722
|
+
}
|
|
723
|
+
if (['credential.revoked', 'credential.revocationList'].includes(event.replace(/^event\//, ''))) {
|
|
724
|
+
await this._getCredentialRenewal()._receiveRevocations(payload, { current, signal });
|
|
725
|
+
}
|
|
708
726
|
if (event.replace(/^event\//, '') === 'org.member.changed' && isJsonObject(payload) && Object.hasOwn(payload, 'membership_package')) {
|
|
709
727
|
await this._getCredentialRenewal().importMembershipPackage(payload, { current, signal });
|
|
710
728
|
if (!current())
|
|
@@ -1179,7 +1197,12 @@ export class AUNClient {
|
|
|
1179
1197
|
async resetOwnershipTask() { return this._getOwnershipWorkflow().resetOwnershipTask(); }
|
|
1180
1198
|
async releaseSubaid(subAid) { return this._getOwnershipWorkflow().releaseSubaid(subAid); }
|
|
1181
1199
|
async transferSubaid(subAid, newOwnerAid) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid); }
|
|
1182
|
-
async checkOwnershipConsensus(subAid) {
|
|
1200
|
+
async checkOwnershipConsensus(subAid) {
|
|
1201
|
+
return this._createOwnershipFiles((aid) => this._agentMdManager._readOwnershipQuery(aid)).checkConsensus(ownershipAid(subAid ?? this._aid, 'sub_aid'));
|
|
1202
|
+
}
|
|
1203
|
+
async _checkOwnershipConsensusFresh(subAid) {
|
|
1204
|
+
return this._getOwnershipWorkflow().checkOwnershipConsensus(subAid);
|
|
1205
|
+
}
|
|
1183
1206
|
async bindAid(subjectAid, options = {}) {
|
|
1184
1207
|
throw ownershipFailure('unsupported_protocol', 'legacy bindAid is unsupported; use bindSubaid');
|
|
1185
1208
|
}
|
|
@@ -1386,6 +1409,9 @@ export class AUNClient {
|
|
|
1386
1409
|
this._identityRuntime.loadIdentity(aid);
|
|
1387
1410
|
this._stopCredentialRenewal();
|
|
1388
1411
|
this._serviceEventIdentityVersion++;
|
|
1412
|
+
this._auth.invalidateStrictPkiCache();
|
|
1413
|
+
this._certCache.clear();
|
|
1414
|
+
this._certFetchInFlight.clear();
|
|
1389
1415
|
this._serviceEventIdentityAbort.abort();
|
|
1390
1416
|
this._serviceEventIdentityAbort = new AbortController();
|
|
1391
1417
|
this._ensureReadStateIdentity();
|
|
@@ -1614,6 +1640,9 @@ export class AUNClient {
|
|
|
1614
1640
|
if (!isJsonObject(raw))
|
|
1615
1641
|
continue;
|
|
1616
1642
|
const group = raw;
|
|
1643
|
+
const status = String(group.status ?? '').trim().toLowerCase();
|
|
1644
|
+
if (status && status !== 'active')
|
|
1645
|
+
continue;
|
|
1617
1646
|
const role = String(group.role ?? group.my_role ?? '').trim().toLowerCase();
|
|
1618
1647
|
const groupId = String(group.group_id ?? group.groupId ?? group.group_aid ?? group.groupAid ?? '').trim();
|
|
1619
1648
|
const groupAid = String(group.group_aid ?? group.groupAid ?? groupId).trim();
|
|
@@ -1753,7 +1782,7 @@ export class AUNClient {
|
|
|
1753
1782
|
await this.createOrg(creation.source_params, { aidStore: store });
|
|
1754
1783
|
continue;
|
|
1755
1784
|
}
|
|
1756
|
-
if (transfer?.owner_aid === this._aid) {
|
|
1785
|
+
if (transfer?.owner_aid === this._aid && transfer.phase !== 'completed') {
|
|
1757
1786
|
await this.completeOrgTransfer(transfer.source_params, { aidStore: store });
|
|
1758
1787
|
continue;
|
|
1759
1788
|
}
|
|
@@ -1817,8 +1846,14 @@ export class AUNClient {
|
|
|
1817
1846
|
let pending = (typeof tokenStore._loadMetadataStrict === 'function' ? tokenStore._loadMetadataStrict(orgAid) : tokenStore.loadMetadata(orgAid))?.org_identity_transfer;
|
|
1818
1847
|
if (pending != null && !isJsonObject(pending))
|
|
1819
1848
|
throw ownershipFailure('persistence_unavailable', 'Org transfer checkpoint is invalid');
|
|
1849
|
+
if (pending?.phase === 'completed' && pending.transfer_id !== transferId)
|
|
1850
|
+
pending = undefined;
|
|
1820
1851
|
if (pending && (pending.transfer_id !== transferId || pending.owner_aid !== owner.aid || pending.input_hash !== inputHash))
|
|
1821
1852
|
throw ownershipFailure('conflict', 'pending Org transfer context changed');
|
|
1853
|
+
if (pending?.phase === 'completed') {
|
|
1854
|
+
localStore.clearPendingGroupBind(pendingKey);
|
|
1855
|
+
return pending.result;
|
|
1856
|
+
}
|
|
1822
1857
|
if (!pending)
|
|
1823
1858
|
await this._verifyOrgTransferMaterials(params, owner.aid);
|
|
1824
1859
|
let keyPair = localStore.loadPendingGroupBind(pendingKey);
|
|
@@ -1879,7 +1914,7 @@ export class AUNClient {
|
|
|
1879
1914
|
}
|
|
1880
1915
|
const result = await this.call('org.lifecycle.transferAccept', await this._resumeOrgRequest('org.lifecycle.transferAccept', pending.finalize_params, target));
|
|
1881
1916
|
await this._uploadOrgAgentMd(store, orgAid, pending.source_params);
|
|
1882
|
-
tokenStore.saveMetadata(orgAid, { org_identity_transfer:
|
|
1917
|
+
tokenStore.saveMetadata(orgAid, { org_identity_transfer: { transfer_id: transferId, owner_aid: owner.aid, input_hash: inputHash, phase: 'completed', result } });
|
|
1883
1918
|
localStore.clearPendingGroupBind(pendingKey);
|
|
1884
1919
|
return result;
|
|
1885
1920
|
}
|
|
@@ -2132,7 +2167,13 @@ export class AUNClient {
|
|
|
2132
2167
|
entityIdentityGetter: (aid, type) => this._freshEntityCertificate(aid, type),
|
|
2133
2168
|
entitySignerResolver: (aid, fingerprint) => this._freshEntitySigner(aid, fingerprint),
|
|
2134
2169
|
gatewayResolver: (aid) => identityStore._resolveGateway(aid),
|
|
2135
|
-
accessTokenResolver: (
|
|
2170
|
+
accessTokenResolver: async () => {
|
|
2171
|
+
const state = identityStore._tokenStore?.loadInstanceState?.(identity.aid, store.deviceId, store.slotId) ?? {};
|
|
2172
|
+
const token = AuthFlow._getCachedAccessToken(state);
|
|
2173
|
+
if (token && String(state.refresh_token ?? '') && !this._auth._validateCachedCredentials(identityStore._authIdentityFromAid(identity)))
|
|
2174
|
+
return token;
|
|
2175
|
+
return identityStore._uploadAgentMdToken(identity, await identityStore._resolveGateway(identity.aid));
|
|
2176
|
+
},
|
|
2136
2177
|
aidValidator: (aid) => identityStore._registerFlow.validateAidName(aid),
|
|
2137
2178
|
});
|
|
2138
2179
|
return await manager.resumePendingUpload(groupAid);
|
|
@@ -2607,6 +2648,11 @@ export class AUNClient {
|
|
|
2607
2648
|
const tStart = Date.now();
|
|
2608
2649
|
this._clientLog.debug(`on enter: event=${event}`);
|
|
2609
2650
|
const result = this._dispatcher.subscribe(event, handler);
|
|
2651
|
+
if (event === 'message.received' || event === 'message.recalled' || event === 'message.batch') {
|
|
2652
|
+
if (this._p2pPeerPullEnabled)
|
|
2653
|
+
this._delivery.refreshPendingPeers();
|
|
2654
|
+
this._delivery.requestBackgroundPullRecovery();
|
|
2655
|
+
}
|
|
2610
2656
|
this._clientLog.debug(`on exit: elapsed=${Date.now() - tStart}ms event=${event}`);
|
|
2611
2657
|
return result;
|
|
2612
2658
|
}
|
|
@@ -3311,6 +3357,8 @@ export class AUNClient {
|
|
|
3311
3357
|
this._clientLog.debug(`bootstrap CA chain cache skipped: peer=${aid}, source=${opts.source ?? 'unknown'}, err=${formatCaughtError(exc)}`);
|
|
3312
3358
|
}
|
|
3313
3359
|
}
|
|
3360
|
+
const auth = this._auth;
|
|
3361
|
+
const pkiEpoch = auth._strictPkiEpoch;
|
|
3314
3362
|
try {
|
|
3315
3363
|
if (opts.signedAt === undefined)
|
|
3316
3364
|
await this._auth.verifyPeerCertificate(peerGatewayUrl, certPem, aid);
|
|
@@ -3328,20 +3376,21 @@ export class AUNClient {
|
|
|
3328
3376
|
}
|
|
3329
3377
|
throw new ValidationError(`peer cert verification failed for ${aid}: ${exc instanceof Error ? exc.message : String(exc)}`);
|
|
3330
3378
|
}
|
|
3379
|
+
if (auth !== this._auth || pkiEpoch !== auth._strictPkiEpoch)
|
|
3380
|
+
throw new ValidationError('peer certificate validation context changed');
|
|
3331
3381
|
const nowSec = Date.now() / 1000;
|
|
3332
3382
|
const entry = {
|
|
3333
3383
|
certPem,
|
|
3334
3384
|
validatedAt: nowSec,
|
|
3335
|
-
refreshAfter: nowSec + PEER_CERT_CACHE_TTL,
|
|
3385
|
+
refreshAfter: Math.min(nowSec + PEER_CERT_CACHE_TTL, Date.parse(x509Cert.validTo) / 1000, auth._gatewayChainCache.get(`${peerGatewayUrl}:${aid}`)?.expiresAt / 1000 || Infinity),
|
|
3386
|
+
auth,
|
|
3387
|
+
pkiEpoch,
|
|
3336
3388
|
};
|
|
3337
|
-
const
|
|
3389
|
+
const scope = opts.signedAt === undefined ? '' : `:historical${opts.agentMdRead ? ':agentmd' : ''}`;
|
|
3390
|
+
const actualFp = `sha256:${x509Cert.fingerprint256.replace(/:/g, '').toLowerCase()}`;
|
|
3391
|
+
const cacheKey = AUNClient._certCacheKey(aid, actualFp) + scope;
|
|
3338
3392
|
this._certCache.set(cacheKey, entry);
|
|
3339
|
-
|
|
3340
|
-
const bareKey = AUNClient._certCacheKey(aid);
|
|
3341
|
-
this._certCache.set(bareKey, entry);
|
|
3342
|
-
const actualFp = `sha256:${x509Cert.fingerprint256.replace(/:/g, '').toLowerCase()}`;
|
|
3343
|
-
this._certCache.set(AUNClient._certCacheKey(aid, actualFp), entry);
|
|
3344
|
-
}
|
|
3393
|
+
this._certCache.set(AUNClient._certCacheKey(aid, certFingerprint) + scope, entry);
|
|
3345
3394
|
try {
|
|
3346
3395
|
// peer 证书只存版本目录,不覆盖 cert.pem
|
|
3347
3396
|
this._tokenStore.saveCert(aid, certPem, opts.agentMdRead && opts.signedAt !== undefined ? `sha256:${x509Cert.fingerprint256.replace(/:/g, '').toLowerCase()}` : certFingerprint, { makeActive: false });
|
|
@@ -3363,14 +3412,46 @@ export class AUNClient {
|
|
|
3363
3412
|
const tStart = Date.now();
|
|
3364
3413
|
this._clientLog.debug(`_fetchPeerCert enter: aid=${aid}, fp=${certFingerprint ?? ''}`);
|
|
3365
3414
|
try {
|
|
3366
|
-
const cacheKey = AUNClient._certCacheKey(aid, certFingerprint) + (signedAt === undefined ? '' : `:
|
|
3415
|
+
const cacheKey = AUNClient._certCacheKey(aid, certFingerprint) + (signedAt === undefined ? '' : `:historical${agentMdRead ? ':agentmd' : ''}`);
|
|
3367
3416
|
const cached = this._certCache.get(cacheKey);
|
|
3368
3417
|
const now = Date.now() / 1000;
|
|
3369
|
-
|
|
3418
|
+
const auth = this._auth, pkiEpoch = auth._strictPkiEpoch;
|
|
3419
|
+
if (cached && cached.auth === auth && cached.pkiEpoch === pkiEpoch && now < cached.refreshAfter) {
|
|
3420
|
+
if (signedAt === undefined) {
|
|
3421
|
+
const statusKey = `${cacheKey}:status:${pkiEpoch}`;
|
|
3422
|
+
let pending = this._certFetchInFlight.get(statusKey);
|
|
3423
|
+
if (!pending) {
|
|
3424
|
+
pending = (async () => {
|
|
3425
|
+
await auth.verifyPeerCertificate(AUNClient._resolvePeerGatewayUrl(this._gatewayUrl, aid), cached.certPem, aid);
|
|
3426
|
+
if (auth !== this._auth || pkiEpoch !== auth._strictPkiEpoch)
|
|
3427
|
+
throw new ValidationError('peer certificate status context changed');
|
|
3428
|
+
return cached.certPem;
|
|
3429
|
+
})();
|
|
3430
|
+
this._certFetchInFlight.set(statusKey, pending);
|
|
3431
|
+
}
|
|
3432
|
+
try {
|
|
3433
|
+
await pending;
|
|
3434
|
+
}
|
|
3435
|
+
finally {
|
|
3436
|
+
if (this._certFetchInFlight.get(statusKey) === pending)
|
|
3437
|
+
this._certFetchInFlight.delete(statusKey);
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
else {
|
|
3441
|
+
const peerGatewayUrl = AUNClient._resolvePeerGatewayUrl(this._gatewayUrl, aid);
|
|
3442
|
+
if (agentMdRead) {
|
|
3443
|
+
validateAgentMdCertificate(cached.certPem, aid, signedAt, { requireCurrentValidity: false, readCompatibility: true });
|
|
3444
|
+
await auth._verifyAuthCertChain(peerGatewayUrl, new crypto.X509Certificate(cached.certPem), aid, signedAt);
|
|
3445
|
+
}
|
|
3446
|
+
else
|
|
3447
|
+
await auth.verifyPeerCertificate(peerGatewayUrl, cached.certPem, aid, signedAt);
|
|
3448
|
+
if (auth !== this._auth || pkiEpoch !== auth._strictPkiEpoch)
|
|
3449
|
+
throw new ValidationError('peer certificate validation context changed');
|
|
3450
|
+
}
|
|
3370
3451
|
this._clientLog.debug(`_fetchPeerCert exit: elapsed=${Date.now() - tStart}ms aid=${aid} (cache_hit)`);
|
|
3371
3452
|
return cached.certPem;
|
|
3372
3453
|
}
|
|
3373
|
-
const inFlightKey = `${cacheKey}:timeout:${timeoutMs}`;
|
|
3454
|
+
const inFlightKey = `${cacheKey}:signed:${signedAt ?? 'current'}:timeout:${timeoutMs}:pki:${pkiEpoch}`;
|
|
3374
3455
|
const pending = this._certFetchInFlight.get(inFlightKey);
|
|
3375
3456
|
if (pending)
|
|
3376
3457
|
return await pending;
|
|
@@ -3381,6 +3462,8 @@ export class AUNClient {
|
|
|
3381
3462
|
}
|
|
3382
3463
|
const peerGatewayUrl = AUNClient._resolvePeerGatewayUrl(gatewayUrl, aid);
|
|
3383
3464
|
const certPem = await _httpGetText(AUNClient._buildCertUrl(peerGatewayUrl, aid, certFingerprint), this._configModel.verifySsl, timeoutMs);
|
|
3465
|
+
if (auth !== this._auth || pkiEpoch !== auth._strictPkiEpoch)
|
|
3466
|
+
throw new ValidationError('peer certificate fetch context changed');
|
|
3384
3467
|
const validated = await this._validateAndCachePeerCert({
|
|
3385
3468
|
aid,
|
|
3386
3469
|
certPem,
|
|
@@ -3801,7 +3884,9 @@ export class AUNClient {
|
|
|
3801
3884
|
}
|
|
3802
3885
|
/** 构建证书下载 URL */
|
|
3803
3886
|
static _certCacheKey(aid, certFingerprint) {
|
|
3804
|
-
const
|
|
3887
|
+
const raw = String(certFingerprint ?? '').trim().toLowerCase();
|
|
3888
|
+
const hex = normalizeFingerprintHex(raw);
|
|
3889
|
+
const normalized = hex ? `sha256:${hex}` : raw;
|
|
3805
3890
|
return normalized ? `${aid}#${normalized}` : aid;
|
|
3806
3891
|
}
|
|
3807
3892
|
static _buildCertUrl(gatewayUrl, aid, certFingerprint) {
|
|
@@ -4846,6 +4931,9 @@ export class AUNClient {
|
|
|
4846
4931
|
/** 停止所有后台任务 */
|
|
4847
4932
|
_stopBackgroundTasks() {
|
|
4848
4933
|
this._stopCredentialRenewal();
|
|
4934
|
+
this._auth.invalidateStrictPkiCache();
|
|
4935
|
+
this._certCache.clear();
|
|
4936
|
+
this._certFetchInFlight.clear();
|
|
4849
4937
|
if (this._heartbeatTimer !== null) {
|
|
4850
4938
|
clearInterval(this._heartbeatTimer);
|
|
4851
4939
|
this._heartbeatTimer = null;
|