@agentunion/fastaun 0.5.26 → 0.5.28

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 (94) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/_packed_docs/CHANGELOG.md +77 -0
  3. package/_packed_docs/INDEX.md +37 -14
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +23 -15
  5. 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 +16 -1
  6. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +37 -9
  7. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +20 -9
  8. package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +57 -12
  9. 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 +2 -2
  10. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +2 -2
  11. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +187 -73
  12. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +1 -1
  13. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -9
  14. package/_packed_docs/sdk/INDEX.md +23 -13
  15. 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 +973 -266
  16. 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 +950 -242
  17. package/dist/agent-md-changes.d.ts +42 -0
  18. package/dist/agent-md-changes.js +339 -0
  19. package/dist/agent-md-changes.js.map +1 -0
  20. package/dist/agent-md-schema.d.ts +1 -0
  21. package/dist/agent-md-schema.js +31 -14
  22. package/dist/agent-md-schema.js.map +1 -1
  23. package/dist/agent-md.d.ts +11 -0
  24. package/dist/agent-md.js +91 -15
  25. package/dist/agent-md.js.map +1 -1
  26. package/dist/aid-store.d.ts +11 -0
  27. package/dist/aid-store.js +102 -21
  28. package/dist/aid-store.js.map +1 -1
  29. package/dist/aid.js +3 -3
  30. package/dist/aid.js.map +1 -1
  31. package/dist/auth.d.ts +10 -0
  32. package/dist/auth.js +65 -23
  33. package/dist/auth.js.map +1 -1
  34. package/dist/cert-utils.d.ts +1 -1
  35. package/dist/cert-utils.js +4 -4
  36. package/dist/cert-utils.js.map +1 -1
  37. package/dist/client/control-messages.d.ts +31 -0
  38. package/dist/client/control-messages.js +474 -0
  39. package/dist/client/control-messages.js.map +1 -0
  40. package/dist/client/delivery.js +10 -2
  41. package/dist/client/delivery.js.map +1 -1
  42. package/dist/client/lifecycle.d.ts +1 -1
  43. package/dist/client/lifecycle.js +10 -0
  44. package/dist/client/lifecycle.js.map +1 -1
  45. package/dist/client/rpc-pipeline.js +84 -14
  46. package/dist/client/rpc-pipeline.js.map +1 -1
  47. package/dist/client/v2-e2ee.d.ts +3 -0
  48. package/dist/client/v2-e2ee.js +12 -0
  49. package/dist/client/v2-e2ee.js.map +1 -1
  50. package/dist/client.d.ts +38 -0
  51. package/dist/client.js +572 -36
  52. package/dist/client.js.map +1 -1
  53. package/dist/discovery.d.ts +3 -0
  54. package/dist/discovery.js +52 -2
  55. package/dist/discovery.js.map +1 -1
  56. package/dist/events.js +14 -1
  57. package/dist/events.js.map +1 -1
  58. package/dist/facades.d.ts +38 -0
  59. package/dist/facades.js +49 -5
  60. package/dist/facades.js.map +1 -1
  61. package/dist/index.d.ts +4 -0
  62. package/dist/index.js +3 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/org-protocol.d.ts +1 -0
  65. package/dist/org-protocol.js +39 -36
  66. package/dist/org-protocol.js.map +1 -1
  67. package/dist/ownership-v21.js +7 -7
  68. package/dist/ownership-v21.js.map +1 -1
  69. package/dist/register-flow.js +2 -2
  70. package/dist/register-flow.js.map +1 -1
  71. package/dist/risk-control.d.ts +68 -0
  72. package/dist/risk-control.js +344 -0
  73. package/dist/risk-control.js.map +1 -0
  74. package/dist/semantic-facade.d.ts +176 -0
  75. package/dist/semantic-facade.js +611 -0
  76. package/dist/semantic-facade.js.map +1 -0
  77. package/dist/semantic-protocol.d.ts +810 -0
  78. package/dist/semantic-protocol.js +894 -0
  79. package/dist/semantic-protocol.js.map +1 -0
  80. package/dist/storage/lowlevel.d.ts +1 -0
  81. package/dist/storage/lowlevel.js +2 -2
  82. package/dist/storage/lowlevel.js.map +1 -1
  83. package/dist/tools/cross-sdk-agent.d.ts +11 -1
  84. package/dist/tools/cross-sdk-agent.js +388 -7
  85. package/dist/tools/cross-sdk-agent.js.map +1 -1
  86. package/dist/transport.d.ts +22 -1
  87. package/dist/transport.js +227 -22
  88. package/dist/transport.js.map +1 -1
  89. package/dist/v2/e2ee/decrypt.d.ts +5 -0
  90. package/dist/v2/e2ee/decrypt.js +22 -2
  91. package/dist/v2/e2ee/decrypt.js.map +1 -1
  92. package/dist/version.d.ts +1 -1
  93. package/dist/version.js +1 -1
  94. package/package.json +1 -1
@@ -4,6 +4,7 @@ import * as https from 'node:https';
4
4
  import * as crypto from 'node:crypto';
5
5
  import * as fs from 'node:fs';
6
6
  import * as path from 'node:path';
7
+ import { createRequire } from 'node:module';
7
8
  import { tmpdir } from 'node:os';
8
9
  import { AsyncLocalStorage } from 'node:async_hooks';
9
10
  import { URL } from 'node:url';
@@ -11,13 +12,38 @@ import { fileURLToPath } from 'node:url';
11
12
  import { AUNClient } from '../client.js';
