@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.
Files changed (118) hide show
  1. package/CHANGELOG.md +44 -2
  2. package/_packed_docs/CHANGELOG.md +44 -2
  3. package/_packed_docs/INDEX.md +136 -14
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +42 -16
  5. package/_packed_docs/agent.md/SCHEMA.md +245 -205
  6. 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
  7. 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
  8. 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
  9. 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
  10. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -9
  11. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +22 -27
  12. package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
  13. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +5 -2
  14. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +250 -283
  15. package/_packed_docs/sdk/09-group-rpc-manual.md +46 -14
  16. package/_packed_docs/sdk/09-message-rpc-manual.md +40 -2
  17. package/_packed_docs/sdk/09-storage-rpc-manual.md +74 -64
  18. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +25 -5
  19. package/_packed_docs/sdk/INDEX.md +76 -17
  20. package/dist/agent-md-schema.d.ts +3 -0
  21. package/dist/agent-md-schema.d.ts.map +1 -1
  22. package/dist/agent-md-schema.js +45 -11
  23. package/dist/agent-md-schema.js.map +1 -1
  24. package/dist/agent-md.d.ts +45 -2
  25. package/dist/agent-md.d.ts.map +1 -1
  26. package/dist/agent-md.js +519 -30
  27. package/dist/agent-md.js.map +1 -1
  28. package/dist/aid-store.d.ts +12 -46
  29. package/dist/aid-store.d.ts.map +1 -1
  30. package/dist/aid-store.js +113 -246
  31. package/dist/aid-store.js.map +1 -1
  32. package/dist/aid.d.ts.map +1 -1
  33. package/dist/aid.js +20 -7
  34. package/dist/aid.js.map +1 -1
  35. package/dist/auth.d.ts +4 -1
  36. package/dist/auth.d.ts.map +1 -1
  37. package/dist/auth.js +343 -23
  38. package/dist/auth.js.map +1 -1
  39. package/dist/bundle.js +37330 -32005
  40. package/dist/cert-utils.d.ts +1 -1
  41. package/dist/cert-utils.d.ts.map +1 -1
  42. package/dist/cert-utils.js +19 -7
  43. package/dist/cert-utils.js.map +1 -1
  44. package/dist/client/delivery.d.ts +15 -1
  45. package/dist/client/delivery.d.ts.map +1 -1
  46. package/dist/client/delivery.js +147 -51
  47. package/dist/client/delivery.js.map +1 -1
  48. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  49. package/dist/client/rpc-pipeline.js +19 -5
  50. package/dist/client/rpc-pipeline.js.map +1 -1
  51. package/dist/client/v2-e2ee.d.ts +1 -0
  52. package/dist/client/v2-e2ee.d.ts.map +1 -1
  53. package/dist/client/v2-e2ee.js +104 -30
  54. package/dist/client/v2-e2ee.js.map +1 -1
  55. package/dist/client.d.ts +100 -1
  56. package/dist/client.d.ts.map +1 -1
  57. package/dist/client.js +1204 -23
  58. package/dist/client.js.map +1 -1
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +3 -2
  61. package/dist/errors.js.map +1 -1
  62. package/dist/events.d.ts +4 -0
  63. package/dist/events.d.ts.map +1 -1
  64. package/dist/events.js +41 -1
  65. package/dist/events.js.map +1 -1
  66. package/dist/facades.d.ts +82 -2
  67. package/dist/facades.d.ts.map +1 -1
  68. package/dist/facades.js +98 -4
  69. package/dist/facades.js.map +1 -1
  70. package/dist/index.d.ts +7 -3
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +3 -2
  73. package/dist/index.js.map +1 -1
  74. package/dist/keystore/index.d.ts +17 -0
  75. package/dist/keystore/index.d.ts.map +1 -1
  76. package/dist/keystore/indexeddb-shared.d.ts +10 -1
  77. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  78. package/dist/keystore/indexeddb-shared.js +111 -0
  79. package/dist/keystore/indexeddb-shared.js.map +1 -1
  80. package/dist/keystore/indexeddb-token-store.d.ts +7 -1
  81. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  82. package/dist/keystore/indexeddb-token-store.js +30 -1
  83. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  84. package/dist/org-protocol.d.ts +98 -0
  85. package/dist/org-protocol.d.ts.map +1 -0
  86. package/dist/org-protocol.js +1742 -0
  87. package/dist/org-protocol.js.map +1 -0
  88. package/dist/ownership-proof.d.ts +93 -5
  89. package/dist/ownership-proof.d.ts.map +1 -1
  90. package/dist/ownership-proof.js +239 -53
  91. package/dist/ownership-proof.js.map +1 -1
  92. package/dist/ownership-v21.d.ts +177 -0
  93. package/dist/ownership-v21.d.ts.map +1 -0
  94. package/dist/ownership-v21.js +609 -0
  95. package/dist/ownership-v21.js.map +1 -0
  96. package/dist/ownership-workflow.d.ts +146 -0
  97. package/dist/ownership-workflow.d.ts.map +1 -0
  98. package/dist/ownership-workflow.js +1066 -0
  99. package/dist/ownership-workflow.js.map +1 -0
  100. package/dist/seq-tracker.d.ts +1 -0
  101. package/dist/seq-tracker.d.ts.map +1 -1
  102. package/dist/seq-tracker.js +10 -2
  103. package/dist/seq-tracker.js.map +1 -1
  104. package/dist/tools/cross-sdk-agent.d.ts +82 -0
  105. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  106. package/dist/tools/cross-sdk-agent.js +332 -7
  107. package/dist/tools/cross-sdk-agent.js.map +1 -1
  108. package/dist/transport.d.ts +6 -0
  109. package/dist/transport.d.ts.map +1 -1
  110. package/dist/transport.js +88 -2
  111. package/dist/transport.js.map +1 -1
  112. package/dist/v2/e2ee/decrypt.d.ts +1 -0
  113. package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
  114. package/dist/v2/e2ee/decrypt.js +9 -1
  115. package/dist/v2/e2ee/decrypt.js.map +1 -1
  116. package/dist/version.d.ts +1 -1
  117. package/dist/version.js +1 -1
  118. 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 { OwnershipStatement, signOwnershipStatement } from './ownership-proof.js';
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
- peerResolver: async (target, certFingerprint) => {
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 registerIdentity(aid, uploadDefault = true) {
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 (uploadDefault)
515
- await this.uploadAgentMd(target, buildDefaultAgentMd(target));
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
- await this._peerAuth.verifyPeerCertificate(gatewayUrl, certPem, aid);
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
- if (!current.isPrivateKeyValid() || !current.privateKeyPem) {
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
- if (!uploader.isPrivateKeyValid() || !uploader.privateKeyPem) {
869
- return resultErr(codes.PRIVATE_KEY_NOT_VALID, `uploadAgentMd requires uploader AID with a valid private key: ${uploaderTarget}`);
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: () => target,
877
- currentAidGetter: () => current,
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
- const ownerOperationId = options.ownerOperationId ?? options.owner_operation_id;
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 newIdentity = await this._registerFlow.generateIdentity();
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');