@yeying-community/web3-bs 1.0.14 → 1.0.16

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.
@@ -870,6 +870,73 @@
870
870
  function normalizeUcanExpiry(exp, fallbackMs) {
871
871
  return normalizeExpiry(exp, fallbackMs);
872
872
  }
873
+ function normalizeEthAccount(account) {
874
+ return String(account || '').trim().toLowerCase();
875
+ }
876
+ function parseUcanAccountFromIssuer(issuer) {
877
+ const normalized = String(issuer || '').trim().toLowerCase();
878
+ const prefix = 'did:pkh:eth:';
879
+ if (!normalized.startsWith(prefix))
880
+ return null;
881
+ const account = normalized.slice(prefix.length);
882
+ return account || null;
883
+ }
884
+ function getUcanIssuerForAccount(account) {
885
+ return `did:pkh:eth:${normalizeEthAccount(account)}`;
886
+ }
887
+ function extractUcanStatementPayload(message) {
888
+ if (!message || typeof message !== 'string')
889
+ return null;
890
+ const marker = 'UCAN-AUTH';
891
+ const index = message.indexOf(marker);
892
+ if (index < 0)
893
+ return null;
894
+ const jsonStart = message.indexOf('{', index + marker.length);
895
+ const jsonEnd = message.lastIndexOf('}');
896
+ if (jsonStart < 0 || jsonEnd < jsonStart)
897
+ return null;
898
+ try {
899
+ const parsed = JSON.parse(message.slice(jsonStart, jsonEnd + 1));
900
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
901
+ return null;
902
+ }
903
+ return parsed;
904
+ }
905
+ catch {
906
+ return null;
907
+ }
908
+ }
909
+ function getUcanRootServiceHosts(root) {
910
+ const payload = extractUcanStatementPayload(root.siwe?.message);
911
+ const hosts = payload?.service_hosts;
912
+ if (!hosts || typeof hosts !== 'object' || Array.isArray(hosts)) {
913
+ return null;
914
+ }
915
+ return hosts;
916
+ }
917
+ function getServiceHostMismatch(root, expectedServiceHosts) {
918
+ if (!expectedServiceHosts)
919
+ return null;
920
+ const entries = Object.entries(expectedServiceHosts)
921
+ .map(([key, value]) => [key, String(value || '').trim()])
922
+ .filter(([, value]) => Boolean(value));
923
+ if (!entries.length)
924
+ return null;
925
+ const hosts = getUcanRootServiceHosts(root);
926
+ if (!hosts) {
927
+ return {
928
+ expected: entries.map(([key, value]) => `${key}:${value}`).join('|'),
929
+ actual: '',
930
+ };
931
+ }
932
+ for (const [key, expected] of entries) {
933
+ const actual = typeof hosts[key] === 'string' ? hosts[key].trim() : '';
934
+ if (actual !== expected) {
935
+ return { expected, actual };
936
+ }
937
+ }
938
+ return null;
939
+ }
873
940
  function decodeUcanPayload(token) {
874
941
  const parts = String(token || '').split('.');
875
942
  if (parts.length < 2)
@@ -1297,6 +1364,105 @@
1297
1364
  function isRootExpired(root, nowMs) {
1298
1365
  return Boolean(root.exp && nowMs > root.exp);
1299
1366
  }
1367
+ async function resolveUcanAuthorization(options = {}) {
1368
+ const root = options.root === undefined
1369
+ ? await getStoredUcanRoot(options.sessionId || DEFAULT_SESSION_ID)
1370
+ : options.root;
1371
+ const nowMs = options.nowMs ?? Date.now();
1372
+ if (!root) {
1373
+ return { status: 'unauthorized', reason: 'missing_root', root };
1374
+ }
1375
+ if (typeof root.exp !== 'number' || root.exp <= nowMs) {
1376
+ return {
1377
+ status: 'unauthorized',
1378
+ reason: 'expired',
1379
+ root,
1380
+ expiresAt: root.exp,
1381
+ };
1382
+ }
1383
+ if (typeof root.nbf === 'number' && root.nbf > nowMs) {
1384
+ return {
1385
+ status: 'unauthorized',
1386
+ reason: 'not_before',
1387
+ root,
1388
+ expiresAt: root.exp,
1389
+ };
1390
+ }
1391
+ const accountFromIssuer = parseUcanAccountFromIssuer(root.iss);
1392
+ if (!accountFromIssuer) {
1393
+ return {
1394
+ status: 'unauthorized',
1395
+ reason: 'invalid_issuer',
1396
+ root,
1397
+ expiresAt: root.exp,
1398
+ actual: root.iss,
1399
+ };
1400
+ }
1401
+ const currentAccount = normalizeEthAccount(options.currentAccount);
1402
+ if (!currentAccount && !options.recoverAccountFromRoot) {
1403
+ return {
1404
+ status: 'unauthorized',
1405
+ reason: 'missing_account',
1406
+ root,
1407
+ account: null,
1408
+ expiresAt: root.exp,
1409
+ };
1410
+ }
1411
+ const account = currentAccount || accountFromIssuer;
1412
+ const expectedIssuer = getUcanIssuerForAccount(account);
1413
+ if (root.iss !== expectedIssuer) {
1414
+ return {
1415
+ status: 'unauthorized',
1416
+ reason: 'issuer_mismatch',
1417
+ root,
1418
+ account,
1419
+ expiresAt: root.exp,
1420
+ expected: expectedIssuer,
1421
+ actual: root.iss,
1422
+ };
1423
+ }
1424
+ if (options.expectedCapabilities &&
1425
+ !capsEqual(root.cap, options.expectedCapabilities)) {
1426
+ return {
1427
+ status: 'unauthorized',
1428
+ reason: 'capability_mismatch',
1429
+ root,
1430
+ account,
1431
+ expiresAt: root.exp,
1432
+ };
1433
+ }
1434
+ const expectedAudience = String(options.expectedAudience || '').trim();
1435
+ if (expectedAudience && root.aud !== expectedAudience) {
1436
+ return {
1437
+ status: 'unauthorized',
1438
+ reason: 'audience_mismatch',
1439
+ root,
1440
+ account,
1441
+ expiresAt: root.exp,
1442
+ expected: expectedAudience,
1443
+ actual: root.aud,
1444
+ };
1445
+ }
1446
+ const serviceHostMismatch = getServiceHostMismatch(root, options.expectedServiceHosts);
1447
+ if (serviceHostMismatch) {
1448
+ return {
1449
+ status: 'unauthorized',
1450
+ reason: 'service_host_mismatch',
1451
+ root,
1452
+ account,
1453
+ expiresAt: root.exp,
1454
+ expected: serviceHostMismatch.expected,
1455
+ actual: serviceHostMismatch.actual,
1456
+ };
1457
+ }
1458
+ return {
1459
+ status: 'authorized',
1460
+ account,
1461
+ root,
1462
+ restoredAccount: !currentAccount && account === accountFromIssuer,
1463
+ expiresAt: root.exp,
1464
+ };
1465
+ }
1300
1466
  async function getOrCreateUcanRoot(options) {
1301
1467
  const provider = options.provider || (await requireProvider());
1302
1468
  const session = options.session || (await createUcanSession({ id: options.sessionId, provider }));
@@ -1876,7 +2042,8 @@
1876
2042
  * 调用钱包插件的 `yeying_encrypt` / `yeying_decrypt` / `yeying_getCipherSuites`
1877
2043
  * EIP-1193 自定义方法。命名安全套件 + 静默执行 + 站点授权模型同 UCAN。
1878
2044
  *
1879
- * 数据密码(password 参数)由 DApp 自行管理与钱包密码独立;
2045
+ * 默认数据密码(password 参数)由 DApp 自行管理与钱包密码独立;
2046
+ * 也可通过 passwordSource 请求钱包插件在钱包内部派生加密密码。
1880
2047
  * plaintext 走 base64 字符串跨 message 边界传输。
1881
2048
  */
1882
2049
  class CipherError extends Error {
@@ -1927,6 +2094,8 @@
1927
2094
  params: [{
1928
2095
  data: options.data,
1929
2096
  password: options.password,
2097
+ passwordSource: options.passwordSource,
2098
+ passwordContext: options.passwordContext,
1930
2099
  suite: options.suite
1931
2100
  }]
1932
2101
  });
@@ -1950,7 +2119,9 @@
1950
2119
  method: 'yeying_decrypt',
1951
2120
  params: [{
1952
2121
  ciphertext: options.ciphertext,
1953
- password: options.password
2122
+ password: options.password,
2123
+ passwordSource: options.passwordSource,
2124
+ passwordContext: options.passwordContext
1954
2125
  }]
1955
2126
  });
1956
2127
  if (!result || typeof result !== 'object' || typeof result.plaintext !== 'string') {
@@ -2592,9 +2763,11 @@
2592
2763
  exports.normalizeUcanExpiry = normalizeUcanExpiry;
2593
2764
  exports.onAccountsChanged = onAccountsChanged;
2594
2765
  exports.onChainChanged = onChainChanged;
2766
+ exports.parseUcanAccountFromIssuer = parseUcanAccountFromIssuer;
2595
2767
  exports.refreshAccessToken = refreshAccessToken;
2596
2768
  exports.requestAccounts = requestAccounts;
2597
2769
  exports.requireProvider = requireProvider;
2770
+ exports.resolveUcanAuthorization = resolveUcanAuthorization;
2598
2771
  exports.resolveWalletAccount = resolveWalletAccount;
2599
2772
  exports.setAccessToken = setAccessToken;
2600
2773
  exports.setCentralSessionToken = setCentralSessionToken;