@agentunion/fastaun-browser 0.5.18 → 0.5.19
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 +44 -2
- package/_packed_docs/CHANGELOG.md +44 -2
- package/_packed_docs/INDEX.md +136 -14
- package/_packed_docs/KITE_DOCS_GUIDE.md +42 -16
- package/_packed_docs/agent.md/SCHEMA.md +245 -205
- 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 +42 -15
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +4 -4
- package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +45 -134
- package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +5 -20
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -9
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +22 -27
- package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +5 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +250 -283
- package/_packed_docs/sdk/09-group-rpc-manual.md +46 -14
- package/_packed_docs/sdk/09-message-rpc-manual.md +40 -2
- package/_packed_docs/sdk/09-storage-rpc-manual.md +74 -64
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +25 -5
- package/_packed_docs/sdk/INDEX.md +76 -17
- package/dist/agent-md-schema.d.ts +3 -0
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +45 -11
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +45 -2
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +519 -30
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +12 -46
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +113 -246
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +20 -7
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +4 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +343 -23
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +37330 -32005
- package/dist/cert-utils.d.ts +1 -1
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +19 -7
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +15 -1
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +147 -51
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +19 -5
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +104 -30
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +100 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1204 -23
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -2
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +4 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +41 -1
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +82 -2
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +98 -4
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +17 -0
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +10 -1
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +111 -0
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +7 -1
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +30 -1
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +98 -0
- package/dist/org-protocol.d.ts.map +1 -0
- package/dist/org-protocol.js +1742 -0
- package/dist/org-protocol.js.map +1 -0
- package/dist/ownership-proof.d.ts +93 -5
- package/dist/ownership-proof.d.ts.map +1 -1
- package/dist/ownership-proof.js +239 -53
- package/dist/ownership-proof.js.map +1 -1
- package/dist/ownership-v21.d.ts +177 -0
- package/dist/ownership-v21.d.ts.map +1 -0
- package/dist/ownership-v21.js +609 -0
- package/dist/ownership-v21.js.map +1 -0
- package/dist/ownership-workflow.d.ts +146 -0
- package/dist/ownership-workflow.d.ts.map +1 -0
- package/dist/ownership-workflow.js +1066 -0
- package/dist/ownership-workflow.js.map +1 -0
- package/dist/seq-tracker.d.ts +1 -0
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +10 -2
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +82 -0
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +332 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +6 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +88 -2
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +1 -0
- package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
- package/dist/v2/e2ee/decrypt.js +9 -1
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/aid-store.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { AID } from './aid.js';
|
|
2
|
-
import { CryptoProvider, pemToArrayBuffer, importPrivateKeyEcdsa, importCertPublicKeyEcdsa, ecdsaSignDer, ecdsaVerifyDer } from './crypto.js';
|
|
2
|
+
import { CryptoProvider, pemToArrayBuffer, importPrivateKeyEcdsa, importCertPublicKeyEcdsa, ecdsaSignDer, ecdsaVerifyDer, certificateSha256Fingerprint } from './crypto.js';
|
|
3
3
|
import * as codes from './error-codes.js';
|
|
4
4
|
import { certMatchesFingerprint, publicKeyDerB64 } from './cert-utils.js';
|
|
5
5
|
import { RegisterFlow } from './register-flow.js';
|
|
6
6
|
import { GatewayDiscovery } from './discovery.js';
|
|
7
|
-
import { ClientSignatureError, IdentityConflictError, NotFoundError, ValidationError } from './errors.js';
|
|
7
|
+
import { AUNError, ClientSignatureError, IdentityConflictError, NotFoundError, StateError, ValidationError } from './errors.js';
|
|
8
8
|
import { IndexedDBIdentityStore } from './keystore/indexeddb-identity-store.js';
|
|
9
9
|
import { IndexedDBTokenStore } from './keystore/indexeddb-token-store.js';
|
|
10
10
|
import { getDeviceId, normalizeSlotId } from './config.js';
|
|
11
11
|
import { resultErr, resultOk } from './result.js';
|
|
12
12
|
import { AgentMdManager, buildDefaultAgentMd } from './agent-md.js';
|
|
13
13
|
import { AuthFlow } from './auth.js';
|
|
14
|
-
import {
|
|
14
|
+
import { parseOwnershipRegistrationIntent } from './ownership-workflow.js';
|
|
15
|
+
import { validateAIDFormat } from './validators.js';
|
|
16
|
+
import { validateAgentMdDocument } from './agent-md-schema.js';
|
|
15
17
|
// ── 证书 DER 解析工具 ────────────────────────────────────────────
|
|
16
18
|
function _derReadLength(data, offset) {
|
|
17
19
|
if (offset >= data.length)
|
|
@@ -266,6 +268,8 @@ function resultError(result) {
|
|
|
266
268
|
return result.ok ? null : result.error;
|
|
267
269
|
}
|
|
268
270
|
function agentMdFailure(exc) {
|
|
271
|
+
if (exc instanceof AUNError && exc.stringCode)
|
|
272
|
+
return resultErr(exc.stringCode, exc.message, exc);
|
|
269
273
|
if (exc instanceof ClientSignatureError) {
|
|
270
274
|
return resultErr(codes.SIGNATURE_INVALID, exc.message, exc);
|
|
271
275
|
}
|
|
@@ -277,19 +281,6 @@ function agentMdFailure(exc) {
|
|
|
277
281
|
}
|
|
278
282
|
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
279
283
|
}
|
|
280
|
-
function ownerAgentMd(content, ownerAid, proof) {
|
|
281
|
-
const marker = content.indexOf('<!-- AUN-SIGNATURE');
|
|
282
|
-
const payload = marker >= 0 ? content.slice(0, marker) : content;
|
|
283
|
-
const lines = payload.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
|
|
284
|
-
const end = lines.findIndex((line, index) => index > 0 && line.trim() === '---');
|
|
285
|
-
if (end < 0)
|
|
286
|
-
throw new ValidationError('agent.md frontmatter is required for ownership operation');
|
|
287
|
-
const filtered = lines.filter((line, index) => !(index > 0 && index < end && (/^\s*owner\s*:/.test(line) || /^\s*ownership_proof\s*:/.test(line))));
|
|
288
|
-
const closed = filtered.findIndex((line, index) => index > 0 && line.trim() === '---');
|
|
289
|
-
filtered.splice(closed, 0, `owner: ${JSON.stringify(ownerAid)}`, `ownership_proof: ${JSON.stringify(proof)}`);
|
|
290
|
-
const result = filtered.join('\n');
|
|
291
|
-
return result.endsWith('\n') ? result : `${result}\n`;
|
|
292
|
-
}
|
|
293
284
|
export class AIDStore {
|
|
294
285
|
aunPath;
|
|
295
286
|
deviceId;
|
|
@@ -337,7 +328,10 @@ export class AIDStore {
|
|
|
337
328
|
tokenStore: this._tokenStore,
|
|
338
329
|
aidValidator: (target) => this._registerFlow.validateAidName(target),
|
|
339
330
|
gatewayResolver: (target) => this._resolveGateway(target),
|
|
340
|
-
|
|
331
|
+
entityOwnerResolver: (target, type) => this._resolveEntityAgentMdOwner(target, type),
|
|
332
|
+
entityIdentityGetter: (target, type) => this._currentEntityCertificate(target, type ?? 'group'),
|
|
333
|
+
entitySignerResolver: (target, fingerprint) => this._currentEntitySigner(target, fingerprint),
|
|
334
|
+
peerResolver: async (target, certFingerprint, signedAt) => {
|
|
341
335
|
const fp = String(certFingerprint ?? '').trim().toLowerCase();
|
|
342
336
|
const cachedCert = await this._keystore.loadCert(target, fp || undefined);
|
|
343
337
|
if (cachedCert) {
|
|
@@ -349,7 +343,7 @@ export class AIDStore {
|
|
|
349
343
|
if (!response.ok)
|
|
350
344
|
throw new Error(`certificate not found for aid: ${target}`);
|
|
351
345
|
const certPem = await response.text();
|
|
352
|
-
await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, fp);
|
|
346
|
+
await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, fp, signedAt);
|
|
353
347
|
await this._keystore.saveCert(target, certPem, fp, { makeActive: false });
|
|
354
348
|
return await AID.create({ aid: target, aunPath: this.aunPath, certPem, privateKeyPem: null, certValid: true, privateKeyValid: false });
|
|
355
349
|
}
|
|
@@ -357,7 +351,7 @@ export class AIDStore {
|
|
|
357
351
|
const certPem = await this._registerFlow.fetchPeerCert(gatewayUrl, target);
|
|
358
352
|
if (!certPem)
|
|
359
353
|
throw new Error(`certificate not found for aid: ${target}`);
|
|
360
|
-
await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem);
|
|
354
|
+
await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, undefined, signedAt);
|
|
361
355
|
await this._keystore.saveCert(target, certPem);
|
|
362
356
|
return await AID.create({ aid: target, aunPath: this.aunPath, certPem, privateKeyPem: null, certValid: true, privateKeyValid: false });
|
|
363
357
|
},
|
|
@@ -386,6 +380,9 @@ export class AIDStore {
|
|
|
386
380
|
catch (exc) {
|
|
387
381
|
return resultErr(codes.CERT_PARSE_ERROR, `certificate parse failed for aid: ${target}`, exc);
|
|
388
382
|
}
|
|
383
|
+
if (await this._tokenStore.getMetadata?.(target, 'invalidated_entity_certificate') === await certificateSha256Fingerprint(certPem)) {
|
|
384
|
+
return resultErr(codes.CERT_NOT_VALID, `group/org identity has been invalidated: ${target}`);
|
|
385
|
+
}
|
|
389
386
|
// 有效期检查(对齐 Python cert_time_error)
|
|
390
387
|
const validity = parseCertValidity(certPem);
|
|
391
388
|
if (!validity) {
|
|
@@ -492,12 +489,25 @@ export class AIDStore {
|
|
|
492
489
|
listAsync() {
|
|
493
490
|
return this.list();
|
|
494
491
|
}
|
|
495
|
-
async
|
|
492
|
+
async register(aid, options) {
|
|
496
493
|
const target = String(aid ?? '').trim();
|
|
497
494
|
try {
|
|
498
495
|
if (!target)
|
|
499
496
|
throw new ValidationError("AIDStore.register requires 'aid'");
|
|
500
497
|
this._registerFlow.validateAidName(target);
|
|
498
|
+
const type = String(options?.type ?? '').trim(), owner = String(options?.owner ?? '').trim().toLowerCase();
|
|
499
|
+
const entity = ['group', 'org'].includes(type);
|
|
500
|
+
if (!type || type === 'human' && owner || (type === 'agent' || entity) && !owner)
|
|
501
|
+
throw new ValidationError('register requires type; human forbids owner; agent/group/org requires owner');
|
|
502
|
+
if (owner)
|
|
503
|
+
validateAIDFormat(owner, 'owner');
|
|
504
|
+
const previousRaw = await this._tokenStore.getMetadata(target, 'registration_intent');
|
|
505
|
+
const previous = previousRaw ? parseOwnershipRegistrationIntent(previousRaw, target) : null;
|
|
506
|
+
const exttype = String(options?.exttype ?? '').trim();
|
|
507
|
+
if (previous && (previous.type !== type || previous.owner !== owner || previous.exttype !== exttype))
|
|
508
|
+
throw new StateError('ownership registration intent changed', { stringCode: 'conflict' });
|
|
509
|
+
const intent = previous ?? (entity ? { schema_version: 1, sub_aid: target, type, owner, exttype, protocol: 'entity', pending: false } : { schema_version: 1, sub_aid: target, type, owner, exttype, operation_id: crypto.randomUUID(), pending: Boolean(owner) });
|
|
510
|
+
await this._tokenStore.setMetadata(target, 'registration_intent', JSON.stringify(intent));
|
|
501
511
|
const gatewayUrl = await this._resolveGateway(target);
|
|
502
512
|
const result = await this._registerFlow.registerAid(gatewayUrl, target);
|
|
503
513
|
if (result.cert) {
|
|
@@ -511,11 +521,16 @@ export class AIDStore {
|
|
|
511
521
|
});
|
|
512
522
|
}
|
|
513
523
|
await this._persistGatewayUrl(target, gatewayUrl);
|
|
514
|
-
if (
|
|
515
|
-
await this.
|
|
524
|
+
if (!entity) {
|
|
525
|
+
const snapshot = await this._agentMdManager.readOwnershipFresh(target).catch(() => null);
|
|
526
|
+
if (snapshot && !snapshot.exists && snapshot.relation_version === 0 && snapshot.lock === 'unlocked')
|
|
527
|
+
await this.uploadAgentMd(target, buildDefaultAgentMd(target, { type, exttype: intent.exttype }));
|
|
528
|
+
}
|
|
516
529
|
return resultOk({ registered: true });
|
|
517
530
|
}
|
|
518
531
|
catch (exc) {
|
|
532
|
+
if (exc instanceof StateError && exc.stringCode)
|
|
533
|
+
return resultErr(exc.stringCode, exc.message, exc);
|
|
519
534
|
if (exc instanceof IdentityConflictError) {
|
|
520
535
|
return resultErr(codes.IDENTITY_CONFLICT, String(exc), exc);
|
|
521
536
|
}
|
|
@@ -529,218 +544,6 @@ export class AIDStore {
|
|
|
529
544
|
return resultErr(codes.SERVER_ERROR, message, exc);
|
|
530
545
|
}
|
|
531
546
|
}
|
|
532
|
-
async register(aidOrParams) {
|
|
533
|
-
if (typeof aidOrParams === 'string')
|
|
534
|
-
return await this.registerIdentity(aidOrParams);
|
|
535
|
-
const params = aidOrParams;
|
|
536
|
-
const target = String(params?.aid ?? '').trim();
|
|
537
|
-
const aidType = String(params?.type ?? '').trim().toLowerCase();
|
|
538
|
-
const owner = String(params?.owner ?? params?.owner_aid ?? '').trim();
|
|
539
|
-
if (!target || !aidType)
|
|
540
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'register requires aid and type');
|
|
541
|
-
try {
|
|
542
|
-
const identity = await this.registerIdentity(target, false);
|
|
543
|
-
if (!identity.ok)
|
|
544
|
-
return identity;
|
|
545
|
-
const gatewayUrl = await this._resolveGateway(target);
|
|
546
|
-
const prepareParams = { aid: target, type: aidType };
|
|
547
|
-
if (owner)
|
|
548
|
-
prepareParams.owner = owner;
|
|
549
|
-
const idempotencyKey = params.idempotencyKey ?? params.idempotency_key;
|
|
550
|
-
if (idempotencyKey)
|
|
551
|
-
prepareParams.idempotency_key = idempotencyKey;
|
|
552
|
-
const prepared = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_register_prepare', prepareParams);
|
|
553
|
-
const operationId = String(prepared.operation_id ?? '').trim();
|
|
554
|
-
if (!operationId)
|
|
555
|
-
throw new ValidationError('aid_register_prepare response missing operation_id');
|
|
556
|
-
let subjectSignature = params.subjectSignature ?? params.subject_signature;
|
|
557
|
-
const ownerSignature = params.ownerSignature ?? params.owner_signature;
|
|
558
|
-
if (!subjectSignature && owner) {
|
|
559
|
-
const loaded = await this.load(target);
|
|
560
|
-
if (loaded.ok) {
|
|
561
|
-
const statement = OwnershipStatement.create(String(prepared.proof_id ?? ''), target, owner);
|
|
562
|
-
const signed = await signOwnershipStatement({ certFingerprint: loaded.data.aid.certFingerprint, sign: (payload) => loaded.data.aid.sign(payload) }, statement);
|
|
563
|
-
subjectSignature = { cert_fingerprint: signed.cert_fingerprint, signature: signed.signature };
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
const signatures = {};
|
|
567
|
-
if (subjectSignature)
|
|
568
|
-
signatures.subject_signature = subjectSignature;
|
|
569
|
-
if (ownerSignature)
|
|
570
|
-
signatures.owner_signature = ownerSignature;
|
|
571
|
-
let response = prepared;
|
|
572
|
-
if (Object.keys(signatures).length > 0)
|
|
573
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_register_submit', { operation_id: operationId, ...signatures });
|
|
574
|
-
const state = String(response.state ?? response.operation_state ?? '').toLowerCase();
|
|
575
|
-
const complete = !owner || owner === target || (!!ownerSignature && !!subjectSignature);
|
|
576
|
-
if (complete && state === 'agent_md_pending') {
|
|
577
|
-
let content = params.agentMd ?? params.agent_md ?? buildDefaultAgentMd(target, { type: aidType });
|
|
578
|
-
if (owner) {
|
|
579
|
-
const proof = { proof_id: prepared.proof_id, subject_aid: target, owner_aid: owner, fact_hash: prepared.fact_hash, statement_hash: prepared.statement_hash, subject_signature: subjectSignature };
|
|
580
|
-
if (owner !== target)
|
|
581
|
-
proof.owner_signature = ownerSignature;
|
|
582
|
-
content = ownerAgentMd(content, owner, proof);
|
|
583
|
-
}
|
|
584
|
-
const uploaded = await this.uploadAgentMd(target, content, { ownerOperationId: operationId });
|
|
585
|
-
if (!uploaded.ok)
|
|
586
|
-
return uploaded;
|
|
587
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_register_activate', { operation_id: operationId });
|
|
588
|
-
}
|
|
589
|
-
return resultOk(response);
|
|
590
|
-
}
|
|
591
|
-
catch (exc) {
|
|
592
|
-
if (exc instanceof ValidationError)
|
|
593
|
-
return resultErr(codes.INVALID_AID_FORMAT, exc.message, exc);
|
|
594
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
async create(params) { return await this.register(params); }
|
|
598
|
-
async bindAid(params) {
|
|
599
|
-
const target = String(params?.aid ?? '').trim();
|
|
600
|
-
const aidType = String(params?.type ?? '').trim().toLowerCase();
|
|
601
|
-
const owner = String(params?.owner ?? params?.owner_aid ?? '').trim();
|
|
602
|
-
if (!target || !aidType)
|
|
603
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'bindAid requires aid and type');
|
|
604
|
-
try {
|
|
605
|
-
this._registerFlow.validateAidName(target);
|
|
606
|
-
const gatewayUrl = await this._resolveGateway(target);
|
|
607
|
-
const prepareParams = { aid: target, type: aidType };
|
|
608
|
-
if (owner)
|
|
609
|
-
prepareParams.owner = owner;
|
|
610
|
-
const idempotencyKey = params.idempotencyKey ?? params.idempotency_key;
|
|
611
|
-
if (idempotencyKey)
|
|
612
|
-
prepareParams.idempotency_key = idempotencyKey;
|
|
613
|
-
const prepared = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_bind_prepare', prepareParams);
|
|
614
|
-
const operationId = String(prepared.operation_id ?? '').trim();
|
|
615
|
-
if (!operationId)
|
|
616
|
-
throw new ValidationError('aid_bind_prepare response missing operation_id');
|
|
617
|
-
const signatures = {};
|
|
618
|
-
let subjectSignature = params.subjectSignature ?? params.subject_signature;
|
|
619
|
-
if (!subjectSignature && owner) {
|
|
620
|
-
const loaded = await this.load(target);
|
|
621
|
-
if (loaded.ok) {
|
|
622
|
-
const statement = OwnershipStatement.create(String(prepared.proof_id ?? ''), target, owner);
|
|
623
|
-
const signed = await signOwnershipStatement(loaded.data.aid, statement);
|
|
624
|
-
subjectSignature = { cert_fingerprint: signed.cert_fingerprint, signature: signed.signature };
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (subjectSignature)
|
|
628
|
-
signatures.subject_signature = subjectSignature;
|
|
629
|
-
const ownerSignature = params.ownerSignature ?? params.owner_signature;
|
|
630
|
-
if (ownerSignature)
|
|
631
|
-
signatures.owner_signature = ownerSignature;
|
|
632
|
-
let response = prepared;
|
|
633
|
-
if (Object.keys(signatures).length > 0) {
|
|
634
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_bind_submit', { operation_id: operationId, ...signatures });
|
|
635
|
-
}
|
|
636
|
-
const agentMd = params.agentMd ?? params.agent_md;
|
|
637
|
-
if (agentMd !== undefined) {
|
|
638
|
-
const uploaded = await this.uploadAgentMd(target, agentMd, {
|
|
639
|
-
ownerOperationId: operationId,
|
|
640
|
-
});
|
|
641
|
-
if (!uploaded.ok)
|
|
642
|
-
return uploaded;
|
|
643
|
-
}
|
|
644
|
-
const state = String(response.state ?? response.operation_state ?? '').toLowerCase();
|
|
645
|
-
if (state === 'agent_md_pending' || (!Object.keys(signatures).length && !owner && String(prepared.state ?? '') === 'agent_md_pending')) {
|
|
646
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_bind_activate', { operation_id: operationId });
|
|
647
|
-
}
|
|
648
|
-
return resultOk(response);
|
|
649
|
-
}
|
|
650
|
-
catch (exc) {
|
|
651
|
-
if (exc instanceof ValidationError)
|
|
652
|
-
return resultErr(codes.INVALID_AID_FORMAT, exc.message, exc);
|
|
653
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
async getAidBindingStatus(aid) {
|
|
657
|
-
const target = String(aid ?? '').trim();
|
|
658
|
-
if (!target)
|
|
659
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'getAidBindingStatus requires aid');
|
|
660
|
-
try {
|
|
661
|
-
this._registerFlow.validateAidName(target);
|
|
662
|
-
const gatewayUrl = await this._resolveGateway(target);
|
|
663
|
-
return resultOk(await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_bind_status', { aid: target }));
|
|
664
|
-
}
|
|
665
|
-
catch (exc) {
|
|
666
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
async resumeAidBinding(operationId) {
|
|
670
|
-
const target = String(operationId ?? '').trim();
|
|
671
|
-
if (!target)
|
|
672
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'resumeAidBinding requires operationId');
|
|
673
|
-
try {
|
|
674
|
-
const gatewayUrl = await this._resolveGateway(target);
|
|
675
|
-
let response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_operation_get', { operation_id: target });
|
|
676
|
-
if (String(response.state ?? response.operation_state ?? '').toLowerCase() === 'agent_md_pending') {
|
|
677
|
-
const method = String(response.kind ?? '').toLowerCase() === 'owner_change' ? 'auth.owner_change_activate' : 'auth.aid_bind_activate';
|
|
678
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, method, { operation_id: target });
|
|
679
|
-
}
|
|
680
|
-
return resultOk(response);
|
|
681
|
-
}
|
|
682
|
-
catch (exc) {
|
|
683
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
async bind_aid(params) { return this.bindAid(params); }
|
|
687
|
-
async get_aid_binding_status(aid) { return this.getAidBindingStatus(aid); }
|
|
688
|
-
async resume_aid_binding(operationId) { return this.resumeAidBinding(operationId); }
|
|
689
|
-
async changeOwner(params) {
|
|
690
|
-
const subject = String(params?.subject_aid ?? params?.aid ?? '').trim();
|
|
691
|
-
const newOwner = String(params?.new_owner_aid ?? params?.new_owner ?? '').trim();
|
|
692
|
-
if (!subject || !newOwner)
|
|
693
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'changeOwner requires subject_aid and new_owner_aid');
|
|
694
|
-
try {
|
|
695
|
-
this._registerFlow.validateAidName(subject);
|
|
696
|
-
const gatewayUrl = await this._resolveGateway(subject);
|
|
697
|
-
const prepare = { subject_aid: subject, new_owner_aid: newOwner };
|
|
698
|
-
if (params.current_owner_aid ?? params.owner_aid)
|
|
699
|
-
prepare.current_owner_aid = params.current_owner_aid ?? params.owner_aid;
|
|
700
|
-
if (params.expected_relation_version !== undefined)
|
|
701
|
-
prepare.expected_relation_version = params.expected_relation_version;
|
|
702
|
-
if (params.idempotencyKey ?? params.idempotency_key)
|
|
703
|
-
prepare.idempotency_key = params.idempotencyKey ?? params.idempotency_key;
|
|
704
|
-
const prepared = await this._registerFlow.shortRpc(gatewayUrl, 'auth.owner_change_prepare', prepare);
|
|
705
|
-
const operationId = String(prepared.operation_id ?? '').trim();
|
|
706
|
-
if (!operationId)
|
|
707
|
-
throw new ValidationError('owner_change_prepare response missing operation_id');
|
|
708
|
-
const signatures = {};
|
|
709
|
-
for (const key of ['old_owner_signature', 'subject_signature', 'new_owner_signature'])
|
|
710
|
-
if (params[key])
|
|
711
|
-
signatures[key] = params[key];
|
|
712
|
-
let response = prepared;
|
|
713
|
-
if (Object.keys(signatures).length > 0)
|
|
714
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.owner_change_submit', { operation_id: operationId, ...signatures });
|
|
715
|
-
if (String(response.state ?? response.operation_state ?? '').toLowerCase() === 'agent_md_pending' && (params.agentMd ?? params.agent_md) !== undefined) {
|
|
716
|
-
const proof = { proof_id: prepared.proof_id, subject_aid: subject, owner_aid: newOwner, fact_hash: prepared.fact_hash, statement_hash: prepared.statement_hash, subject_signature: params.subject_signature, owner_signature: params.new_owner_signature };
|
|
717
|
-
const content = ownerAgentMd(String(params.agentMd ?? params.agent_md), newOwner, proof);
|
|
718
|
-
const uploaded = await this.uploadAgentMd(subject, content, { ownerOperationId: operationId });
|
|
719
|
-
if (!uploaded.ok)
|
|
720
|
-
return uploaded;
|
|
721
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.owner_change_activate', { operation_id: operationId });
|
|
722
|
-
}
|
|
723
|
-
return resultOk(response);
|
|
724
|
-
}
|
|
725
|
-
catch (exc) {
|
|
726
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
async resumeOwnerChange(operationId, aid) {
|
|
730
|
-
const id = String(operationId ?? '').trim();
|
|
731
|
-
if (!id)
|
|
732
|
-
return resultErr(codes.INVALID_AID_FORMAT, 'resumeOwnerChange requires operationId');
|
|
733
|
-
try {
|
|
734
|
-
const gatewayUrl = await this._resolveGateway(String(aid ?? id));
|
|
735
|
-
let response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.aid_operation_get', { operation_id: id });
|
|
736
|
-
if (String(response.state ?? response.operation_state ?? '').toLowerCase() === 'agent_md_pending')
|
|
737
|
-
response = await this._registerFlow.shortRpc(gatewayUrl, 'auth.owner_change_activate', { operation_id: id });
|
|
738
|
-
return resultOk(response);
|
|
739
|
-
}
|
|
740
|
-
catch (exc) {
|
|
741
|
-
return resultErr(codes.NETWORK_ERROR, exc instanceof Error ? exc.message : String(exc), exc);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
547
|
async exists(aid) {
|
|
745
548
|
const target = String(aid ?? '').trim();
|
|
746
549
|
try {
|
|
@@ -812,12 +615,30 @@ export class AIDStore {
|
|
|
812
615
|
return agentMdFailure(exc);
|
|
813
616
|
}
|
|
814
617
|
}
|
|
815
|
-
async _verifyDownloadedPeerCertificate(gatewayUrl, aid, certPem, certFingerprint = '') {
|
|
618
|
+
async _verifyDownloadedPeerCertificate(gatewayUrl, aid, certPem, certFingerprint = '', signedAt) {
|
|
816
619
|
const expectedFp = String(certFingerprint ?? '').trim().toLowerCase();
|
|
817
620
|
if (expectedFp && !(await certMatchesFingerprint(certPem, expectedFp))) {
|
|
818
621
|
throw new ValidationError(`certificate fingerprint mismatch for aid: ${aid}`);
|
|
819
622
|
}
|
|
820
|
-
|
|
623
|
+
if (signedAt === undefined)
|
|
624
|
+
await this._peerAuth.verifyPeerCertificate(gatewayUrl, certPem, aid);
|
|
625
|
+
else
|
|
626
|
+
await this._peerAuth.verifyPeerCertificate(gatewayUrl, certPem, aid, signedAt);
|
|
627
|
+
}
|
|
628
|
+
async _resolveEntityAgentMdOwner(aid, type) {
|
|
629
|
+
const authority = await this._agentMdManager.readEntityAuthorityFresh(aid);
|
|
630
|
+
const certificate = await this._currentEntityCertificate(aid, type);
|
|
631
|
+
if (authority.entity_cert_fingerprint !== certificate.certFingerprint)
|
|
632
|
+
throw new StateError('entity certificate authority changed', { stringCode: 'conflict' });
|
|
633
|
+
return authority.owner_aid;
|
|
634
|
+
}
|
|
635
|
+
async _currentEntityCertificate(aid, type) {
|
|
636
|
+
const cert = await this._peerAuth.resolveCurrentEntityCertificate(await this._resolveGateway(aid), aid, type);
|
|
637
|
+
return AID.create({ aid, aunPath: this.aunPath, certPem: cert.cert_pem, certValid: true, privateKeyPem: null, privateKeyValid: false });
|
|
638
|
+
}
|
|
639
|
+
async _currentEntitySigner(aid, fingerprint) {
|
|
640
|
+
const cert = await this._peerAuth.resolveOwnershipCertificate(await this._resolveGateway(aid), aid, fingerprint);
|
|
641
|
+
return AID.create({ aid, aunPath: this.aunPath, certPem: cert.cert_pem, certValid: true, privateKeyPem: null, privateKeyValid: false });
|
|
821
642
|
}
|
|
822
643
|
_authIdentityFromAid(aid) {
|
|
823
644
|
return {
|
|
@@ -853,10 +674,14 @@ export class AIDStore {
|
|
|
853
674
|
return resultErr(loaded.error.code, loaded.error.message);
|
|
854
675
|
}
|
|
855
676
|
const current = loaded.data.aid;
|
|
856
|
-
|
|
677
|
+
const raw = content ?? await this._agentMdManager.readContent(target);
|
|
678
|
+
const parsed = validateAgentMdDocument(String(raw ?? ''), { expectedAid: target });
|
|
679
|
+
const meta = parsed.frontmatter;
|
|
680
|
+
const entity = ['group', 'org'].includes(String(meta.type));
|
|
681
|
+
if ((!current.isPrivateKeyValid() || !current.privateKeyPem) && !(entity && parsed.signature)) {
|
|
857
682
|
return resultErr(codes.PRIVATE_KEY_NOT_VALID, `uploadAgentMd requires local AID with a valid private key: ${target}`);
|
|
858
683
|
}
|
|
859
|
-
const uploaderTarget = String(options.uploaderAid ?? options.uploader_aid ?? target).trim();
|
|
684
|
+
const uploaderTarget = String(options.uploaderAid ?? options.uploader_aid ?? (entity ? meta.owner : target)).trim();
|
|
860
685
|
this._registerFlow.validateAidName(uploaderTarget);
|
|
861
686
|
let uploader = current;
|
|
862
687
|
if (uploaderTarget.toLowerCase() !== target.toLowerCase()) {
|
|
@@ -865,22 +690,24 @@ export class AIDStore {
|
|
|
865
690
|
return resultErr(uploaderLoaded.error.code, uploaderLoaded.error.message);
|
|
866
691
|
}
|
|
867
692
|
uploader = uploaderLoaded.data.aid;
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
693
|
+
}
|
|
694
|
+
if (!uploader.isPrivateKeyValid() || !uploader.privateKeyPem) {
|
|
695
|
+
return resultErr(codes.PRIVATE_KEY_NOT_VALID, `uploadAgentMd requires uploader AID with a valid private key: ${uploaderTarget}`);
|
|
871
696
|
}
|
|
872
697
|
const manager = new AgentMdManager({
|
|
873
698
|
aunPath: this.aunPath,
|
|
874
699
|
tokenStore: this._tokenStore,
|
|
875
700
|
uploadViaGatewayHost: true,
|
|
876
|
-
ownerAidGetter: () =>
|
|
877
|
-
currentAidGetter: () =>
|
|
701
|
+
ownerAidGetter: () => uploaderTarget,
|
|
702
|
+
currentAidGetter: () => uploader,
|
|
703
|
+
entityOwnerResolver: options.entityOwnerResolver ?? ((value, type) => this._resolveEntityAgentMdOwner(value, type)),
|
|
704
|
+
entityIdentityGetter: options.entityIdentityGetter ?? ((value, type) => this._currentEntityCertificate(value, type ?? 'group')),
|
|
705
|
+
entitySignerResolver: options.entitySignerResolver ?? ((value, fingerprint) => this._currentEntitySigner(value, fingerprint)),
|
|
878
706
|
gatewayResolver: (value) => this._resolveGateway(value),
|
|
879
707
|
accessTokenResolver: async () => this._uploadAgentMdToken(uploader, await this._resolveGateway(uploaderTarget)),
|
|
880
708
|
aidValidator: (value) => this._registerFlow.validateAidName(value),
|
|
881
709
|
});
|
|
882
|
-
|
|
883
|
-
return resultOk(await manager.upload(content, ownerOperationId));
|
|
710
|
+
return resultOk(entity ? await manager.uploadAs(target, String(raw), current) : await manager.upload(raw));
|
|
884
711
|
}
|
|
885
712
|
catch (exc) {
|
|
886
713
|
return agentMdFailure(exc);
|
|
@@ -977,7 +804,45 @@ export class AIDStore {
|
|
|
977
804
|
return resultErr(codes.PRIVATE_KEY_REQUIRED, `private key required for aid: ${target}`);
|
|
978
805
|
}
|
|
979
806
|
const gatewayUrl = await this._resolveGateway(target);
|
|
980
|
-
const
|
|
807
|
+
const pendingStore = this._keystore;
|
|
808
|
+
let pendingDir = null;
|
|
809
|
+
let newIdentity = null;
|
|
810
|
+
for (const handle of await pendingStore.listPendingIdentityDirs(target)) {
|
|
811
|
+
const candidate = await pendingStore.loadPendingKeyPair(handle, target);
|
|
812
|
+
if (candidate?.rekey_pending === true) {
|
|
813
|
+
pendingDir = handle;
|
|
814
|
+
newIdentity = candidate;
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
if (newIdentity) {
|
|
819
|
+
const serverCert = await this._registerFlow.fetchPeerCert(gatewayUrl, target);
|
|
820
|
+
if (serverCert) {
|
|
821
|
+
const validity = parseCertValidity(serverCert);
|
|
822
|
+
const now = Date.now();
|
|
823
|
+
if (publicKeyDerB64(serverCert) === newIdentity.public_key_der_b64
|
|
824
|
+
&& parseCertCN(serverCert) === target
|
|
825
|
+
&& validity && now >= validity.notBefore && now <= validity.notAfter) {
|
|
826
|
+
await pendingStore.savePendingCert(pendingDir, serverCert);
|
|
827
|
+
await this._keystore.saveIdentity(target, {
|
|
828
|
+
aid: target, private_key_pem: newIdentity.private_key_pem,
|
|
829
|
+
public_key_der_b64: newIdentity.public_key_der_b64, curve: newIdentity.curve, cert: serverCert,
|
|
830
|
+
});
|
|
831
|
+
await pendingStore.discardPendingIdentity(pendingDir);
|
|
832
|
+
const refreshed = await this.load(target);
|
|
833
|
+
if (!refreshed.ok || !refreshed.data)
|
|
834
|
+
return resultErr(codes.REKEY_FAILED, 'rekeyed identity reload failed');
|
|
835
|
+
return resultOk({ rekeyed: true, new_cert_not_after: refreshed.data.aid.certNotAfter, new_fingerprint: refreshed.data.aid.certFingerprint });
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
newIdentity = await this._registerFlow.generateIdentity();
|
|
841
|
+
pendingDir = await pendingStore.pendingIdentityDir(target);
|
|
842
|
+
await pendingStore.savePendingKeyPair(pendingDir, target, { ...newIdentity, aid: target, rekey_pending: true });
|
|
843
|
+
}
|
|
844
|
+
if (!pendingDir || !newIdentity)
|
|
845
|
+
return resultErr(codes.REKEY_FAILED, 'pending rekey identity is unavailable');
|
|
981
846
|
const phase1 = await this._beginAidOperation(gatewayUrl, oldAid);
|
|
982
847
|
const signPayload = `${String(phase1.nonce ?? '')}${newIdentity.public_key_der_b64}`;
|
|
983
848
|
const signResult = await loaded.data.aid.sign(signPayload);
|
|
@@ -993,6 +858,7 @@ export class AIDStore {
|
|
|
993
858
|
const certPem = String(response.cert ?? response.cert_pem ?? '').trim();
|
|
994
859
|
if (!certPem)
|
|
995
860
|
return resultErr(codes.REKEY_FAILED, 'server response missing certificate');
|
|
861
|
+
await pendingStore.savePendingCert(pendingDir, certPem);
|
|
996
862
|
const nextIdentity = {
|
|
997
863
|
aid: target,
|
|
998
864
|
private_key_pem: newIdentity.private_key_pem,
|
|
@@ -1001,6 +867,7 @@ export class AIDStore {
|
|
|
1001
867
|
cert: certPem,
|
|
1002
868
|
};
|
|
1003
869
|
await this._keystore.saveIdentity(target, nextIdentity);
|
|
870
|
+
await pendingStore.discardPendingIdentity(pendingDir);
|
|
1004
871
|
const refreshed = await this.load(target);
|
|
1005
872
|
if (!refreshed.ok)
|
|
1006
873
|
return resultErr(codes.REKEY_FAILED, 'rekeyed identity reload failed');
|