@agentunion/fastaun 0.5.22 → 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/_packed_docs/INDEX.md +5 -1
- package/_packed_docs/KITE_DOCS_GUIDE.md +1 -0
- package/dist/agent-md.d.ts +15 -1
- package/dist/agent-md.js +49 -20
- 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 +6 -0
- package/dist/auth.js +205 -69
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +79 -19
- package/dist/client.js.map +1 -1
- package/dist/org-protocol.d.ts +10 -0
- package/dist/org-protocol.js +100 -12
- package/dist/org-protocol.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
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,12 +489,15 @@ 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
|
|
500
|
+
readAgentMdFresh,
|
|
498
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),
|
|
@@ -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;
|
|
@@ -665,14 +671,14 @@ 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 };
|
|
668
|
-
|
|
674
|
+
this._nextCredentialRevocationSyncAt ||= Date.now() + 3_600_000;
|
|
669
675
|
const scan = async () => {
|
|
670
676
|
const task = this._credentialRenewalScan.then(async () => {
|
|
671
677
|
if (!current())
|
|
672
678
|
return;
|
|
673
|
-
const syncRevocations = Date.now() >=
|
|
679
|
+
const syncRevocations = Date.now() >= this._nextCredentialRevocationSyncAt;
|
|
674
680
|
if (syncRevocations)
|
|
675
|
-
|
|
681
|
+
this._nextCredentialRevocationSyncAt = Date.now() + 3_600_000;
|
|
676
682
|
await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
|
|
677
683
|
});
|
|
678
684
|
this._credentialRenewalScan = task.catch(() => { });
|
|
@@ -710,6 +716,10 @@ export class AUNClient {
|
|
|
710
716
|
const verified = await verifyServiceEvent(event, payload, { targetAid, resolveEventCertificate: (aid, fingerprint) => this._fetchServiceEventCertificate(aid, fingerprint), resolveCredentialService: this.resolveCredentialService });
|
|
711
717
|
if (!current())
|
|
712
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
|
+
}
|
|
713
723
|
if (['credential.revoked', 'credential.revocationList'].includes(event.replace(/^event\//, ''))) {
|
|
714
724
|
await this._getCredentialRenewal()._receiveRevocations(payload, { current, signal });
|
|
715
725
|
}
|
|
@@ -1187,7 +1197,12 @@ export class AUNClient {
|
|
|
1187
1197
|
async resetOwnershipTask() { return this._getOwnershipWorkflow().resetOwnershipTask(); }
|
|
1188
1198
|
async releaseSubaid(subAid) { return this._getOwnershipWorkflow().releaseSubaid(subAid); }
|
|
1189
1199
|
async transferSubaid(subAid, newOwnerAid) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid); }
|
|
1190
|
-
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
|
+
}
|
|
1191
1206
|
async bindAid(subjectAid, options = {}) {
|
|
1192
1207
|
throw ownershipFailure('unsupported_protocol', 'legacy bindAid is unsupported; use bindSubaid');
|
|
1193
1208
|
}
|
|
@@ -1394,6 +1409,9 @@ export class AUNClient {
|
|
|
1394
1409
|
this._identityRuntime.loadIdentity(aid);
|
|
1395
1410
|
this._stopCredentialRenewal();
|
|
1396
1411
|
this._serviceEventIdentityVersion++;
|
|
1412
|
+
this._auth.invalidateStrictPkiCache();
|
|
1413
|
+
this._certCache.clear();
|
|
1414
|
+
this._certFetchInFlight.clear();
|
|
1397
1415
|
this._serviceEventIdentityAbort.abort();
|
|
1398
1416
|
this._serviceEventIdentityAbort = new AbortController();
|
|
1399
1417
|
this._ensureReadStateIdentity();
|
|
@@ -3339,6 +3357,8 @@ export class AUNClient {
|
|
|
3339
3357
|
this._clientLog.debug(`bootstrap CA chain cache skipped: peer=${aid}, source=${opts.source ?? 'unknown'}, err=${formatCaughtError(exc)}`);
|
|
3340
3358
|
}
|
|
3341
3359
|
}
|
|
3360
|
+
const auth = this._auth;
|
|
3361
|
+
const pkiEpoch = auth._strictPkiEpoch;
|
|
3342
3362
|
try {
|
|
3343
3363
|
if (opts.signedAt === undefined)
|
|
3344
3364
|
await this._auth.verifyPeerCertificate(peerGatewayUrl, certPem, aid);
|
|
@@ -3356,20 +3376,21 @@ export class AUNClient {
|
|
|
3356
3376
|
}
|
|
3357
3377
|
throw new ValidationError(`peer cert verification failed for ${aid}: ${exc instanceof Error ? exc.message : String(exc)}`);
|
|
3358
3378
|
}
|
|
3379
|
+
if (auth !== this._auth || pkiEpoch !== auth._strictPkiEpoch)
|
|
3380
|
+
throw new ValidationError('peer certificate validation context changed');
|
|
3359
3381
|
const nowSec = Date.now() / 1000;
|
|
3360
3382
|
const entry = {
|
|
3361
3383
|
certPem,
|
|
3362
3384
|
validatedAt: nowSec,
|
|
3363
|
-
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,
|
|
3364
3388
|
};
|
|
3365
|
-
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;
|
|
3366
3392
|
this._certCache.set(cacheKey, entry);
|
|
3367
|
-
|
|
3368
|
-
const bareKey = AUNClient._certCacheKey(aid);
|
|
3369
|
-
this._certCache.set(bareKey, entry);
|
|
3370
|
-
const actualFp = `sha256:${x509Cert.fingerprint256.replace(/:/g, '').toLowerCase()}`;
|
|
3371
|
-
this._certCache.set(AUNClient._certCacheKey(aid, actualFp), entry);
|
|
3372
|
-
}
|
|
3393
|
+
this._certCache.set(AUNClient._certCacheKey(aid, certFingerprint) + scope, entry);
|
|
3373
3394
|
try {
|
|
3374
3395
|
// peer 证书只存版本目录,不覆盖 cert.pem
|
|
3375
3396
|
this._tokenStore.saveCert(aid, certPem, opts.agentMdRead && opts.signedAt !== undefined ? `sha256:${x509Cert.fingerprint256.replace(/:/g, '').toLowerCase()}` : certFingerprint, { makeActive: false });
|
|
@@ -3391,14 +3412,46 @@ export class AUNClient {
|
|
|
3391
3412
|
const tStart = Date.now();
|
|
3392
3413
|
this._clientLog.debug(`_fetchPeerCert enter: aid=${aid}, fp=${certFingerprint ?? ''}`);
|
|
3393
3414
|
try {
|
|
3394
|
-
const cacheKey = AUNClient._certCacheKey(aid, certFingerprint) + (signedAt === undefined ? '' : `:
|
|
3415
|
+
const cacheKey = AUNClient._certCacheKey(aid, certFingerprint) + (signedAt === undefined ? '' : `:historical${agentMdRead ? ':agentmd' : ''}`);
|
|
3395
3416
|
const cached = this._certCache.get(cacheKey);
|
|
3396
3417
|
const now = Date.now() / 1000;
|
|
3397
|
-
|
|
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
|
+
}
|
|
3398
3451
|
this._clientLog.debug(`_fetchPeerCert exit: elapsed=${Date.now() - tStart}ms aid=${aid} (cache_hit)`);
|
|
3399
3452
|
return cached.certPem;
|
|
3400
3453
|
}
|
|
3401
|
-
const inFlightKey = `${cacheKey}:timeout:${timeoutMs}`;
|
|
3454
|
+
const inFlightKey = `${cacheKey}:signed:${signedAt ?? 'current'}:timeout:${timeoutMs}:pki:${pkiEpoch}`;
|
|
3402
3455
|
const pending = this._certFetchInFlight.get(inFlightKey);
|
|
3403
3456
|
if (pending)
|
|
3404
3457
|
return await pending;
|
|
@@ -3409,6 +3462,8 @@ export class AUNClient {
|
|
|
3409
3462
|
}
|
|
3410
3463
|
const peerGatewayUrl = AUNClient._resolvePeerGatewayUrl(gatewayUrl, aid);
|
|
3411
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');
|
|
3412
3467
|
const validated = await this._validateAndCachePeerCert({
|
|
3413
3468
|
aid,
|
|
3414
3469
|
certPem,
|
|
@@ -3829,7 +3884,9 @@ export class AUNClient {
|
|
|
3829
3884
|
}
|
|
3830
3885
|
/** 构建证书下载 URL */
|
|
3831
3886
|
static _certCacheKey(aid, certFingerprint) {
|
|
3832
|
-
const
|
|
3887
|
+
const raw = String(certFingerprint ?? '').trim().toLowerCase();
|
|
3888
|
+
const hex = normalizeFingerprintHex(raw);
|
|
3889
|
+
const normalized = hex ? `sha256:${hex}` : raw;
|
|
3833
3890
|
return normalized ? `${aid}#${normalized}` : aid;
|
|
3834
3891
|
}
|
|
3835
3892
|
static _buildCertUrl(gatewayUrl, aid, certFingerprint) {
|
|
@@ -4874,6 +4931,9 @@ export class AUNClient {
|
|
|
4874
4931
|
/** 停止所有后台任务 */
|
|
4875
4932
|
_stopBackgroundTasks() {
|
|
4876
4933
|
this._stopCredentialRenewal();
|
|
4934
|
+
this._auth.invalidateStrictPkiCache();
|
|
4935
|
+
this._certCache.clear();
|
|
4936
|
+
this._certFetchInFlight.clear();
|
|
4877
4937
|
if (this._heartbeatTimer !== null) {
|
|
4878
4938
|
clearInterval(this._heartbeatTimer);
|
|
4879
4939
|
this._heartbeatTimer = null;
|