12
13
  import { AID } from '../aid.js';
13
14
  import { AIDStore } from '../aid-store.js';
14
- import { publicKeyFingerprint } from '../cert-utils.js';
15
+ import { certCommonName, certFingerprint, isStrictBase64, publicKeyFingerprint, verifySignatureWithCert } from '../cert-utils.js';
16
+ import { validateAgentMdCertificate } from '../agent-md-schema.js';
17
+ import { createDefaultSecretStore } from '../secret-store/index.js';
18
+ import { normalizeGroupId } from '../group-id.js';
19
+ import { validateAIDFormat } from '../validators.js';
15
20
  import { VERSION } from '../version.js';
16
21
  import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
22
+ import { decodeBase64 as semanticBase64, decodeSignedJson, digest as semanticDigest, validateStatusProof, SemanticProtocolError } from '../semantic-protocol.js';
17
23
  import { TimeoutError } from '../errors.js';
18
24
  const credentialProcessStartupId = crypto.randomUUID();
25
+ const { DatabaseSync } = createRequire(import.meta.url)('node:sqlite');
19
26
  const cacheReadContext = new AsyncLocalStorage();
20
27
  const cacheReadObservers = new WeakMap();
28
+ function loadTrustedArchive(configPath, issuer) {
29
+ if (!configPath)
30
+ return undefined;
31
+ const value = jsonObjectOf(JSON.parse(fs.readFileSync(configPath, 'utf8')));
32
+ const owner = value?.owner_aid, routed = typeof owner === 'string' && owner.indexOf('.') > 0 && owner.indexOf('.') < owner.length - 1;
33
+ if (!value || Object.keys(value).some(key => !['service_aid', 'objects', 'owner_aid'].includes(key)) || Object.keys(value).length !== (routed ? 3 : 2) || ('owner_aid' in value && !routed) || value.service_aid !== `storage.${routed ? owner.slice(owner.indexOf('.') + 1) : issuer}` || !Array.isArray(value.objects))
34
+ throw new Error('ARCHIVE_SERVICE_UNTRUSTED');
35
+ const objects = new Map();
36
+ for (const row of value.objects) {
37
+ const item = jsonObjectOf(row);
38
+ if (!item || Object.keys(item).length !== 3 || !['object_id', 'object_version', 'share_id'].every(key => typeof item[key] === 'string' && item[key]))
39
+ throw new Error('ARCHIVE_OBJECT_UNTRUSTED');
40
+ const key = JSON.stringify([item.object_id, item.object_version]);
41
+ if (objects.has(key))
42
+ throw new Error('ARCHIVE_OBJECT_DUPLICATE');
43
+ objects.set(key, item.share_id);
44
+ }
45
+ return { serviceAid: value.service_aid, ...(routed ? { ownerAid: owner } : {}), objects };
46
+ }
21
47
  function acquireCacheReadObserver(target, key, wrap) {
22
48
  let observers = cacheReadObservers.get(target);
23
49
  if (!observers) {
@@ -147,6 +173,10 @@ export class CrossSdkTsAgent {
147
173
  slotId = textOf(process.env.AUN_TEST_SLOT_ID || `cross-sdk-ts-${crypto.randomUUID().slice(0, 8)}`).trim();
148
174
  aunPath = textOf(process.env.AUN_TEST_AUN_PATH || process.env.AUN_DATA_ROOT || '/data/aun').trim();
149
175
  debug = envBool('AUN_TEST_DEBUG', false);
176
+ semanticReaderIdentityDir = textOf(process.env.AUN_SEMANTIC_READER_IDENTITY_DIR).trim();
177
+ semanticReaderAid = textOf(process.env.AUN_SEMANTIC_READER_AID).trim();
178
+ semanticReaderSeed = process.env.AUN_TEST_ENCRYPTION_SEED || process.env.AUN_ENCRYPTION_SEED || '';
179
+ semanticArchive = loadTrustedArchive(textOf(process.env.AUN_TEST_SEMANTIC_ARCHIVE_CONFIG), this.issuer);
150
180
  client;
151
181
  ready = false;
152
182
  startupError = '';
@@ -740,7 +770,10 @@ export class CrossSdkTsAgent {
740
770
  const identity = JSON.parse(fs.readFileSync(fixedIdentityFile, 'utf-8'));
741
771
  if (identity.aid !== this.aid)
742
772
  throw new Error('固定测试身份与配置 AID 不一致');
743
- store._keystore.saveIdentity(this.aid, identity);
773
+ const local = store.load(this.aid);
774
+ if (!local.ok || !local.data.aid.isPrivateKeyValid()) {
775
+ store._keystore.saveIdentity(this.aid, identity);
776
+ }
744
777
  }
745
778
  const registered = fixedIdentityFile ? store.load(this.aid) : await store.register(this.aid, { type: 'service' });
746
779
  if (!registered.ok) {
@@ -913,6 +946,7 @@ export class CrossSdkTsAgent {
913
946
  error_code: errorCode,
914
947
  raw_sha256: sha256Json(data),
915
948
  ...metadata,
949
+ ...(decrypted && jsonObjectOf(data._semantic_evidence) ? { _semantic_evidence: structuredClone(data._semantic_evidence) } : {}),
916
950
  };
917
951
  }
918
952
  normalizeGroupMessage(msg, decrypted, errorCode = '') {
@@ -934,6 +968,7 @@ export class CrossSdkTsAgent {
934
968
  error_code: errorCode,
935
969
  raw_sha256: sha256Json(data),
936
970
  ...metadata,
971
+ ...(decrypted && jsonObjectOf(data._semantic_evidence) ? { _semantic_evidence: structuredClone(data._semantic_evidence) } : {}),
937
972
  };
938
973
  }
939
974
  async storeGroupInboxItem(item) {
@@ -954,6 +989,7 @@ export class CrossSdkTsAgent {
954
989
  aid: this.aid,
955
990
  language: this.language,
956
991
  sdk_version: this.sdkVersion,
992
+ gateway_url: textOf(this.client._gatewayUrl),
957
993
  startup_error: this.startupError,
958
994
  });
959
995
  return;
@@ -1775,8 +1811,11 @@ export class CrossSdkTsAgent {
1775
1811
  return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
1776
1812
  if (op === 'revocation_checkpoint') {
1777
1813
  const internal = this.client;
1778
- if (params.sync === true)
1779
- await internal._getCredentialRenewal()._syncRevocations();
1814
+ if (params.sync === true) {
1815
+ const manager = internal._getCredentialRenewal();
1816
+ manager.invalidateQueries();
1817
+ await manager._syncRevocations();
1818
+ }
1780
1819
  return internal._tokenStore._loadMetadataStrict(this.aid)?.credential_revocations_v1 ?? { version: 1, authorities: {} };
1781
1820
  }
1782
1821
  if (op === 'credential_process')
@@ -1870,6 +1909,333 @@ export class CrossSdkTsAgent {
1870
1909
  }
1871
1910
  return result;
1872
1911
  }
1912
+ semanticReaderMessageContext() {
1913
+ const root = this.semanticReaderIdentityDir, aid = this.semanticReaderAid;
1914
+ if (!root && !aid)
1915
+ return {};
1916
+ if (!root || !aid || validateAIDFormat(aid) !== aid || !fs.statSync(root).isDirectory())
1917
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'fixed semantic reader identity is unavailable');
1918
+ const device = fs.readFileSync(path.join(root, '.device_id'), 'utf8').trim(), directory = path.join(root, 'AIDs', aid);
1919
+ if (!device)
1920
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver device is unavailable');
1921
+ const stored = JSON.parse(fs.readFileSync(path.join(directory, 'private', 'key.json'), 'utf8'));
1922
+ const pem = stored.private_key_pem || (stored.private_key_protection && createDefaultSecretStore(root, this.semanticReaderSeed).reveal(aid, 'identity/private_key', stored.private_key_protection)?.toString('utf8'));
1923
+ if (!pem)
1924
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver identity key is unavailable');
1925
+ const privateKey = crypto.createPrivateKey(pem), publicKey = crypto.createPublicKey(privateKey).export({ format: 'der', type: 'spki' });
1926
+ const certPem = fs.readFileSync(path.join(directory, 'public', 'cert.pem'), 'utf8'), certificate = new crypto.X509Certificate(certPem);
1927
+ const jwk = privateKey.export({ format: 'jwk' });
1928
+ if (certCommonName(certPem) !== aid || jwk.kty !== 'EC' || jwk.crv !== 'P-256' || !jwk.d
1929
+ || !publicKey.equals(certificate.publicKey.export({ format: 'der', type: 'spki' })))
1930
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver certificate or key differs');
1931
+ const ikPriv = new Uint8Array(Buffer.from(jwk.d, 'base64url'));
1932
+ return { selfAid: aid, selfDeviceId: device, resolveDecryptionKeys: (envelope) => {
1933
+ const row = Array.isArray(envelope.recipients) ? envelope.recipients.find((item) => Array.isArray(item) && item.length === 8 && item[0] === aid && (item[1] === device || item[1] === '')) : undefined;
1934
+ const recipient = jsonObjectOf(envelope.recipient);
1935
+ if (!row && (!recipient || recipient.aid !== aid || recipient.device_id !== device && recipient.device_id !== ''))
1936
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver row is unavailable');
1937
+ let spkId = textOf(row ? row[5] : recipient.spk_id), groupId = envelope.type === 'e2ee.group_encrypted' ? textOf(envelope.aad?.group_id) : '';
1938
+ if (!spkId)
1939
+ return { ikPriv };
1940
+ const separator = spkId.indexOf('\0');
1941
+ if (separator >= 0) {
1942
+ if (!groupId || normalizeGroupId(spkId.slice(0, separator)) !== normalizeGroupId(groupId))
1943
+ throw new SemanticProtocolError('SEMANTIC_BINDING_INVALID', 'original group SPK scope differs');
1944
+ spkId = spkId.slice(separator + 1);
1945
+ }
1946
+ const db = new DatabaseSync(path.join(directory, 'aun.db'), { readOnly: true });
1947
+ try {
1948
+ const find = (type, group) => db.prepare('SELECT private_key FROM v2_device_keys WHERE device_id=? AND key_type=? AND group_id=? AND key_id=?').get(device, type, group, spkId);
1949
+ let key;
1950
+ if (groupId)
1951
+ for (const candidate of new Set([groupId, normalizeGroupId(groupId)])) {
1952
+ key = find('group_spk', candidate);
1953
+ if (key)
1954
+ break;
1955
+ }
1956
+ key ??= find('spk', '');
1957
+ if (key)
1958
+ return { ikPriv, spkPriv: new Uint8Array(key.private_key) };
1959
+ const alias = find('ik', '');
1960
+ if (alias)
1961
+ return { ikPriv: new Uint8Array(alias.private_key), spkPriv: new Uint8Array(alias.private_key) };
1962
+ if (spkId === 'sha256:' + crypto.createHash('sha256').update(publicKey).digest('hex').slice(0, 16))
1963
+ return { ikPriv, spkPriv: ikPriv };
1964
+ throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'original receiver SPK is unavailable');
1965
+ }
1966
+ finally {
1967
+ db.close();
1968
+ }
1969
+ } };
1970
+ }
1971
+ semanticHistoricalSenderContext(context) {
1972
+ const certificates = jsonObjectOf(context.certificates);
1973
+ if (!certificates || Object.keys(certificates).length === 0)
1974
+ return {};
1975
+ const key = (fingerprint) => new crypto.X509Certificate(textOf(certificates[fingerprint])).publicKey.export({ type: 'spki', format: 'der' });
1976
+ return {
1977
+ resolveSenderKey: async (_sender, _device, fingerprint) => new Uint8Array(key(fingerprint)),
1978
+ verifySenderIdentity: async (sender, _device, fingerprint, signedAt, publicKey) => {
1979
+ if (!key(fingerprint).equals(Buffer.from(publicKey)))
1980
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'historical sender identity differs from message key');
1981
+ await this.client._semanticVerificationContext().verifyCertificateTrust(textOf(certificates[fingerprint]), { expectedAID: sender, signedAt, now: Math.floor(Date.now() / 1000) });
1982
+ },
1983
+ };
1984
+ }
1985
+ semanticContext(context, nativeOnline = false, original) {
1986
+ if (!nativeOnline && (['query', 'queries', 'query_started_monotonic', 'elapsed_seconds', 'elapsedSeconds', 'monotonicNow'].some(key => Object.hasOwn(context, key))
1987
+ || context.policy !== undefined && jsonObjectOf(context.policy)?.mode !== 'bounded') || context.require_current_validity === false || context.legacy_context !== undefined) {
1988
+ throw new SemanticProtocolError('SEMANTIC_FORMAT_INVALID', 'unsupported cross-process semantic verification context override');
1989
+ }
1990
+ const native = this.client._semanticVerificationContext();
1991
+ const certificates = jsonObjectOf(context.certificates) ?? {};
1992
+ const signers = jsonObjectOf(context.credential_signers);
1993
+ const services = jsonObjectOf(context.credential_services);
1994
+ const supplied = jsonObjectOf(original), credential = supplied && Object.hasOwn(supplied, 'bytes_base64') ? jsonObjectOf(decodeSignedJson(supplied)) : supplied;
1995
+ const signer = credential && signers ? textOf(signers[semanticDigest(credential)]) : '';
1996
+ const expectedAid = textOf(context.expected_aid);
1997
+ if (signer && expectedAid && signer !== expectedAid)
1998
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'explicit signer differs from trusted original signer');
1999
+ return { ...native, now: typeof context.now === 'number' ? context.now : Math.floor(Date.now() / 1000),
2000
+ expectedAid: expectedAid || signer || textOf(credential?.iss) || undefined, expectedServiceAid: textOf(context.service_aid) || undefined,
2001
+ audience: textOf(context.audience), statePolicy: context.policy,
2002
+ resolveCertificate: async (fingerprint, aid, signedAt) => Object.hasOwn(certificates, fingerprint)
2003
+ ? certificates[fingerprint] : native.resolveCertificate(fingerprint, aid, signedAt),
2004
+ ...(signers ? { originalSigner: (entry) => {
2005
+ const signer = textOf(signers[semanticDigest(entry.credential)]) || entry.credential.iss;
2006
+ if (!signer)
2007
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted original signer is required');
2008
+ return signer;
2009
+ } } : {}),
2010
+ ...(services ? { serviceFor: (cid) => {
2011
+ const service = Object.hasOwn(services, cid) ? textOf(services[cid]) : '';
2012
+ if (!service)
2013
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted credential service is required');
2014
+ return service;
2015
+ } } : {}),
2016
+ };
2017
+ }
2018
+ trustedArchiveResolvers() {
2019
+ const config = this.semanticArchive;
2020
+ if (!config)
2021
+ return {};
2022
+ return { [config.serviceAid]: async (locator) => {
2023
+ if (Object.keys(locator).length !== 4 || locator.resolver !== 'aun-evidence-archive/1' || locator.service_aid !== config.serviceAid)
2024
+ throw new Error('ARCHIVE_LOCATOR_UNTRUSTED');
2025
+ const share = config.objects.get(JSON.stringify([locator.object_id, locator.object_version]));
2026
+ if (!share)
2027
+ throw new Error('ARCHIVE_OBJECT_UNTRUSTED');
2028
+ const result = jsonObjectOf(await this.client.call('storage.get_by_share', { share_id: share, ...(config.ownerAid ? { owner_aid: config.ownerAid } : {}) }));
2029
+ if (!result || result.object_id !== locator.object_id || String(result.version) !== locator.object_version)
2030
+ throw new Error('ARCHIVE_OBJECT_VERSION_MISMATCH');
2031
+ const content = result.content;
2032
+ if (typeof content !== 'string' || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(content)
2033
+ || Buffer.from(content, 'base64').toString('base64') !== content)
2034
+ throw new Error('ARCHIVE_CONTENT_INVALID');
2035
+ return new Uint8Array(Buffer.from(content, 'base64'));
2036
+ } };
2037
+ }
2038
+ async verifySemanticRepresentative(request, context) {
2039
+ for (const grant of context.representation_grants ?? []) {
2040
+ const root = grant.lineage[0], leaf = grant.lineage.at(-1);
2041
+ if (root.credential.iss !== request.sub || root.metadata.iss !== request.sub || leaf.metadata.sub !== request.actor || !root.credential.cap.some((cap) => cap.ns === request.ns && [request.action, '*'].includes(cap.action) && [request.resource, '*'].includes(cap.resource) && cap.constraints.length === 0)
2042
+ || root.credential.authorization.kind !== 'text' || root.credential.authorization.text !== '签发者明确授权已确认持有人代表签发者执行所列能力,仅限本次隔离报告测试。')
2043
+ continue;
2044
+ const { params_hash: _paramsHash, request_binding: _binding, ...fixed } = request;
2045
+ const represented = await this.client.credential.buildRequest({ ...fixed, sub: request.actor, grant,
2046
+ request_id: request.request_id + '-representation', nonce: Buffer.from(semanticDigest([request.request_binding.request_hash, 'representation']).slice(7), 'hex').toString('base64url') });
2047
+ const nested = { ...context, representation_grants: undefined, grantors: [request.sub],
2048
+ credential_services: Object.fromEntries(grant.lineage.map((item) => [item.credential.cid, context.representation_service])),
2049
+ credential_signers: Object.fromEntries(grant.lineage.map((item) => [semanticDigest(item.credential), item.metadata.iss])) };
2050
+ const result = await this.semanticProtocol({ op: 'refresh_and_verify_request', params: represented, context: nested });
2051
+ return result.report.request_bound === true;
2052
+ }
2053
+ return false;
2054
+ }
2055
+ async semanticProtocol(params) {
2056
+ if (params.op === 'state_checkpoint')
2057
+ return { startup_id: credentialProcessStartupId, aid: this.aid, scope_identity: this.client._semanticContextKey(), state: this.client._loadSemanticState() };
2058
+ const facade = this.client.credential, op = textOf(params.op);
2059
+ if (op === 'probe_online_status') {
2060
+ const began = performance.now() / 1000, input = jsonObjectOf(params.params) ?? {}, target = textOf(params.target);
2061
+ const query = { request_hash: textOf(params.request_hash), nonce: crypto.randomBytes(24).toString('base64url') };
2062
+ const proof = await facade.status({ ...input, request_id: crypto.randomUUID(), nonce: query.nonce, query }, { serviceAid: target });
2063
+ const expectedQuery = { ...query };
2064
+ if (params.probe === 'nonce')
2065
+ expectedQuery.nonce = 'AAAAAAAAAAAAAAAAAAAAAA';
2066
+ if (params.probe === 'request_hash')
2067
+ expectedQuery.request_hash = `sha256:${'0'.repeat(64)}`;
2068
+ if (params.probe === 'timeout')
2069
+ await new Promise(resolve => setTimeout(resolve, Math.max(0, 30100 - (performance.now() / 1000 - began) * 1000)));
2070
+ const context = this.semanticContext({ service_aid: target, audience: input.audience }, true);
2071
+ const report = await facade.verifyStatus(proof, { ...context, policy: { mode: 'online' },
2072
+ query: params.probe === 'missing_query' ? undefined : expectedQuery, elapsedSeconds: performance.now() / 1000 - began });
2073
+ return { proof, query, report, elapsed_seconds: performance.now() / 1000 - began };
2074
+ }
2075
+ if (op === 'refresh_and_verify_request') {
2076
+ const began = performance.now() / 1000, request = structuredClone(params.params);
2077
+ const input = jsonObjectOf(params.context) ?? {}, context = this.semanticContext({ ...input, now: Math.floor(Date.now() / 1000) }, true);
2078
+ const query = { request_hash: request.request_binding.request_hash, nonce: crypto.randomBytes(24).toString('base64url') };
2079
+ const queries = {};
2080
+ const legacyProofs = new Map(), legacyChecks = [], reader = this.client.aid;
2081
+ const legacyCertificate = async (aid, signature, verifiedAt = Math.floor(Date.now() / 1000)) => {
2082
+ if (!signature || !Number.isSafeInteger(signature.timestamp) || signature.timestamp < 0 || signature.timestamp > Math.floor(Date.now() / 1000) + 300
2083
+ || typeof signature.cert_fingerprint !== 'string' || !/^sha256:[0-9a-f]{64}$/i.test(signature.cert_fingerprint)
2084
+ || typeof signature.signature !== 'string' || !isStrictBase64(signature.signature)
2085
+ || Object.keys(signature).some(key => !['cert_fingerprint', 'public_key_fingerprint', 'timestamp', 'signature'].includes(key)))
2086
+ throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy signature is invalid');
2087
+ const resolved = await context.resolveCertificate(signature.cert_fingerprint, aid, signature.timestamp);
2088
+ const material = resolved && typeof resolved === 'object' && !(resolved instanceof Uint8Array) ? resolved.certificatePem : resolved;
2089
+ if (!material)
2090
+ throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy certificate is unavailable');
2091
+ const certificate = new crypto.X509Certificate(typeof material === 'string' && !material.startsWith('-----BEGIN') ? Buffer.from(material, 'base64') : material).toString();
2092
+ if (certFingerprint(certificate).toLowerCase() !== signature.cert_fingerprint.toLowerCase()
2093
+ || signature.public_key_fingerprint !== undefined && (typeof signature.public_key_fingerprint !== 'string' || publicKeyFingerprint(certificate).toLowerCase() !== signature.public_key_fingerprint.toLowerCase()))
2094
+ throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy certificate fingerprint differs');
2095
+ validateAgentMdCertificate(certificate, aid, signature.timestamp, { now: verifiedAt, requireCurrentValidity: true });
2096
+ await context.verifyCertificateTrust(certificate, { expectedAID: aid, signedAt: signature.timestamp, now: Math.floor(Date.now() / 1000) });
2097
+ return certificate;
2098
+ };
2099
+ for (const entry of request.grant.lineage) {
2100
+ const cid = entry.credential.cid;
2101
+ if (!context.serviceFor)
2102
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted credential service is required');
2103
+ const service = context.serviceFor(cid);
2104
+ if (entry.credential.ver === 'aun-cap/1' && 'legacy' in entry) {
2105
+ const original = entry.credential, requestedAt = Math.floor(Date.now() / 1000);
2106
+ const statusQuery = { credential_cid: cid, include_chain: true, request_id: crypto.randomUUID(), nonce: crypto.randomBytes(24).toString('base64url') };
2107
+ statusQuery.request_binding = buildRequestBinding('credential.status', service, statusQuery, cid, String(statusQuery.nonce), String(statusQuery.request_id), requestedAt, requestedAt + 300);
2108
+ const proof = await facade.status(statusQuery), now = Math.floor(Date.now() / 1000);
2109
+ if (!reader || reader !== this.client.aid || !proof || proof.ver !== 'aun-credential-status/1' || proof.credentialCid !== cid || proof.credential_hash !== digest(original)
2110
+ || proof.issuerAid !== original.iss || proof.subjectAid !== original.sub || proof.expiresAt !== original.exp || proof.responder !== service
2111
+ || proof.target !== reader || proof.request_id !== statusQuery.request_id || proof.nonce !== statusQuery.nonce || proof.status !== 'active'
2112
+ || !Number.isSafeInteger(proof.asOf) || proof.asOf < 0 || !Number.isSafeInteger(proof.proofExpiresAt) || proof.proofExpiresAt <= proof.asOf
2113
+ || proof.proofExpiresAt > proof.asOf + 300 || proof.asOf > now + 300 || now > proof.proofExpiresAt + 300
2114
+ || proof.signature?.timestamp !== proof.asOf)
2115
+ throw new ProtocolError('CREDENTIAL_STATUS_UNKNOWN', 'fresh legacy status differs from credential or query');
2116
+ const certificate = await legacyCertificate(service, proof.signature), unsigned = { ...proof };
2117
+ delete unsigned.signature;
2118
+ if (!verifySignatureWithCert(certificate, Buffer.from(proof.signature.signature, 'base64'), Buffer.from(canonicalJson(unsigned))))
2119
+ throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'fresh legacy status signature is invalid');
2120
+ entry.legacy.status_proof = proof;
2121
+ legacyProofs.set(cid, proof);
2122
+ continue;
2123
+ }
2124
+ if (entry.credential.ver !== 'aun-cap/semantic-1' || !('metadata' in entry))
2125
+ continue;
2126
+ const semantic = entry;
2127
+ queries[cid] = query;
2128
+ semantic.status = await facade.status({ request_id: crypto.randomUUID(), nonce: crypto.randomBytes(24).toString('base64url'),
2129
+ credential_cid: cid, authority: input.authority, audience: context.audience,
2130
+ expected_revision: { cid, original_hash: semantic.metadata.original_hash, metadata_hash: semanticDigest(semantic.metadata), metadata_version: semantic.metadata.version },
2131
+ policy: { mode: 'online' }, query }, { serviceAid: service, verificationContext: context });
2132
+ }
2133
+ if (legacyProofs.size)
2134
+ context.legacyVerifier = async (entry, audience) => {
2135
+ const original = entry.credential, index = request.grant.lineage.findIndex(item => item.credential.cid === original.cid && digest(item.credential) === digest(original));
2136
+ if (index < 0)
2137
+ throw new ProtocolError('CREDENTIAL_CHAIN_INVALID', 'legacy original differs from fixed request lineage');
2138
+ const ancestors = request.grant.lineage.slice(0, index).reverse().map(item => item.credential), root = ancestors.at(-1) ?? original;
2139
+ if (!Array.isArray(input.grantors) || !input.grantors.includes(root.iss))
2140
+ throw new ProtocolError('CREDENTIAL_CHAIN_INVALID', 'legacy root issuer is not trusted for this resource');
2141
+ const certificates = new Map();
2142
+ for (const document of [original, ...ancestors])
2143
+ certificates.set(document.signature.cert_fingerprint, await legacyCertificate(document.iss, document.signature));
2144
+ const receipt = 'legacy' in entry ? entry.legacy.registration_receipt : undefined;
2145
+ if (receipt) {
2146
+ const service = context.serviceFor(original.cid), certificate = await legacyCertificate(service, receipt.signature, receipt.registered_at);
2147
+ facade.verifyRegistrationReceipt(receipt, original, { request_id: receipt.request_id, nonce: receipt.nonce, registrar_aid: original.iss, proof_chain: ancestors }, () => certificate, service, receipt.registered_at);
2148
+ }
2149
+ const now = Math.floor(Date.now() / 1000), method = request.ns + '.' + request.action;
2150
+ const requestBinding = buildRequestBinding(method, request.target, request.params, original.cid, request.nonce, request.request_id, now, now + 300);
2151
+ const verifyLegacy = () => {
2152
+ facade.verify(original, { audience, subject: original.sub, actor: original.sub, rootIssuer: root.iss, ns: request.ns, action: request.action, resource: request.resource,
2153
+ params: request.params, method, target: request.target, requestId: request.request_id, nonce: request.nonce,
2154
+ requestBinding, proofChain: ancestors, resolveCertificate: fingerprint => certificates.get(fingerprint), resolveStatusProof: cid => legacyProofs.get(cid), now: Math.floor(Date.now() / 1000) });
2155
+ };
2156
+ verifyLegacy();
2157
+ legacyChecks.push(verifyLegacy);
2158
+ };
2159
+ const packageReport = await facade.verifyPackage(request.grant, { ...context, audience: context.audience, now: Math.floor(Date.now() / 1000),
2160
+ statePolicy: { mode: 'online' }, queries, elapsedSeconds: performance.now() / 1000 - began });
2161
+ const requestReport = await facade.verifyRequest(request, input.authenticated, { now: Math.floor(Date.now() / 1000), representedActor: () => this.verifySemanticRepresentative(request, input) });
2162
+ const elapsedSeconds = performance.now() / 1000 - began;
2163
+ if (!Number.isFinite(elapsedSeconds) || elapsedSeconds < 0 || elapsedSeconds >= 30)
2164
+ throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'online status monotonic lifetime exceeded');
2165
+ for (const entry of request.grant.lineage)
2166
+ if (entry.credential.ver === 'aun-cap/semantic-1' && 'status' in entry) {
2167
+ validateStatusProof(entry.status, { mode: 'online' }, { now: Math.floor(Date.now() / 1000), elapsedSeconds, query });
2168
+ }
2169
+ for (const proof of legacyProofs.values())
2170
+ if (reader !== this.client.aid || Math.floor(Date.now() / 1000) < Number(proof.asOf) - 300 || Math.floor(Date.now() / 1000) > Number(proof.proofExpiresAt) + 300)
2171
+ throw new ProtocolError('CREDENTIAL_STATUS_UNKNOWN', 'fresh legacy status expired before verification completed');
2172
+ for (const verifyLegacy of legacyChecks)
2173
+ verifyLegacy();
2174
+ if (legacyChecks.length && performance.now() / 1000 - began >= 30)
2175
+ throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'online status monotonic lifetime exceeded');
2176
+ if (requestReport.request_hash !== query.request_hash)
2177
+ throw new SemanticProtocolError('SEMANTIC_BINDING_INVALID', 'refreshed request hash differs');
2178
+ return { request, language: 'typescript', report: { ...packageReport, request_bound: true, request_hash: requestReport.request_hash,
2179
+ checked: [...new Set([...packageReport.checked, ...requestReport.checked, 'lineage_structure', 'signatures', 'identities', 'revisions', 'state', 'usage_refs', 'authenticated_request'])],
2180
+ required: [...new Set([...packageReport.required, ...requestReport.required.filter(item => item !== 'package_verification')])] } };
2181
+ }
2182
+ const management = { register: 'register', revise: 'revise', get: 'get', status: 'status', revoke: 'revoke', revocations: 'revocations', prepare_usage: 'prepareUsage', commit_usage: 'commitUsage', abort_usage: 'abortUsage' };
2183
+ if (Object.hasOwn(management, op)) {
2184
+ const method = management[op];
2185
+ return facade[method].call(facade, params.params, params.target ? { serviceAid: textOf(params.target) } : {});
2186
+ }
2187
+ const signatures = { sign_credential: 'signCredential', sign_metadata: 'signMetadata', sign_allocation: 'signAllocation' };
2188
+ if (Object.hasOwn(signatures, op))
2189
+ return facade[signatures[op]](params.value, undefined, typeof params.now === 'number' ? { timestamp: params.now } : {});
2190
+ if (op === 'sign_usage_record')
2191
+ return facade.signUsageRecord(params.domain, params.value, undefined, typeof params.now === 'number' ? { timestamp: params.now } : {});
2192
+ if (op === 'build_package')
2193
+ return facade.buildPackage(params.params.lineage);
2194
+ if (op === 'build_request')
2195
+ return facade.buildRequest(params.params, typeof params.now === 'number' ? { now: params.now } : {});
2196
+ const verification = { verify_original: 'verifyOriginal', verify_metadata: 'verifyMetadata', verify_receipt: 'verifyReceipt', verify_package: 'verifyPackage' };
2197
+ if (Object.hasOwn(verification, op))
2198
+ return facade[verification[op]].call(facade, params.value, this.semanticContext(jsonObjectOf(params.context) ?? {}, false, op === 'verify_original' ? params.value : undefined));
2199
+ if (op === 'verify_status') {
2200
+ const context = this.semanticContext(jsonObjectOf(params.context) ?? {});
2201
+ return facade.verifyStatus(params.value, { ...context, policy: context.statePolicy });
2202
+ }
2203
+ if (op === 'verify_usage_record')
2204
+ return facade.verifyUsageRecord(params.domain, params.value, this.semanticContext(jsonObjectOf(params.context) ?? {}));
2205
+ const input = (jsonObjectOf(params.params) ?? {});
2206
+ if (op === 'archive_received_message') {
2207
+ const item = [...this.inbox, ...this.groupInbox].find(value => value.message_id === input.message_id && value.decrypted === true && jsonObjectOf(value._semantic_evidence));
2208
+ const evidence = jsonObjectOf(item?._semantic_evidence);
2209
+ if (!evidence)
2210
+ throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'original decrypted message evidence is unavailable');
2211
+ const receiver = this.client.aid;
2212
+ if (!receiver || evidence.received_by !== receiver || receiver !== this.aid)
2213
+ throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original message receiver differs from current identity');
2214
+ const envelope = new Uint8Array(semanticBase64(evidence.envelope_bytes_base64));
2215
+ semanticBase64(evidence.payload_bytes_base64);
2216
+ return { archive: await facade.archiveMessage(envelope, { received_by: receiver, received_at: evidence.received_at, source: textOf(evidence.source) }),
2217
+ envelope_bytes_base64: evidence.envelope_bytes_base64, payload_bytes_base64: evidence.payload_bytes_base64 };
2218
+ }
2219
+ if (op === 'verify_request') {
2220
+ const request = input.request ?? input, actual = jsonObjectOf(input.context) ?? jsonObjectOf(params.context) ?? {}, context = this.semanticContext(actual);
2221
+ const packageReport = await facade.verifyPackage(request.grant, context);
2222
+ const requestReport = await facade.verifyRequest(request, actual.authenticated, { now: context.now });
2223
+ return { ...packageReport, ...requestReport, request_bound: true, checked: [...new Set([...packageReport.checked, ...requestReport.checked])] };
2224
+ }
2225
+ if (op === 'build_decision_input')
2226
+ return facade.buildDecisionInput(input.request, input.bodies, input.facts, input.policy);
2227
+ if (op === 'create_evidence_ref')
2228
+ return facade.createEvidenceRef(new Uint8Array(Buffer.from(textOf(input.bytes_base64), 'base64')), textOf(input.profile), input.locator);
2229
+ if (op === 'resolve_evidence')
2230
+ return { bytes_base64: Buffer.from(await facade.resolveEvidence(input.evidence ?? input, this.trustedArchiveResolvers())).toString('base64') };
2231
+ if (op === 'archive_message')
2232
+ return facade.archiveMessage(new Uint8Array(Buffer.from(textOf(input.bytes_base64), 'base64')), { received_by: this.aid, received_at: input.received_at, source: input.source });
2233
+ if (op === 'verify_message_body') {
2234
+ const context = jsonObjectOf(input.context) ?? jsonObjectOf(params.context) ?? {};
2235
+ return facade.verifyMessageBody(input.credential ?? input, { ...this.semanticContext(context, false, input.credential ?? input), ...this.semanticReaderMessageContext(), ...this.semanticHistoricalSenderContext(context), resolvers: this.trustedArchiveResolvers() });
2236
+ }
2237
+ throw new SemanticProtocolError('SEMANTIC_FORMAT_INVALID', `unsupported semantic protocol operation: ${op}`);
2238
+ }
1873
2239
  async groupCall(req, res) {
1874
2240
  const body = await readJson(req);
1875
2241
  const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
@@ -1888,6 +2254,9 @@ export class CrossSdkTsAgent {
1888
2254
  case 'sdk.org.protocol':
1889
2255
  result = await this.orgProtocol(params);
1890
2256
  break;
2257
+ case 'sdk.semantic.protocol':
2258
+ result = await this.semanticProtocol(params);
2259
+ break;
1891
2260
  case 'credential.register':
1892
2261
  result = await this.client.credential.register(params);
1893
2262
  break;
@@ -1900,9 +2269,16 @@ export class CrossSdkTsAgent {
1900
2269
  case 'credential.revocationList':
1901
2270
  result = await this.client.credential.revocationList(params);
1902
2271
  break;
1903
- case 'org.lifecycle.create':
1904
- result = await this.client.org.lifecycle.create(params);
2272
+ case 'org.lifecycle.create': {
2273
+ const store = this.aidStore();
2274
+ try {
2275
+ result = await this.client.org.lifecycle.create({ ...params, aidStore: store });
2276
+ }
2277
+ finally {
2278
+ store.close();
2279
+ }
1905
2280
  break;
2281
+ }
1906
2282
  case 'org.lifecycle.dissolve':
1907
2283
  result = await this.client.org.lifecycle.dissolve(params);
1908
2284
  break;
@@ -1992,9 +2368,14 @@ export class CrossSdkTsAgent {
1992
2368
  error_code: err instanceof Error ? err.name : 'Error',
1993
2369
  error_message: err instanceof Error ? err.message : String(err),
1994
2370
  };
1995
- if (method.startsWith('org.') || method === 'sdk.org.protocol') {
2371
+ if (method.startsWith('org.') || method.startsWith('credential.semantic.') || method === 'sdk.org.protocol' || method === 'sdk.semantic.protocol') {
1996
2372
  const remote = err;
1997
2373
  error.rpc_error_code = remote?.stringCode || remote?.data?.error_code || remote?.data?.code || (typeof remote?.code === 'string' ? remote.code : '');
2374
+ if (method.startsWith('credential.semantic.') || method === 'sdk.semantic.protocol') {
2375
+ error.rpc_numeric_code = typeof remote?.code === 'number' ? remote.code : null;
2376
+ error.error_data = jsonSafe(remote?.data);
2377
+ error.retryable = remote?.retryable === true || remote?.data?.retryable === true;
2378
+ }
1998
2379
  }
1999
2380
  this.recordTrace(traceId, { stage: 'group_call_error', method, error });
2000
2381
  sendJson(res, 500, error);