@yeying-community/web3-bs 1.0.5 → 1.0.7
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/README.md +113 -77
- package/dist/auth/central.d.ts +77 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/ucan.d.ts +18 -2
- package/dist/dapp.d.ts +8 -0
- package/dist/web3-bs.esm.js +633 -46
- package/dist/web3-bs.esm.js.map +1 -1
- package/dist/web3-bs.umd.js +647 -45
- package/dist/web3-bs.umd.js.map +1 -1
- package/package.json +5 -3
package/dist/web3-bs.umd.js
CHANGED
|
@@ -199,12 +199,12 @@
|
|
|
199
199
|
return () => provider.removeListener?.('chainChanged', handler);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
function normalizeBaseUrl$
|
|
202
|
+
function normalizeBaseUrl$2(baseUrl) {
|
|
203
203
|
return baseUrl.replace(/\/+$/, '');
|
|
204
204
|
}
|
|
205
|
-
function joinUrl$
|
|
205
|
+
function joinUrl$2(baseUrl, path) {
|
|
206
206
|
const trimmed = path.replace(/^\/+/, '');
|
|
207
|
-
return `${normalizeBaseUrl$
|
|
207
|
+
return `${normalizeBaseUrl$2(baseUrl)}/${trimmed}`;
|
|
208
208
|
}
|
|
209
209
|
const DEFAULT_TOKEN_KEY = 'authToken';
|
|
210
210
|
let cachedAccessToken = null;
|
|
@@ -215,10 +215,10 @@
|
|
|
215
215
|
function shouldStoreToken(options) {
|
|
216
216
|
return options?.storeToken !== false;
|
|
217
217
|
}
|
|
218
|
-
function resolveFetcher(options) {
|
|
218
|
+
function resolveFetcher$1(options) {
|
|
219
219
|
return options?.fetcher || fetch;
|
|
220
220
|
}
|
|
221
|
-
function resolveCredentials(options) {
|
|
221
|
+
function resolveCredentials$1(options) {
|
|
222
222
|
return options?.credentials ?? 'include';
|
|
223
223
|
}
|
|
224
224
|
function readStoredToken(options) {
|
|
@@ -358,11 +358,11 @@
|
|
|
358
358
|
async function loginWithChallenge(options = {}) {
|
|
359
359
|
const provider = options.provider || (await requireProvider());
|
|
360
360
|
const address = await resolveAddress$1(provider, options.address);
|
|
361
|
-
const fetcher = resolveFetcher(options);
|
|
362
|
-
const credentials = resolveCredentials(options);
|
|
361
|
+
const fetcher = resolveFetcher$1(options);
|
|
362
|
+
const credentials = resolveCredentials$1(options);
|
|
363
363
|
const baseUrl = options.baseUrl || '/api/v1/public/auth';
|
|
364
|
-
const challengeUrl = joinUrl$
|
|
365
|
-
const verifyUrl = joinUrl$
|
|
364
|
+
const challengeUrl = joinUrl$2(baseUrl, options.challengePath || 'challenge');
|
|
365
|
+
const verifyUrl = joinUrl$2(baseUrl, options.verifyPath || 'verify');
|
|
366
366
|
const challengeBody = {
|
|
367
367
|
address,
|
|
368
368
|
};
|
|
@@ -426,10 +426,10 @@
|
|
|
426
426
|
return refreshInFlight;
|
|
427
427
|
}
|
|
428
428
|
const task = (async () => {
|
|
429
|
-
const fetcher = resolveFetcher(options);
|
|
430
|
-
const credentials = resolveCredentials(options);
|
|
429
|
+
const fetcher = resolveFetcher$1(options);
|
|
430
|
+
const credentials = resolveCredentials$1(options);
|
|
431
431
|
const baseUrl = options.baseUrl || '/api/v1/public/auth';
|
|
432
|
-
const refreshUrl = joinUrl$
|
|
432
|
+
const refreshUrl = joinUrl$2(baseUrl, options.refreshPath || 'refresh');
|
|
433
433
|
const refreshRes = await fetcher(refreshUrl, {
|
|
434
434
|
method: 'POST',
|
|
435
435
|
headers: {
|
|
@@ -458,10 +458,10 @@
|
|
|
458
458
|
}
|
|
459
459
|
}
|
|
460
460
|
async function logout(options = {}) {
|
|
461
|
-
const fetcher = resolveFetcher(options);
|
|
462
|
-
const credentials = resolveCredentials(options);
|
|
461
|
+
const fetcher = resolveFetcher$1(options);
|
|
462
|
+
const credentials = resolveCredentials$1(options);
|
|
463
463
|
const baseUrl = options.baseUrl || '/api/v1/public/auth';
|
|
464
|
-
const logoutUrl = joinUrl$
|
|
464
|
+
const logoutUrl = joinUrl$2(baseUrl, options.logoutPath || 'logout');
|
|
465
465
|
const logoutRes = await fetcher(logoutUrl, {
|
|
466
466
|
method: 'POST',
|
|
467
467
|
headers: {
|
|
@@ -484,8 +484,8 @@
|
|
|
484
484
|
return { response: payload };
|
|
485
485
|
}
|
|
486
486
|
async function authFetch(input, init = {}, options = {}) {
|
|
487
|
-
const fetcher = resolveFetcher(options);
|
|
488
|
-
const credentials = resolveCredentials(options);
|
|
487
|
+
const fetcher = resolveFetcher$1(options);
|
|
488
|
+
const credentials = resolveCredentials$1(options);
|
|
489
489
|
const retryOnUnauthorized = options.retryOnUnauthorized !== false;
|
|
490
490
|
const performRequest = async (tokenOverride) => {
|
|
491
491
|
const headers = new Headers(init.headers || {});
|
|
@@ -517,6 +517,8 @@
|
|
|
517
517
|
const DEFAULT_UCAN_TTL = 5 * 60 * 1000;
|
|
518
518
|
const DB_NAME = 'yeying-web3';
|
|
519
519
|
const DB_STORE = 'ucan-sessions';
|
|
520
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
521
|
+
const DID_KEY_ED25519_MULTICODEC = new Uint8Array([0xed, 0x01]);
|
|
520
522
|
const textEncoder = new TextEncoder();
|
|
521
523
|
function toBase64Url(data) {
|
|
522
524
|
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -526,6 +528,70 @@
|
|
|
526
528
|
}
|
|
527
529
|
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
528
530
|
}
|
|
531
|
+
function normalizeActionExpression(raw) {
|
|
532
|
+
const normalized = String(raw || '').trim().toLowerCase().replace(/\|/g, ',');
|
|
533
|
+
if (!normalized)
|
|
534
|
+
return '';
|
|
535
|
+
const parts = normalized
|
|
536
|
+
.split(',')
|
|
537
|
+
.map(part => part.trim())
|
|
538
|
+
.filter(Boolean);
|
|
539
|
+
if (!parts.length)
|
|
540
|
+
return '';
|
|
541
|
+
return Array.from(new Set(parts)).join(',');
|
|
542
|
+
}
|
|
543
|
+
function getCapabilityResource(cap) {
|
|
544
|
+
if (!cap || typeof cap !== 'object')
|
|
545
|
+
return '';
|
|
546
|
+
const withValue = typeof cap.with === 'string' ? cap.with.trim() : '';
|
|
547
|
+
if (withValue)
|
|
548
|
+
return withValue;
|
|
549
|
+
return typeof cap.resource === 'string' ? cap.resource.trim() : '';
|
|
550
|
+
}
|
|
551
|
+
function getCapabilityAction(cap) {
|
|
552
|
+
if (!cap || typeof cap !== 'object')
|
|
553
|
+
return '';
|
|
554
|
+
const canValue = typeof cap.can === 'string' ? cap.can.trim() : '';
|
|
555
|
+
if (canValue)
|
|
556
|
+
return normalizeActionExpression(canValue);
|
|
557
|
+
const actionValue = typeof cap.action === 'string' ? cap.action.trim() : '';
|
|
558
|
+
return normalizeActionExpression(actionValue);
|
|
559
|
+
}
|
|
560
|
+
function normalizeUcanCapability(cap, options = {}) {
|
|
561
|
+
const includeLegacyAliases = options.includeLegacyAliases !== false;
|
|
562
|
+
const resource = getCapabilityResource(cap);
|
|
563
|
+
const action = getCapabilityAction(cap);
|
|
564
|
+
if (!resource || !action)
|
|
565
|
+
return null;
|
|
566
|
+
const normalized = {
|
|
567
|
+
with: resource,
|
|
568
|
+
can: action,
|
|
569
|
+
};
|
|
570
|
+
if (includeLegacyAliases) {
|
|
571
|
+
normalized.resource = resource;
|
|
572
|
+
normalized.action = action;
|
|
573
|
+
}
|
|
574
|
+
if (cap && Object.prototype.hasOwnProperty.call(cap, 'nb')) {
|
|
575
|
+
normalized.nb = cap.nb;
|
|
576
|
+
}
|
|
577
|
+
return normalized;
|
|
578
|
+
}
|
|
579
|
+
function normalizeUcanCapabilities(caps, options = {}) {
|
|
580
|
+
const includeLegacyAliases = options.includeLegacyAliases !== false;
|
|
581
|
+
const seen = new Set();
|
|
582
|
+
const result = [];
|
|
583
|
+
for (const cap of caps || []) {
|
|
584
|
+
const normalized = normalizeUcanCapability(cap, { includeLegacyAliases });
|
|
585
|
+
if (!normalized)
|
|
586
|
+
continue;
|
|
587
|
+
const key = `${normalized.with}|${normalized.can}`;
|
|
588
|
+
if (seen.has(key))
|
|
589
|
+
continue;
|
|
590
|
+
seen.add(key);
|
|
591
|
+
result.push(normalized);
|
|
592
|
+
}
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
529
595
|
function encodeJson(value) {
|
|
530
596
|
return toBase64Url(textEncoder.encode(JSON.stringify(value)));
|
|
531
597
|
}
|
|
@@ -539,6 +605,123 @@
|
|
|
539
605
|
function normalizeExpiry(exp, fallbackMs) {
|
|
540
606
|
return Date.now() + fallbackMs;
|
|
541
607
|
}
|
|
608
|
+
function isSessionExpired(expiresAt, nowMs = Date.now()) {
|
|
609
|
+
return typeof expiresAt === 'number' && nowMs >= expiresAt;
|
|
610
|
+
}
|
|
611
|
+
function encodeBase58(bytes) {
|
|
612
|
+
if (bytes.length === 0)
|
|
613
|
+
return '';
|
|
614
|
+
let value = 0n;
|
|
615
|
+
for (const byte of bytes) {
|
|
616
|
+
value = (value << 8n) + BigInt(byte);
|
|
617
|
+
}
|
|
618
|
+
let encoded = '';
|
|
619
|
+
while (value > 0n) {
|
|
620
|
+
const mod = Number(value % 58n);
|
|
621
|
+
encoded = `${BASE58_ALPHABET[mod]}${encoded}`;
|
|
622
|
+
value /= 58n;
|
|
623
|
+
}
|
|
624
|
+
let leadingZeroCount = 0;
|
|
625
|
+
while (leadingZeroCount < bytes.length && bytes[leadingZeroCount] === 0) {
|
|
626
|
+
leadingZeroCount += 1;
|
|
627
|
+
}
|
|
628
|
+
if (leadingZeroCount > 0) {
|
|
629
|
+
encoded = `${'1'.repeat(leadingZeroCount)}${encoded}`;
|
|
630
|
+
}
|
|
631
|
+
return encoded || '1';
|
|
632
|
+
}
|
|
633
|
+
function ensureWebCrypto() {
|
|
634
|
+
if (typeof crypto === 'undefined' || !crypto.subtle) {
|
|
635
|
+
throw new Error('WebCrypto not available for UCAN session');
|
|
636
|
+
}
|
|
637
|
+
return crypto;
|
|
638
|
+
}
|
|
639
|
+
function parseSessionId(options) {
|
|
640
|
+
return options.id || DEFAULT_SESSION_ID;
|
|
641
|
+
}
|
|
642
|
+
function isLocalSessionRecord(record) {
|
|
643
|
+
return Boolean(record?.source === 'local' || record?.privateKeyJwk);
|
|
644
|
+
}
|
|
645
|
+
async function buildDidKey(publicKey) {
|
|
646
|
+
const webCrypto = ensureWebCrypto();
|
|
647
|
+
const raw = new Uint8Array(await webCrypto.subtle.exportKey('raw', publicKey));
|
|
648
|
+
const prefixed = new Uint8Array(DID_KEY_ED25519_MULTICODEC.length + raw.length);
|
|
649
|
+
prefixed.set(DID_KEY_ED25519_MULTICODEC, 0);
|
|
650
|
+
prefixed.set(raw, DID_KEY_ED25519_MULTICODEC.length);
|
|
651
|
+
return `did:key:z${encodeBase58(prefixed)}`;
|
|
652
|
+
}
|
|
653
|
+
async function importLocalPrivateKey(privateKeyJwk) {
|
|
654
|
+
const webCrypto = ensureWebCrypto();
|
|
655
|
+
return await webCrypto.subtle.importKey('jwk', privateKeyJwk, 'Ed25519', true, ['sign']);
|
|
656
|
+
}
|
|
657
|
+
async function loadLocalSessionFromRecord(id, record) {
|
|
658
|
+
if (!record || !isLocalSessionRecord(record) || !record.privateKeyJwk) {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
if (isSessionExpired(record.expiresAt)) {
|
|
662
|
+
await deleteSessionRecord(id);
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
try {
|
|
666
|
+
const privateKey = await importLocalPrivateKey(record.privateKeyJwk);
|
|
667
|
+
return {
|
|
668
|
+
id: record.id || id,
|
|
669
|
+
did: record.did,
|
|
670
|
+
createdAt: record.createdAt,
|
|
671
|
+
expiresAt: record.expiresAt,
|
|
672
|
+
source: 'local',
|
|
673
|
+
privateKey,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
catch {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function shouldKeepRootForSession(root, did, nowMs) {
|
|
681
|
+
if (!root)
|
|
682
|
+
return false;
|
|
683
|
+
if (root.aud && root.aud !== did)
|
|
684
|
+
return false;
|
|
685
|
+
if (isRootExpired(root, nowMs))
|
|
686
|
+
return false;
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
async function createLocalSession(options, record) {
|
|
690
|
+
const webCrypto = ensureWebCrypto();
|
|
691
|
+
const sessionId = parseSessionId(options);
|
|
692
|
+
if (!options.forceNew) {
|
|
693
|
+
const existing = await loadLocalSessionFromRecord(sessionId, record);
|
|
694
|
+
if (existing)
|
|
695
|
+
return existing;
|
|
696
|
+
}
|
|
697
|
+
const pair = (await webCrypto.subtle.generateKey('Ed25519', true, ['sign', 'verify']));
|
|
698
|
+
const [privateKeyJwk, publicKeyJwk, did] = await Promise.all([
|
|
699
|
+
webCrypto.subtle.exportKey('jwk', pair.privateKey),
|
|
700
|
+
webCrypto.subtle.exportKey('jwk', pair.publicKey),
|
|
701
|
+
buildDidKey(pair.publicKey),
|
|
702
|
+
]);
|
|
703
|
+
const createdAt = Date.now();
|
|
704
|
+
const expiresAt = normalizeExpiry(undefined, options.expiresInMs ?? DEFAULT_SESSION_TTL);
|
|
705
|
+
const root = shouldKeepRootForSession(record?.root, did, createdAt) ? record?.root : undefined;
|
|
706
|
+
await writeSessionRecord({
|
|
707
|
+
id: sessionId,
|
|
708
|
+
did,
|
|
709
|
+
createdAt,
|
|
710
|
+
expiresAt,
|
|
711
|
+
source: 'local',
|
|
712
|
+
privateKeyJwk,
|
|
713
|
+
publicKeyJwk,
|
|
714
|
+
root,
|
|
715
|
+
});
|
|
716
|
+
return {
|
|
717
|
+
id: sessionId,
|
|
718
|
+
did,
|
|
719
|
+
createdAt,
|
|
720
|
+
expiresAt,
|
|
721
|
+
source: 'local',
|
|
722
|
+
privateKey: pair.privateKey,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
542
725
|
function openDb() {
|
|
543
726
|
if (typeof indexedDB === 'undefined') {
|
|
544
727
|
return Promise.reject(new Error('IndexedDB not available'));
|
|
@@ -601,17 +784,19 @@
|
|
|
601
784
|
}
|
|
602
785
|
}
|
|
603
786
|
async function getUcanSession(id = DEFAULT_SESSION_ID, provider) {
|
|
787
|
+
const record = await readSessionRecord(id);
|
|
604
788
|
const walletProvider = provider || (typeof window !== 'undefined'
|
|
605
789
|
? await getProvider({ preferYeYing: true })
|
|
606
790
|
: null);
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
791
|
+
if (walletProvider) {
|
|
792
|
+
try {
|
|
793
|
+
return await requestWalletUcanSession(walletProvider, { id });
|
|
794
|
+
}
|
|
795
|
+
catch {
|
|
796
|
+
return await loadLocalSessionFromRecord(id, record);
|
|
797
|
+
}
|
|
614
798
|
}
|
|
799
|
+
return await loadLocalSessionFromRecord(id, record);
|
|
615
800
|
}
|
|
616
801
|
async function requestWalletUcanSession(provider, options) {
|
|
617
802
|
const sessionId = options.id || DEFAULT_SESSION_ID;
|
|
@@ -636,6 +821,7 @@
|
|
|
636
821
|
did: result.did,
|
|
637
822
|
createdAt,
|
|
638
823
|
expiresAt,
|
|
824
|
+
source: 'wallet',
|
|
639
825
|
root: existing?.root,
|
|
640
826
|
};
|
|
641
827
|
if (nextRecord.root && nextRecord.root.aud && nextRecord.root.aud !== nextRecord.did) {
|
|
@@ -647,6 +833,7 @@
|
|
|
647
833
|
did: result.did,
|
|
648
834
|
createdAt,
|
|
649
835
|
expiresAt,
|
|
836
|
+
source: 'wallet',
|
|
650
837
|
signer: async (signingInput, payload) => {
|
|
651
838
|
const signatureResult = (await provider.request({
|
|
652
839
|
method: 'yeying_ucan_sign',
|
|
@@ -669,13 +856,20 @@
|
|
|
669
856
|
};
|
|
670
857
|
}
|
|
671
858
|
async function createUcanSession(options = {}) {
|
|
859
|
+
const sessionId = parseSessionId(options);
|
|
860
|
+
const record = await readSessionRecord(sessionId);
|
|
672
861
|
const provider = options.provider || (typeof window !== 'undefined'
|
|
673
862
|
? await getProvider({ preferYeYing: true })
|
|
674
863
|
: null);
|
|
675
|
-
if (
|
|
676
|
-
|
|
864
|
+
if (provider) {
|
|
865
|
+
try {
|
|
866
|
+
return await requestWalletUcanSession(provider, { ...options, id: sessionId });
|
|
867
|
+
}
|
|
868
|
+
catch {
|
|
869
|
+
// fallback to local ed25519 session
|
|
870
|
+
}
|
|
677
871
|
}
|
|
678
|
-
return await
|
|
872
|
+
return await createLocalSession({ ...options, id: sessionId }, record);
|
|
679
873
|
}
|
|
680
874
|
async function clearUcanSession(id = DEFAULT_SESSION_ID) {
|
|
681
875
|
await deleteSessionRecord(id);
|
|
@@ -686,6 +880,7 @@
|
|
|
686
880
|
const expiresAt = record?.expiresAt ?? null;
|
|
687
881
|
const did = record?.did || root.aud;
|
|
688
882
|
const nextRecord = {
|
|
883
|
+
...(record || {}),
|
|
689
884
|
id,
|
|
690
885
|
did,
|
|
691
886
|
createdAt,
|
|
@@ -699,7 +894,9 @@
|
|
|
699
894
|
return record?.root || null;
|
|
700
895
|
}
|
|
701
896
|
function capsEqual(a, b) {
|
|
702
|
-
|
|
897
|
+
const left = normalizeUcanCapabilities(a, { includeLegacyAliases: false });
|
|
898
|
+
const right = normalizeUcanCapabilities(b, { includeLegacyAliases: false });
|
|
899
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
703
900
|
}
|
|
704
901
|
function isRootExpired(root, nowMs) {
|
|
705
902
|
return Boolean(root.exp && nowMs > root.exp);
|
|
@@ -774,9 +971,13 @@
|
|
|
774
971
|
const nonce = options.nonce || randomNonce(8);
|
|
775
972
|
const exp = normalizeExpiry(undefined, options.expiresInMs ?? DEFAULT_SESSION_TTL);
|
|
776
973
|
const nbf = options.notBeforeMs;
|
|
974
|
+
const normalizedCapabilities = normalizeUcanCapabilities(options.capabilities);
|
|
975
|
+
if (!normalizedCapabilities.length) {
|
|
976
|
+
throw new Error('Missing UCAN capabilities');
|
|
977
|
+
}
|
|
777
978
|
const statementPayload = {
|
|
778
979
|
aud: session.did,
|
|
779
|
-
cap:
|
|
980
|
+
cap: normalizedCapabilities,
|
|
780
981
|
exp,
|
|
781
982
|
};
|
|
782
983
|
if (nbf)
|
|
@@ -799,7 +1000,7 @@
|
|
|
799
1000
|
type: 'siwe',
|
|
800
1001
|
iss: `did:pkh:eth:${address.toLowerCase()}`,
|
|
801
1002
|
aud: session.did,
|
|
802
|
-
cap:
|
|
1003
|
+
cap: normalizedCapabilities,
|
|
803
1004
|
exp,
|
|
804
1005
|
nbf,
|
|
805
1006
|
siwe: {
|
|
@@ -848,11 +1049,15 @@
|
|
|
848
1049
|
}));
|
|
849
1050
|
if (!issuer)
|
|
850
1051
|
throw new Error('Missing UCAN session key');
|
|
1052
|
+
const normalizedCapabilities = normalizeUcanCapabilities(options.capabilities);
|
|
1053
|
+
if (!normalizedCapabilities.length) {
|
|
1054
|
+
throw new Error('Missing UCAN capabilities');
|
|
1055
|
+
}
|
|
851
1056
|
const exp = normalizeExpiry(undefined, options.expiresInMs ?? DEFAULT_UCAN_TTL);
|
|
852
1057
|
const payload = {
|
|
853
1058
|
iss: issuer.did,
|
|
854
1059
|
aud: options.audience,
|
|
855
|
-
cap:
|
|
1060
|
+
cap: normalizedCapabilities,
|
|
856
1061
|
exp,
|
|
857
1062
|
nbf: options.notBeforeMs,
|
|
858
1063
|
prf: await resolveProofs(options, issuer),
|
|
@@ -866,11 +1071,15 @@
|
|
|
866
1071
|
}));
|
|
867
1072
|
if (!issuer)
|
|
868
1073
|
throw new Error('Missing UCAN session key');
|
|
1074
|
+
const normalizedCapabilities = normalizeUcanCapabilities(options.capabilities);
|
|
1075
|
+
if (!normalizedCapabilities.length) {
|
|
1076
|
+
throw new Error('Missing UCAN capabilities');
|
|
1077
|
+
}
|
|
869
1078
|
const exp = normalizeExpiry(undefined, options.expiresInMs ?? DEFAULT_UCAN_TTL);
|
|
870
1079
|
const payload = {
|
|
871
1080
|
iss: issuer.did,
|
|
872
1081
|
aud: options.audience,
|
|
873
|
-
cap:
|
|
1082
|
+
cap: normalizedCapabilities,
|
|
874
1083
|
exp,
|
|
875
1084
|
nbf: options.notBeforeMs,
|
|
876
1085
|
prf: await resolveProofs(options, issuer),
|
|
@@ -903,6 +1112,314 @@
|
|
|
903
1112
|
});
|
|
904
1113
|
}
|
|
905
1114
|
|
|
1115
|
+
const DEFAULT_BASE_URL = '/api/v1/public/auth/central';
|
|
1116
|
+
const DEFAULT_ISSUER_PATH = 'issuer';
|
|
1117
|
+
const DEFAULT_SESSION_PATH = 'session';
|
|
1118
|
+
const DEFAULT_ISSUE_PATH = 'issue';
|
|
1119
|
+
const DEFAULT_SESSION_TOKEN_KEY = 'centralUcanSessionToken';
|
|
1120
|
+
let cachedCentralSessionToken = null;
|
|
1121
|
+
function normalizeBaseUrl$1(baseUrl) {
|
|
1122
|
+
return baseUrl.replace(/\/+$/, '');
|
|
1123
|
+
}
|
|
1124
|
+
function joinUrl$1(baseUrl, path) {
|
|
1125
|
+
const trimmed = path.replace(/^\/+/, '');
|
|
1126
|
+
return `${normalizeBaseUrl$1(baseUrl)}/${trimmed}`;
|
|
1127
|
+
}
|
|
1128
|
+
function resolveBaseUrl(options) {
|
|
1129
|
+
return options?.baseUrl || DEFAULT_BASE_URL;
|
|
1130
|
+
}
|
|
1131
|
+
function resolveFetcher(options) {
|
|
1132
|
+
return options?.fetcher || fetch;
|
|
1133
|
+
}
|
|
1134
|
+
function resolveCredentials(options) {
|
|
1135
|
+
return options?.credentials ?? 'include';
|
|
1136
|
+
}
|
|
1137
|
+
function resolveSessionTokenKey(options) {
|
|
1138
|
+
return options?.sessionTokenStorageKey || DEFAULT_SESSION_TOKEN_KEY;
|
|
1139
|
+
}
|
|
1140
|
+
function resolveAccessToken(options) {
|
|
1141
|
+
if (typeof options?.accessToken === 'string') {
|
|
1142
|
+
const token = options.accessToken.trim();
|
|
1143
|
+
return token || null;
|
|
1144
|
+
}
|
|
1145
|
+
if (options?.accessToken === null) {
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
return getAccessToken(options);
|
|
1149
|
+
}
|
|
1150
|
+
function shouldStoreSessionToken(options) {
|
|
1151
|
+
return options?.storeSessionToken !== false;
|
|
1152
|
+
}
|
|
1153
|
+
function parseObject(value) {
|
|
1154
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1155
|
+
return {};
|
|
1156
|
+
}
|
|
1157
|
+
return value;
|
|
1158
|
+
}
|
|
1159
|
+
function parseEnvelopeData(payload) {
|
|
1160
|
+
const root = parseObject(payload);
|
|
1161
|
+
if (Object.prototype.hasOwnProperty.call(root, 'data')) {
|
|
1162
|
+
return parseObject(root.data);
|
|
1163
|
+
}
|
|
1164
|
+
return root;
|
|
1165
|
+
}
|
|
1166
|
+
function parseStringField(obj, keys) {
|
|
1167
|
+
for (const key of keys) {
|
|
1168
|
+
const value = obj[key];
|
|
1169
|
+
if (typeof value === 'string') {
|
|
1170
|
+
return value;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return undefined;
|
|
1174
|
+
}
|
|
1175
|
+
function parseNumberField(obj, keys) {
|
|
1176
|
+
for (const key of keys) {
|
|
1177
|
+
const value = obj[key];
|
|
1178
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1179
|
+
return value;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return undefined;
|
|
1183
|
+
}
|
|
1184
|
+
function parseCapabilitiesField(obj, keys) {
|
|
1185
|
+
for (const key of keys) {
|
|
1186
|
+
const value = obj[key];
|
|
1187
|
+
if (!Array.isArray(value))
|
|
1188
|
+
continue;
|
|
1189
|
+
const caps = value
|
|
1190
|
+
.filter(item => item && typeof item === 'object')
|
|
1191
|
+
.map(item => normalizeUcanCapability(item))
|
|
1192
|
+
.filter((cap) => Boolean(cap));
|
|
1193
|
+
return caps;
|
|
1194
|
+
}
|
|
1195
|
+
return undefined;
|
|
1196
|
+
}
|
|
1197
|
+
function parseIssuerDidField(obj) {
|
|
1198
|
+
return parseStringField(obj, ['issuerDid', 'issuer', 'did']);
|
|
1199
|
+
}
|
|
1200
|
+
function readStoredSessionToken(options) {
|
|
1201
|
+
if (!shouldStoreSessionToken(options))
|
|
1202
|
+
return null;
|
|
1203
|
+
if (typeof localStorage === 'undefined')
|
|
1204
|
+
return null;
|
|
1205
|
+
const key = resolveSessionTokenKey(options);
|
|
1206
|
+
return localStorage.getItem(key);
|
|
1207
|
+
}
|
|
1208
|
+
function persistSessionToken(token, options) {
|
|
1209
|
+
cachedCentralSessionToken = token;
|
|
1210
|
+
if (!shouldStoreSessionToken(options))
|
|
1211
|
+
return;
|
|
1212
|
+
if (typeof localStorage === 'undefined')
|
|
1213
|
+
return;
|
|
1214
|
+
const key = resolveSessionTokenKey(options);
|
|
1215
|
+
if (!token) {
|
|
1216
|
+
localStorage.removeItem(key);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
localStorage.setItem(key, token);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
async function parseJsonBody(response) {
|
|
1223
|
+
const text = await response.text();
|
|
1224
|
+
if (!text)
|
|
1225
|
+
return null;
|
|
1226
|
+
try {
|
|
1227
|
+
return JSON.parse(text);
|
|
1228
|
+
}
|
|
1229
|
+
catch {
|
|
1230
|
+
return { raw: text };
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
function getCentralSessionToken(options) {
|
|
1234
|
+
if (cachedCentralSessionToken)
|
|
1235
|
+
return cachedCentralSessionToken;
|
|
1236
|
+
const stored = readStoredSessionToken(options);
|
|
1237
|
+
if (stored) {
|
|
1238
|
+
cachedCentralSessionToken = stored;
|
|
1239
|
+
}
|
|
1240
|
+
return stored;
|
|
1241
|
+
}
|
|
1242
|
+
function setCentralSessionToken(token, options) {
|
|
1243
|
+
persistSessionToken(token, options);
|
|
1244
|
+
}
|
|
1245
|
+
function clearCentralSessionToken(options) {
|
|
1246
|
+
cachedCentralSessionToken = null;
|
|
1247
|
+
if (typeof localStorage === 'undefined')
|
|
1248
|
+
return;
|
|
1249
|
+
const key = resolveSessionTokenKey(options);
|
|
1250
|
+
localStorage.removeItem(key);
|
|
1251
|
+
}
|
|
1252
|
+
async function getCentralIssuerInfo(options = {}) {
|
|
1253
|
+
const fetcher = resolveFetcher(options);
|
|
1254
|
+
const credentials = resolveCredentials(options);
|
|
1255
|
+
const url = joinUrl$1(resolveBaseUrl(options), options.issuerPath || DEFAULT_ISSUER_PATH);
|
|
1256
|
+
const token = resolveAccessToken(options);
|
|
1257
|
+
const headers = new Headers({
|
|
1258
|
+
accept: 'application/json',
|
|
1259
|
+
});
|
|
1260
|
+
if (token) {
|
|
1261
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
1262
|
+
}
|
|
1263
|
+
const response = await fetcher(url, {
|
|
1264
|
+
method: 'GET',
|
|
1265
|
+
headers,
|
|
1266
|
+
credentials,
|
|
1267
|
+
});
|
|
1268
|
+
const payload = await parseJsonBody(response);
|
|
1269
|
+
if (!response.ok) {
|
|
1270
|
+
throw new Error(`Central issuer request failed: ${response.status} ${JSON.stringify(payload)}`);
|
|
1271
|
+
}
|
|
1272
|
+
const data = parseEnvelopeData(payload);
|
|
1273
|
+
return {
|
|
1274
|
+
enabled: typeof data.enabled === 'boolean' ? data.enabled : undefined,
|
|
1275
|
+
issuerDid: parseIssuerDidField(data),
|
|
1276
|
+
defaultAudience: parseStringField(data, ['defaultAudience']),
|
|
1277
|
+
defaultCapabilities: parseCapabilitiesField(data, ['defaultCapabilities']),
|
|
1278
|
+
response: payload,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
async function createCentralSession(options) {
|
|
1282
|
+
const subject = String(options?.subject || '').trim();
|
|
1283
|
+
if (!subject) {
|
|
1284
|
+
throw new Error('Missing subject');
|
|
1285
|
+
}
|
|
1286
|
+
const fetcher = resolveFetcher(options);
|
|
1287
|
+
const credentials = resolveCredentials(options);
|
|
1288
|
+
const accessToken = resolveAccessToken(options);
|
|
1289
|
+
const url = joinUrl$1(resolveBaseUrl(options), options.sessionPath || DEFAULT_SESSION_PATH);
|
|
1290
|
+
const headers = new Headers({
|
|
1291
|
+
'Content-Type': 'application/json',
|
|
1292
|
+
accept: 'application/json',
|
|
1293
|
+
});
|
|
1294
|
+
if (accessToken) {
|
|
1295
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
1296
|
+
}
|
|
1297
|
+
const response = await fetcher(url, {
|
|
1298
|
+
method: 'POST',
|
|
1299
|
+
headers,
|
|
1300
|
+
credentials,
|
|
1301
|
+
body: JSON.stringify({
|
|
1302
|
+
subject,
|
|
1303
|
+
sessionTtlMs: options.sessionTtlMs,
|
|
1304
|
+
}),
|
|
1305
|
+
});
|
|
1306
|
+
const payload = await parseJsonBody(response);
|
|
1307
|
+
if (!response.ok) {
|
|
1308
|
+
throw new Error(`Central session request failed: ${response.status} ${JSON.stringify(payload)}`);
|
|
1309
|
+
}
|
|
1310
|
+
const data = parseEnvelopeData(payload);
|
|
1311
|
+
const sessionToken = parseStringField(data, ['sessionToken']);
|
|
1312
|
+
if (!sessionToken) {
|
|
1313
|
+
throw new Error('Central session response missing sessionToken');
|
|
1314
|
+
}
|
|
1315
|
+
persistSessionToken(sessionToken, options);
|
|
1316
|
+
return {
|
|
1317
|
+
subject: parseStringField(data, ['subject']) || subject,
|
|
1318
|
+
sessionToken,
|
|
1319
|
+
expiresAt: parseNumberField(data, ['expiresAt']),
|
|
1320
|
+
issuerDid: parseIssuerDidField(data),
|
|
1321
|
+
response: payload,
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
async function issueCentralUcan(options = {}) {
|
|
1325
|
+
const sessionToken = options.sessionToken || getCentralSessionToken(options);
|
|
1326
|
+
if (!sessionToken) {
|
|
1327
|
+
throw new Error('Missing central session token');
|
|
1328
|
+
}
|
|
1329
|
+
const normalizedCapabilities = options.capabilities
|
|
1330
|
+
? normalizeUcanCapabilities(options.capabilities)
|
|
1331
|
+
: undefined;
|
|
1332
|
+
const fetcher = resolveFetcher(options);
|
|
1333
|
+
const credentials = resolveCredentials(options);
|
|
1334
|
+
const url = joinUrl$1(resolveBaseUrl(options), options.issuePath || DEFAULT_ISSUE_PATH);
|
|
1335
|
+
const response = await fetcher(url, {
|
|
1336
|
+
method: 'POST',
|
|
1337
|
+
headers: {
|
|
1338
|
+
'Content-Type': 'application/json',
|
|
1339
|
+
accept: 'application/json',
|
|
1340
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
1341
|
+
},
|
|
1342
|
+
credentials,
|
|
1343
|
+
body: JSON.stringify({
|
|
1344
|
+
audience: options.audience,
|
|
1345
|
+
capabilities: normalizedCapabilities,
|
|
1346
|
+
expiresInMs: options.expiresInMs,
|
|
1347
|
+
ttlMs: options.ttlMs,
|
|
1348
|
+
}),
|
|
1349
|
+
});
|
|
1350
|
+
const payload = await parseJsonBody(response);
|
|
1351
|
+
if (!response.ok) {
|
|
1352
|
+
throw new Error(`Central UCAN issue failed: ${response.status} ${JSON.stringify(payload)}`);
|
|
1353
|
+
}
|
|
1354
|
+
const data = parseEnvelopeData(payload);
|
|
1355
|
+
const ucan = parseStringField(data, ['ucan']);
|
|
1356
|
+
if (!ucan) {
|
|
1357
|
+
throw new Error('Central UCAN response missing ucan');
|
|
1358
|
+
}
|
|
1359
|
+
return {
|
|
1360
|
+
ucan,
|
|
1361
|
+
issuerDid: parseIssuerDidField(data),
|
|
1362
|
+
subject: parseStringField(data, ['subject']),
|
|
1363
|
+
audience: parseStringField(data, ['audience']),
|
|
1364
|
+
capabilities: parseCapabilitiesField(data, ['capabilities']),
|
|
1365
|
+
exp: parseNumberField(data, ['exp', 'expiresAt']),
|
|
1366
|
+
nbf: parseNumberField(data, ['nbf', 'notBefore']),
|
|
1367
|
+
iat: parseNumberField(data, ['iat', 'issuedAt']),
|
|
1368
|
+
response: payload,
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
async function createAndIssueCentralUcan(options) {
|
|
1372
|
+
const session = await createCentralSession({
|
|
1373
|
+
...options,
|
|
1374
|
+
subject: options.subject,
|
|
1375
|
+
sessionTtlMs: options.sessionTtlMs,
|
|
1376
|
+
});
|
|
1377
|
+
const issue = await issueCentralUcan({
|
|
1378
|
+
...options,
|
|
1379
|
+
sessionToken: session.sessionToken,
|
|
1380
|
+
audience: options.audience,
|
|
1381
|
+
capabilities: options.capabilities,
|
|
1382
|
+
expiresInMs: options.expiresInMs,
|
|
1383
|
+
ttlMs: options.ttlMs,
|
|
1384
|
+
});
|
|
1385
|
+
return { session, issue };
|
|
1386
|
+
}
|
|
1387
|
+
async function authCentralUcanFetch(input, init = {}, options = {}) {
|
|
1388
|
+
const fetcher = resolveFetcher(options);
|
|
1389
|
+
const credentials = resolveCredentials(options);
|
|
1390
|
+
let token = options.ucan || null;
|
|
1391
|
+
if (!token) {
|
|
1392
|
+
let sessionToken = options.sessionToken || getCentralSessionToken(options);
|
|
1393
|
+
if (!sessionToken) {
|
|
1394
|
+
if (!options.subject) {
|
|
1395
|
+
throw new Error('Missing central session token or subject');
|
|
1396
|
+
}
|
|
1397
|
+
const session = await createCentralSession({
|
|
1398
|
+
...options,
|
|
1399
|
+
subject: options.subject,
|
|
1400
|
+
sessionTtlMs: options.sessionTtlMs,
|
|
1401
|
+
});
|
|
1402
|
+
sessionToken = session.sessionToken;
|
|
1403
|
+
}
|
|
1404
|
+
const issued = await issueCentralUcan({
|
|
1405
|
+
...options,
|
|
1406
|
+
sessionToken,
|
|
1407
|
+
audience: options.audience,
|
|
1408
|
+
capabilities: options.capabilities,
|
|
1409
|
+
expiresInMs: options.expiresInMs,
|
|
1410
|
+
ttlMs: options.ttlMs,
|
|
1411
|
+
});
|
|
1412
|
+
token = issued.ucan;
|
|
1413
|
+
}
|
|
1414
|
+
const headers = new Headers(init.headers || {});
|
|
1415
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
1416
|
+
return fetcher(input, {
|
|
1417
|
+
...init,
|
|
1418
|
+
headers,
|
|
1419
|
+
credentials,
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
|
|
906
1423
|
function normalizeBaseUrl(baseUrl) {
|
|
907
1424
|
return baseUrl.replace(/\/+$/, '');
|
|
908
1425
|
}
|
|
@@ -1120,6 +1637,13 @@
|
|
|
1120
1637
|
const tokenCache = new Map();
|
|
1121
1638
|
const TOKEN_SKEW_MS = 5000;
|
|
1122
1639
|
const DEFAULT_APP_ACTION = 'write';
|
|
1640
|
+
const LOOPBACK_HOST_ALIASES = new Set([
|
|
1641
|
+
'localhost',
|
|
1642
|
+
'127.0.0.1',
|
|
1643
|
+
'::1',
|
|
1644
|
+
'0:0:0:0:0:0:0:1',
|
|
1645
|
+
'0.0.0.0',
|
|
1646
|
+
]);
|
|
1123
1647
|
function normalizeAppDir(path) {
|
|
1124
1648
|
const trimmed = path.trim();
|
|
1125
1649
|
if (!trimmed)
|
|
@@ -1131,6 +1655,69 @@
|
|
|
1131
1655
|
function sanitizeAppId(appId) {
|
|
1132
1656
|
return appId.trim().replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
1133
1657
|
}
|
|
1658
|
+
function parseHostPort(rawHost) {
|
|
1659
|
+
const host = rawHost.trim();
|
|
1660
|
+
if (!host)
|
|
1661
|
+
return { hostname: '', port: '' };
|
|
1662
|
+
const bracketMatch = host.match(/^\[([^\]]+)\](?::([0-9]+))?$/);
|
|
1663
|
+
if (bracketMatch) {
|
|
1664
|
+
return {
|
|
1665
|
+
hostname: bracketMatch[1] || '',
|
|
1666
|
+
port: bracketMatch[2] || '',
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
const firstColon = host.indexOf(':');
|
|
1670
|
+
const lastColon = host.lastIndexOf(':');
|
|
1671
|
+
if (firstColon > -1 && firstColon === lastColon) {
|
|
1672
|
+
const hostname = host.slice(0, firstColon).trim();
|
|
1673
|
+
const port = host.slice(firstColon + 1).trim();
|
|
1674
|
+
if (/^[0-9]+$/.test(port)) {
|
|
1675
|
+
return { hostname, port };
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
return { hostname: host, port: '' };
|
|
1679
|
+
}
|
|
1680
|
+
function normalizeAppHostnameForAppId(hostname) {
|
|
1681
|
+
const normalized = (hostname || '').trim().toLowerCase();
|
|
1682
|
+
if (!normalized)
|
|
1683
|
+
return '';
|
|
1684
|
+
const bare = normalized.replace(/^\[(.*)\]$/, '$1');
|
|
1685
|
+
if (LOOPBACK_HOST_ALIASES.has(normalized) || LOOPBACK_HOST_ALIASES.has(bare)) {
|
|
1686
|
+
return 'localhost';
|
|
1687
|
+
}
|
|
1688
|
+
return bare;
|
|
1689
|
+
}
|
|
1690
|
+
function buildSanitizedAppId(hostname, port) {
|
|
1691
|
+
const normalizedHostname = normalizeAppHostnameForAppId(hostname);
|
|
1692
|
+
if (!normalizedHostname)
|
|
1693
|
+
return '';
|
|
1694
|
+
const normalizedPort = port === undefined || port === null ? '' : String(port).trim();
|
|
1695
|
+
const host = normalizedPort
|
|
1696
|
+
? `${normalizedHostname}:${normalizedPort}`
|
|
1697
|
+
: normalizedHostname;
|
|
1698
|
+
return sanitizeAppId(host);
|
|
1699
|
+
}
|
|
1700
|
+
function deriveAppIdFromHost(host) {
|
|
1701
|
+
const parsed = parseHostPort(host || '');
|
|
1702
|
+
return buildSanitizedAppId(parsed.hostname, parsed.port);
|
|
1703
|
+
}
|
|
1704
|
+
function deriveAppIdFromLocation(locationLike) {
|
|
1705
|
+
const source = locationLike ||
|
|
1706
|
+
(typeof window !== 'undefined' ? window.location : undefined);
|
|
1707
|
+
if (!source)
|
|
1708
|
+
return '';
|
|
1709
|
+
const hostname = typeof source.hostname === 'string' ? source.hostname : '';
|
|
1710
|
+
const port = source.port;
|
|
1711
|
+
if (hostname) {
|
|
1712
|
+
const appId = buildSanitizedAppId(hostname, port);
|
|
1713
|
+
if (appId)
|
|
1714
|
+
return appId;
|
|
1715
|
+
}
|
|
1716
|
+
if (typeof source.host === 'string') {
|
|
1717
|
+
return deriveAppIdFromHost(source.host);
|
|
1718
|
+
}
|
|
1719
|
+
return '';
|
|
1720
|
+
}
|
|
1134
1721
|
function normalizeAction(action) {
|
|
1135
1722
|
const trimmed = (action || '').trim();
|
|
1136
1723
|
return trimmed ? trimmed : null;
|
|
@@ -1139,25 +1726,19 @@
|
|
|
1139
1726
|
if (!options.appId)
|
|
1140
1727
|
return null;
|
|
1141
1728
|
const action = normalizeAction(options.appAction) || DEFAULT_APP_ACTION;
|
|
1729
|
+
const resource = `app:all:${sanitizeAppId(options.appId)}`;
|
|
1142
1730
|
return {
|
|
1143
|
-
|
|
1731
|
+
with: resource,
|
|
1732
|
+
can: action,
|
|
1733
|
+
resource,
|
|
1144
1734
|
action,
|
|
1145
1735
|
};
|
|
1146
1736
|
}
|
|
1147
1737
|
function hasAppCapability(caps) {
|
|
1148
|
-
return (caps || []).some(cap =>
|
|
1738
|
+
return (caps || []).some(cap => getCapabilityResource(cap).startsWith('app:'));
|
|
1149
1739
|
}
|
|
1150
1740
|
function dedupeCapabilities(caps) {
|
|
1151
|
-
|
|
1152
|
-
return (caps || []).filter(cap => {
|
|
1153
|
-
if (!cap || !cap.resource || !cap.action)
|
|
1154
|
-
return false;
|
|
1155
|
-
const key = `${cap.resource}|${cap.action}`;
|
|
1156
|
-
if (seen.has(key))
|
|
1157
|
-
return false;
|
|
1158
|
-
seen.add(key);
|
|
1159
|
-
return true;
|
|
1160
|
-
});
|
|
1741
|
+
return normalizeUcanCapabilities(caps);
|
|
1161
1742
|
}
|
|
1162
1743
|
function ensureAppCapability(caps, options) {
|
|
1163
1744
|
const appCap = buildAppCapability(options);
|
|
@@ -1177,7 +1758,13 @@
|
|
|
1177
1758
|
return undefined;
|
|
1178
1759
|
}
|
|
1179
1760
|
function buildCapsKey(caps) {
|
|
1180
|
-
|
|
1761
|
+
const canonical = (caps || [])
|
|
1762
|
+
.map(cap => ({
|
|
1763
|
+
with: getCapabilityResource(cap),
|
|
1764
|
+
can: getCapabilityAction(cap),
|
|
1765
|
+
}))
|
|
1766
|
+
.filter(cap => Boolean(cap.with && cap.can));
|
|
1767
|
+
return JSON.stringify(canonical);
|
|
1181
1768
|
}
|
|
1182
1769
|
function buildTokenCacheKey(issuer, audience, caps) {
|
|
1183
1770
|
return `${issuer.did}|${audience}|${buildCapsKey(caps)}`;
|
|
@@ -1355,18 +1942,28 @@
|
|
|
1355
1942
|
}
|
|
1356
1943
|
|
|
1357
1944
|
exports.WebDavClient = WebDavClient;
|
|
1945
|
+
exports.authCentralUcanFetch = authCentralUcanFetch;
|
|
1358
1946
|
exports.authFetch = authFetch;
|
|
1359
1947
|
exports.authUcanFetch = authUcanFetch;
|
|
1360
1948
|
exports.clearAccessToken = clearAccessToken;
|
|
1949
|
+
exports.clearCentralSessionToken = clearCentralSessionToken;
|
|
1361
1950
|
exports.clearUcanSession = clearUcanSession;
|
|
1951
|
+
exports.createAndIssueCentralUcan = createAndIssueCentralUcan;
|
|
1952
|
+
exports.createCentralSession = createCentralSession;
|
|
1362
1953
|
exports.createDelegationUcan = createDelegationUcan;
|
|
1363
1954
|
exports.createInvocationUcan = createInvocationUcan;
|
|
1364
1955
|
exports.createRootUcan = createRootUcan;
|
|
1365
1956
|
exports.createUcanSession = createUcanSession;
|
|
1366
1957
|
exports.createWebDavClient = createWebDavClient;
|
|
1958
|
+
exports.deriveAppIdFromHost = deriveAppIdFromHost;
|
|
1959
|
+
exports.deriveAppIdFromLocation = deriveAppIdFromLocation;
|
|
1367
1960
|
exports.getAccessToken = getAccessToken;
|
|
1368
1961
|
exports.getAccounts = getAccounts;
|
|
1369
1962
|
exports.getBalance = getBalance;
|
|
1963
|
+
exports.getCapabilityAction = getCapabilityAction;
|
|
1964
|
+
exports.getCapabilityResource = getCapabilityResource;
|
|
1965
|
+
exports.getCentralIssuerInfo = getCentralIssuerInfo;
|
|
1966
|
+
exports.getCentralSessionToken = getCentralSessionToken;
|
|
1370
1967
|
exports.getChainId = getChainId;
|
|
1371
1968
|
exports.getOrCreateUcanRoot = getOrCreateUcanRoot;
|
|
1372
1969
|
exports.getPreferredAccount = getPreferredAccount;
|
|
@@ -1376,14 +1973,19 @@
|
|
|
1376
1973
|
exports.initDappSession = initDappSession;
|
|
1377
1974
|
exports.initWebDavStorage = initWebDavStorage;
|
|
1378
1975
|
exports.isYeYingProvider = isYeYingProvider;
|
|
1976
|
+
exports.issueCentralUcan = issueCentralUcan;
|
|
1379
1977
|
exports.loginWithChallenge = loginWithChallenge;
|
|
1380
1978
|
exports.logout = logout;
|
|
1979
|
+
exports.normalizeAppHostnameForAppId = normalizeAppHostnameForAppId;
|
|
1980
|
+
exports.normalizeUcanCapabilities = normalizeUcanCapabilities;
|
|
1981
|
+
exports.normalizeUcanCapability = normalizeUcanCapability;
|
|
1381
1982
|
exports.onAccountsChanged = onAccountsChanged;
|
|
1382
1983
|
exports.onChainChanged = onChainChanged;
|
|
1383
1984
|
exports.refreshAccessToken = refreshAccessToken;
|
|
1384
1985
|
exports.requestAccounts = requestAccounts;
|
|
1385
1986
|
exports.requireProvider = requireProvider;
|
|
1386
1987
|
exports.setAccessToken = setAccessToken;
|
|
1988
|
+
exports.setCentralSessionToken = setCentralSessionToken;
|
|
1387
1989
|
exports.signMessage = signMessage;
|
|
1388
1990
|
exports.storeUcanRoot = storeUcanRoot;
|
|
1389
1991
|
exports.watchAccounts = watchAccounts;
|