@yeying-community/web3-bs 1.0.14 → 1.0.15
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/dist/auth/ucan.d.ts +28 -0
- package/dist/web3-bs.esm.js +167 -1
- package/dist/web3-bs.esm.js.map +1 -1
- package/dist/web3-bs.umd.js +168 -0
- package/dist/web3-bs.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/web3-bs.umd.js
CHANGED
|
@@ -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 }));
|
|
@@ -2592,9 +2758,11 @@
|
|
|
2592
2758
|
exports.normalizeUcanExpiry = normalizeUcanExpiry;
|
|
2593
2759
|
exports.onAccountsChanged = onAccountsChanged;
|
|
2594
2760
|
exports.onChainChanged = onChainChanged;
|
|
2761
|
+
exports.parseUcanAccountFromIssuer = parseUcanAccountFromIssuer;
|
|
2595
2762
|
exports.refreshAccessToken = refreshAccessToken;
|
|
2596
2763
|
exports.requestAccounts = requestAccounts;
|
|
2597
2764
|
exports.requireProvider = requireProvider;
|
|
2765
|
+
exports.resolveUcanAuthorization = resolveUcanAuthorization;
|
|
2598
2766
|
exports.resolveWalletAccount = resolveWalletAccount;
|
|
2599
2767
|
exports.setAccessToken = setAccessToken;
|
|
2600
2768
|
exports.setCentralSessionToken = setCentralSessionToken;
|