@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/auth/ucan.d.ts
CHANGED
|
@@ -120,6 +120,32 @@ export type UcanAuthErrorInfo = {
|
|
|
120
120
|
status?: number;
|
|
121
121
|
code?: string | number;
|
|
122
122
|
};
|
|
123
|
+
export type ResolveUcanAuthorizationReason = 'missing_root' | 'expired' | 'not_before' | 'missing_account' | 'invalid_issuer' | 'issuer_mismatch' | 'capability_mismatch' | 'audience_mismatch' | 'service_host_mismatch';
|
|
124
|
+
export type ResolveUcanAuthorizationOptions = {
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
root?: UcanRootProof | null;
|
|
127
|
+
currentAccount?: string | null;
|
|
128
|
+
expectedCapabilities?: UcanCapability[];
|
|
129
|
+
expectedAudience?: string | null;
|
|
130
|
+
expectedServiceHosts?: Record<string, string | null | undefined>;
|
|
131
|
+
recoverAccountFromRoot?: boolean;
|
|
132
|
+
nowMs?: number;
|
|
133
|
+
};
|
|
134
|
+
export type ResolveUcanAuthorizationResult = {
|
|
135
|
+
status: 'authorized';
|
|
136
|
+
account: string;
|
|
137
|
+
root: UcanRootProof;
|
|
138
|
+
restoredAccount: boolean;
|
|
139
|
+
expiresAt: number;
|
|
140
|
+
} | {
|
|
141
|
+
status: 'unauthorized';
|
|
142
|
+
reason: ResolveUcanAuthorizationReason;
|
|
143
|
+
root?: UcanRootProof | null;
|
|
144
|
+
account?: string | null;
|
|
145
|
+
expiresAt?: number;
|
|
146
|
+
expected?: string;
|
|
147
|
+
actual?: string;
|
|
148
|
+
};
|
|
123
149
|
export declare const DEFAULT_UCAN_SESSION_TTL_MS: number;
|
|
124
150
|
export declare const DEFAULT_UCAN_TOKEN_TTL_MS: number;
|
|
125
151
|
export declare const DEFAULT_UCAN_TOKEN_SKEW_MS: number;
|
|
@@ -132,6 +158,7 @@ export declare function normalizeUcanCapabilities(caps: UcanCapability[] | undef
|
|
|
132
158
|
includeLegacyAliases?: boolean;
|
|
133
159
|
}): UcanCapability[];
|
|
134
160
|
export declare function normalizeUcanExpiry(exp: number | undefined, fallbackMs: number): number;
|
|
161
|
+
export declare function parseUcanAccountFromIssuer(issuer?: string | null): string | null;
|
|
135
162
|
export declare function decodeUcanPayload(token: string): UcanTokenPayload | null;
|
|
136
163
|
export declare function getUcanTokenTiming(token: string, options?: {
|
|
137
164
|
nowMs?: number;
|
|
@@ -145,6 +172,7 @@ export declare function createUcanSession(options?: CreateUcanSessionOptions): P
|
|
|
145
172
|
export declare function clearUcanSession(id?: string): Promise<void>;
|
|
146
173
|
export declare function storeUcanRoot(root: UcanRootProof, id?: string): Promise<void>;
|
|
147
174
|
export declare function getStoredUcanRoot(id?: string): Promise<UcanRootProof | null>;
|
|
175
|
+
export declare function resolveUcanAuthorization(options?: ResolveUcanAuthorizationOptions): Promise<ResolveUcanAuthorizationResult>;
|
|
148
176
|
export declare function getOrCreateUcanRoot(options: CreateRootUcanOptions): Promise<UcanRootProof>;
|
|
149
177
|
export declare function createRootUcan(options: CreateRootUcanOptions): Promise<UcanRootProof>;
|
|
150
178
|
export declare function createDelegationUcan(options: CreateUcanTokenOptions): Promise<string>;
|
package/dist/web3-bs.esm.js
CHANGED
|
@@ -864,6 +864,73 @@ function normalizeExpiry(exp, fallbackMs) {
|
|
|
864
864
|
function normalizeUcanExpiry(exp, fallbackMs) {
|
|
865
865
|
return normalizeExpiry(exp, fallbackMs);
|
|
866
866
|
}
|
|
867
|
+
function normalizeEthAccount(account) {
|
|
868
|
+
return String(account || '').trim().toLowerCase();
|
|
869
|
+
}
|
|
870
|
+
function parseUcanAccountFromIssuer(issuer) {
|
|
871
|
+
const normalized = String(issuer || '').trim().toLowerCase();
|
|
872
|
+
const prefix = 'did:pkh:eth:';
|
|
873
|
+
if (!normalized.startsWith(prefix))
|
|
874
|
+
return null;
|
|
875
|
+
const account = normalized.slice(prefix.length);
|
|
876
|
+
return account || null;
|
|
877
|
+
}
|
|
878
|
+
function getUcanIssuerForAccount(account) {
|
|
879
|
+
return `did:pkh:eth:${normalizeEthAccount(account)}`;
|
|
880
|
+
}
|
|
881
|
+
function extractUcanStatementPayload(message) {
|
|
882
|
+
if (!message || typeof message !== 'string')
|
|
883
|
+
return null;
|
|
884
|
+
const marker = 'UCAN-AUTH';
|
|
885
|
+
const index = message.indexOf(marker);
|
|
886
|
+
if (index < 0)
|
|
887
|
+
return null;
|
|
888
|
+
const jsonStart = message.indexOf('{', index + marker.length);
|
|
889
|
+
const jsonEnd = message.lastIndexOf('}');
|
|
890
|
+
if (jsonStart < 0 || jsonEnd < jsonStart)
|
|
891
|
+
return null;
|
|
892
|
+
try {
|
|
893
|
+
const parsed = JSON.parse(message.slice(jsonStart, jsonEnd + 1));
|
|
894
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
return parsed;
|
|
898
|
+
}
|
|
899
|
+
catch {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function getUcanRootServiceHosts(root) {
|
|
904
|
+
const payload = extractUcanStatementPayload(root.siwe?.message);
|
|
905
|
+
const hosts = payload?.service_hosts;
|
|
906
|
+
if (!hosts || typeof hosts !== 'object' || Array.isArray(hosts)) {
|
|
907
|
+
return null;
|
|
908
|
+
}
|
|
909
|
+
return hosts;
|
|
910
|
+
}
|
|
911
|
+
function getServiceHostMismatch(root, expectedServiceHosts) {
|
|
912
|
+
if (!expectedServiceHosts)
|
|
913
|
+
return null;
|
|
914
|
+
const entries = Object.entries(expectedServiceHosts)
|
|
915
|
+
.map(([key, value]) => [key, String(value || '').trim()])
|
|
916
|
+
.filter(([, value]) => Boolean(value));
|
|
917
|
+
if (!entries.length)
|
|
918
|
+
return null;
|
|
919
|
+
const hosts = getUcanRootServiceHosts(root);
|
|
920
|
+
if (!hosts) {
|
|
921
|
+
return {
|
|
922
|
+
expected: entries.map(([key, value]) => `${key}:${value}`).join('|'),
|
|
923
|
+
actual: '',
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
for (const [key, expected] of entries) {
|
|
927
|
+
const actual = typeof hosts[key] === 'string' ? hosts[key].trim() : '';
|
|
928
|
+
if (actual !== expected) {
|
|
929
|
+
return { expected, actual };
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
867
934
|
function decodeUcanPayload(token) {
|
|
868
935
|
const parts = String(token || '').split('.');
|
|
869
936
|
if (parts.length < 2)
|
|
@@ -1291,6 +1358,105 @@ function capsEqual(a, b) {
|
|
|
1291
1358
|
function isRootExpired(root, nowMs) {
|
|
1292
1359
|
return Boolean(root.exp && nowMs > root.exp);
|
|
1293
1360
|
}
|
|
1361
|
+
async function resolveUcanAuthorization(options = {}) {
|
|
1362
|
+
const root = options.root === undefined
|
|
1363
|
+
? await getStoredUcanRoot(options.sessionId || DEFAULT_SESSION_ID)
|
|
1364
|
+
: options.root;
|
|
1365
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
1366
|
+
if (!root) {
|
|
1367
|
+
return { status: 'unauthorized', reason: 'missing_root', root };
|
|
1368
|
+
}
|
|
1369
|
+
if (typeof root.exp !== 'number' || root.exp <= nowMs) {
|
|
1370
|
+
return {
|
|
1371
|
+
status: 'unauthorized',
|
|
1372
|
+
reason: 'expired',
|
|
1373
|
+
root,
|
|
1374
|
+
expiresAt: root.exp,
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
if (typeof root.nbf === 'number' && root.nbf > nowMs) {
|
|
1378
|
+
return {
|
|
1379
|
+
status: 'unauthorized',
|
|
1380
|
+
reason: 'not_before',
|
|
1381
|
+
root,
|
|
1382
|
+
expiresAt: root.exp,
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
const accountFromIssuer = parseUcanAccountFromIssuer(root.iss);
|
|
1386
|
+
if (!accountFromIssuer) {
|
|
1387
|
+
return {
|
|
1388
|
+
status: 'unauthorized',
|
|
1389
|
+
reason: 'invalid_issuer',
|
|
1390
|
+
root,
|
|
1391
|
+
expiresAt: root.exp,
|
|
1392
|
+
actual: root.iss,
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
const currentAccount = normalizeEthAccount(options.currentAccount);
|
|
1396
|
+
if (!currentAccount && !options.recoverAccountFromRoot) {
|
|
1397
|
+
return {
|
|
1398
|
+
status: 'unauthorized',
|
|
1399
|
+
reason: 'missing_account',
|
|
1400
|
+
root,
|
|
1401
|
+
account: null,
|
|
1402
|
+
expiresAt: root.exp,
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
const account = currentAccount || accountFromIssuer;
|
|
1406
|
+
const expectedIssuer = getUcanIssuerForAccount(account);
|
|
1407
|
+
if (root.iss !== expectedIssuer) {
|
|
1408
|
+
return {
|
|
1409
|
+
status: 'unauthorized',
|
|
1410
|
+
reason: 'issuer_mismatch',
|
|
1411
|
+
root,
|
|
1412
|
+
account,
|
|
1413
|
+
expiresAt: root.exp,
|
|
1414
|
+
expected: expectedIssuer,
|
|
1415
|
+
actual: root.iss,
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
if (options.expectedCapabilities &&
|
|
1419
|
+
!capsEqual(root.cap, options.expectedCapabilities)) {
|
|
1420
|
+
return {
|
|
1421
|
+
status: 'unauthorized',
|
|
1422
|
+
reason: 'capability_mismatch',
|
|
1423
|
+
root,
|
|
1424
|
+
account,
|
|
1425
|
+
expiresAt: root.exp,
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
const expectedAudience = String(options.expectedAudience || '').trim();
|
|
1429
|
+
if (expectedAudience && root.aud !== expectedAudience) {
|
|
1430
|
+
return {
|
|
1431
|
+
status: 'unauthorized',
|
|
1432
|
+
reason: 'audience_mismatch',
|
|
1433
|
+
root,
|
|
1434
|
+
account,
|
|
1435
|
+
expiresAt: root.exp,
|
|
1436
|
+
expected: expectedAudience,
|
|
1437
|
+
actual: root.aud,
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
const serviceHostMismatch = getServiceHostMismatch(root, options.expectedServiceHosts);
|
|
1441
|
+
if (serviceHostMismatch) {
|
|
1442
|
+
return {
|
|
1443
|
+
status: 'unauthorized',
|
|
1444
|
+
reason: 'service_host_mismatch',
|
|
1445
|
+
root,
|
|
1446
|
+
account,
|
|
1447
|
+
expiresAt: root.exp,
|
|
1448
|
+
expected: serviceHostMismatch.expected,
|
|
1449
|
+
actual: serviceHostMismatch.actual,
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
return {
|
|
1453
|
+
status: 'authorized',
|
|
1454
|
+
account,
|
|
1455
|
+
root,
|
|
1456
|
+
restoredAccount: !currentAccount && account === accountFromIssuer,
|
|
1457
|
+
expiresAt: root.exp,
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1294
1460
|
async function getOrCreateUcanRoot(options) {
|
|
1295
1461
|
const provider = options.provider || (await requireProvider());
|
|
1296
1462
|
const session = options.session || (await createUcanSession({ id: options.sessionId, provider }));
|
|
@@ -2525,5 +2691,5 @@ async function initDappSession(options) {
|
|
|
2525
2691
|
return result;
|
|
2526
2692
|
}
|
|
2527
2693
|
|
|
2528
|
-
export { CipherError, DEFAULT_UCAN_SESSION_TTL_MS, DEFAULT_UCAN_TOKEN_SKEW_MS, DEFAULT_UCAN_TOKEN_TTL_MS, WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, base64ToBytes, bytesToBase64, classifyUcanAuthError, classifyWalletError, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, decodeUcanPayload, decrypt, deriveAppIdFromHost, deriveAppIdFromLocation, encrypt, focusPendingApproval, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateInvocationUcan, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getSupportedCipherSuites, getUcanSession, getUcanTokenTiming, getWalletErrorCode, getWalletErrorMessage, initDappSession, initWebDavStorage, isUcanTokenFresh, isUserRejectedWalletAction, isWalletReconnectError, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeAppHostnameForAppId, normalizeUcanCapabilities, normalizeUcanCapability, normalizeUcanExpiry, onAccountsChanged, onChainChanged, refreshAccessToken, requestAccounts, requireProvider, resolveWalletAccount, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts, watchProvider };
|
|
2694
|
+
export { CipherError, DEFAULT_UCAN_SESSION_TTL_MS, DEFAULT_UCAN_TOKEN_SKEW_MS, DEFAULT_UCAN_TOKEN_TTL_MS, WebDavClient, authCentralUcanFetch, authFetch, authUcanFetch, base64ToBytes, bytesToBase64, classifyUcanAuthError, classifyWalletError, clearAccessToken, clearCentralSessionToken, clearUcanSession, createAndIssueCentralUcan, createCentralSession, createDelegationUcan, createInvocationUcan, createRootUcan, createUcanSession, createWebDavClient, decodeUcanPayload, decrypt, deriveAppIdFromHost, deriveAppIdFromLocation, encrypt, focusPendingApproval, getAccessToken, getAccounts, getBalance, getCapabilityAction, getCapabilityResource, getCentralIssuerInfo, getCentralSessionToken, getChainId, getOrCreateInvocationUcan, getOrCreateUcanRoot, getPreferredAccount, getProvider, getStoredUcanRoot, getSupportedCipherSuites, getUcanSession, getUcanTokenTiming, getWalletErrorCode, getWalletErrorMessage, initDappSession, initWebDavStorage, isUcanTokenFresh, isUserRejectedWalletAction, isWalletReconnectError, isYeYingProvider, issueCentralUcan, loginWithChallenge, logout, normalizeAppHostnameForAppId, normalizeUcanCapabilities, normalizeUcanCapability, normalizeUcanExpiry, onAccountsChanged, onChainChanged, parseUcanAccountFromIssuer, refreshAccessToken, requestAccounts, requireProvider, resolveUcanAuthorization, resolveWalletAccount, setAccessToken, setCentralSessionToken, signMessage, storeUcanRoot, watchAccounts, watchProvider };
|
|
2529
2695
|
//# sourceMappingURL=web3-bs.esm.js.map
|