@yeying-community/web3-bs 1.0.2 → 1.0.3
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 +229 -5
- package/dist/auth/ucan.d.ts +1 -0
- package/dist/dapp.d.ts +48 -0
- package/dist/index.d.ts +1 -0
- package/dist/storage/webdav.d.ts +1 -0
- package/dist/web3-bs.esm.js +242 -2
- package/dist/web3-bs.esm.js.map +1 -1
- package/dist/web3-bs.umd.js +244 -1
- package/dist/web3-bs.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/web3-bs.umd.js
CHANGED
|
@@ -643,6 +643,25 @@
|
|
|
643
643
|
const record = await readSessionRecord(id);
|
|
644
644
|
return record?.root || null;
|
|
645
645
|
}
|
|
646
|
+
function capsEqual(a, b) {
|
|
647
|
+
return JSON.stringify(a || []) === JSON.stringify(b || []);
|
|
648
|
+
}
|
|
649
|
+
function isRootExpired(root, nowMs) {
|
|
650
|
+
return Boolean(root.exp && nowMs > root.exp);
|
|
651
|
+
}
|
|
652
|
+
async function getOrCreateUcanRoot(options) {
|
|
653
|
+
const provider = options.provider || (await requireProvider());
|
|
654
|
+
const session = options.session || (await createUcanSession({ id: options.sessionId, provider }));
|
|
655
|
+
const nowMs = Date.now();
|
|
656
|
+
const stored = await getStoredUcanRoot(session.id);
|
|
657
|
+
if (stored &&
|
|
658
|
+
(!stored.aud || stored.aud === session.did) &&
|
|
659
|
+
capsEqual(stored.cap, options.capabilities) &&
|
|
660
|
+
!isRootExpired(stored, nowMs)) {
|
|
661
|
+
return stored;
|
|
662
|
+
}
|
|
663
|
+
return await createRootUcan({ ...options, provider, session });
|
|
664
|
+
}
|
|
646
665
|
function buildUcanStatement(payload) {
|
|
647
666
|
return `UCAN-AUTH ${JSON.stringify(payload)}`;
|
|
648
667
|
}
|
|
@@ -667,7 +686,15 @@
|
|
|
667
686
|
async function resolveAddress(provider, address) {
|
|
668
687
|
if (address)
|
|
669
688
|
return address;
|
|
670
|
-
|
|
689
|
+
let accounts = await getAccounts(provider);
|
|
690
|
+
if (!accounts[0]) {
|
|
691
|
+
const requested = (await provider.request({
|
|
692
|
+
method: 'eth_requestAccounts',
|
|
693
|
+
}));
|
|
694
|
+
if (Array.isArray(requested)) {
|
|
695
|
+
accounts = requested;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
671
698
|
if (!accounts[0])
|
|
672
699
|
throw new Error('No account available');
|
|
673
700
|
return accounts[0];
|
|
@@ -931,6 +958,27 @@
|
|
|
931
958
|
async createDirectory(path) {
|
|
932
959
|
return await this.request('MKCOL', path);
|
|
933
960
|
}
|
|
961
|
+
async ensureDirectory(path) {
|
|
962
|
+
if (!path || path === '/')
|
|
963
|
+
return;
|
|
964
|
+
const segments = path.split('/').filter(Boolean);
|
|
965
|
+
if (segments.length === 0)
|
|
966
|
+
return;
|
|
967
|
+
let current = '';
|
|
968
|
+
for (const segment of segments) {
|
|
969
|
+
current = `${current}/${segment}`;
|
|
970
|
+
const res = await this.fetcher(this.buildUrl(current), {
|
|
971
|
+
method: 'MKCOL',
|
|
972
|
+
headers: this.buildHeaders(),
|
|
973
|
+
credentials: this.credentials,
|
|
974
|
+
});
|
|
975
|
+
if (res.ok)
|
|
976
|
+
continue;
|
|
977
|
+
if (res.status === 405)
|
|
978
|
+
continue;
|
|
979
|
+
throw new Error(`WebDAV MKCOL ${current} failed: ${res.status} ${res.statusText}`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
934
982
|
async remove(path) {
|
|
935
983
|
return await this.request('DELETE', path);
|
|
936
984
|
}
|
|
@@ -1014,6 +1062,198 @@
|
|
|
1014
1062
|
return new WebDavClient(options);
|
|
1015
1063
|
}
|
|
1016
1064
|
|
|
1065
|
+
const tokenCache = new Map();
|
|
1066
|
+
const TOKEN_SKEW_MS = 5000;
|
|
1067
|
+
function normalizeAppDir(path) {
|
|
1068
|
+
const trimmed = path.trim();
|
|
1069
|
+
if (!trimmed)
|
|
1070
|
+
return '/';
|
|
1071
|
+
let next = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
1072
|
+
next = next.replace(/\/+$/, '');
|
|
1073
|
+
return next || '/';
|
|
1074
|
+
}
|
|
1075
|
+
function sanitizeAppId(appId) {
|
|
1076
|
+
return appId.trim().replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
1077
|
+
}
|
|
1078
|
+
function resolveAppDir(options) {
|
|
1079
|
+
if (options.appDir) {
|
|
1080
|
+
return normalizeAppDir(options.appDir);
|
|
1081
|
+
}
|
|
1082
|
+
if (options.appId) {
|
|
1083
|
+
return normalizeAppDir(`/apps/${sanitizeAppId(options.appId)}`);
|
|
1084
|
+
}
|
|
1085
|
+
return undefined;
|
|
1086
|
+
}
|
|
1087
|
+
function buildCapsKey(caps) {
|
|
1088
|
+
return JSON.stringify(caps || []);
|
|
1089
|
+
}
|
|
1090
|
+
function buildTokenCacheKey(issuer, audience, caps) {
|
|
1091
|
+
return `${issuer.did}|${audience}|${buildCapsKey(caps)}`;
|
|
1092
|
+
}
|
|
1093
|
+
function isTokenValid(entry, nowMs) {
|
|
1094
|
+
if (!entry.exp)
|
|
1095
|
+
return false;
|
|
1096
|
+
if (entry.nbf && nowMs < entry.nbf)
|
|
1097
|
+
return false;
|
|
1098
|
+
return entry.exp - TOKEN_SKEW_MS > nowMs;
|
|
1099
|
+
}
|
|
1100
|
+
function decodeBase64Url(input) {
|
|
1101
|
+
if (!input)
|
|
1102
|
+
return null;
|
|
1103
|
+
const base64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
1104
|
+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');
|
|
1105
|
+
try {
|
|
1106
|
+
if (typeof atob === 'function') {
|
|
1107
|
+
return atob(padded);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
catch {
|
|
1111
|
+
// ignore
|
|
1112
|
+
}
|
|
1113
|
+
try {
|
|
1114
|
+
const nodeBuffer = globalThis.Buffer;
|
|
1115
|
+
if (nodeBuffer) {
|
|
1116
|
+
return nodeBuffer.from(padded, 'base64').toString('utf8');
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
catch {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
function decodeUcanPayload(token) {
|
|
1125
|
+
const parts = token.split('.');
|
|
1126
|
+
if (parts.length < 2)
|
|
1127
|
+
return null;
|
|
1128
|
+
const decoded = decodeBase64Url(parts[1]);
|
|
1129
|
+
if (!decoded)
|
|
1130
|
+
return null;
|
|
1131
|
+
try {
|
|
1132
|
+
return JSON.parse(decoded);
|
|
1133
|
+
}
|
|
1134
|
+
catch {
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
async function getCachedInvocationToken(options) {
|
|
1139
|
+
const cacheKey = buildTokenCacheKey(options.issuer, options.audience, options.capabilities);
|
|
1140
|
+
const cached = tokenCache.get(cacheKey);
|
|
1141
|
+
const nowMs = Date.now();
|
|
1142
|
+
if (cached && isTokenValid(cached, nowMs)) {
|
|
1143
|
+
return cached.token;
|
|
1144
|
+
}
|
|
1145
|
+
const token = await createInvocationUcan({
|
|
1146
|
+
issuer: options.issuer,
|
|
1147
|
+
audience: options.audience,
|
|
1148
|
+
capabilities: options.capabilities,
|
|
1149
|
+
proofs: options.proofs,
|
|
1150
|
+
expiresInMs: options.expiresInMs,
|
|
1151
|
+
notBeforeMs: options.notBeforeMs,
|
|
1152
|
+
});
|
|
1153
|
+
const payload = decodeUcanPayload(token);
|
|
1154
|
+
if (payload && typeof payload.exp === 'number') {
|
|
1155
|
+
tokenCache.set(cacheKey, {
|
|
1156
|
+
token,
|
|
1157
|
+
exp: payload.exp,
|
|
1158
|
+
nbf: payload.nbf,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
return token;
|
|
1162
|
+
}
|
|
1163
|
+
async function initWebDavStorage(options) {
|
|
1164
|
+
const caps = options.capabilities || options.root?.cap;
|
|
1165
|
+
if (!caps || caps.length === 0) {
|
|
1166
|
+
throw new Error('Missing UCAN capabilities for WebDAV');
|
|
1167
|
+
}
|
|
1168
|
+
const needsProvider = !options.session || !options.root;
|
|
1169
|
+
const provider = options.provider || (needsProvider ? await requireProvider() : undefined);
|
|
1170
|
+
const session = options.session ||
|
|
1171
|
+
(await createUcanSession({
|
|
1172
|
+
id: options.sessionId,
|
|
1173
|
+
provider,
|
|
1174
|
+
}));
|
|
1175
|
+
const nowMs = Date.now();
|
|
1176
|
+
let root = options.root;
|
|
1177
|
+
if (root && root.aud && root.aud !== session.did) {
|
|
1178
|
+
root = undefined;
|
|
1179
|
+
}
|
|
1180
|
+
if (root && buildCapsKey(root.cap) !== buildCapsKey(caps)) {
|
|
1181
|
+
root = undefined;
|
|
1182
|
+
}
|
|
1183
|
+
if (root && root.exp && nowMs > root.exp) {
|
|
1184
|
+
root = undefined;
|
|
1185
|
+
}
|
|
1186
|
+
if (!root) {
|
|
1187
|
+
root = await getOrCreateUcanRoot({
|
|
1188
|
+
provider: provider || (await requireProvider()),
|
|
1189
|
+
session,
|
|
1190
|
+
capabilities: caps,
|
|
1191
|
+
expiresInMs: options.rootExpiresInMs,
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
const invocationCaps = options.invocationCapabilities || caps;
|
|
1195
|
+
const token = await getCachedInvocationToken({
|
|
1196
|
+
issuer: session,
|
|
1197
|
+
audience: options.audience,
|
|
1198
|
+
capabilities: invocationCaps,
|
|
1199
|
+
proofs: [root],
|
|
1200
|
+
expiresInMs: options.invocationExpiresInMs,
|
|
1201
|
+
notBeforeMs: options.notBeforeMs,
|
|
1202
|
+
});
|
|
1203
|
+
const client = createWebDavClient({
|
|
1204
|
+
baseUrl: options.baseUrl,
|
|
1205
|
+
prefix: options.prefix,
|
|
1206
|
+
token,
|
|
1207
|
+
fetcher: options.fetcher,
|
|
1208
|
+
credentials: options.credentials,
|
|
1209
|
+
});
|
|
1210
|
+
const appDir = resolveAppDir(options);
|
|
1211
|
+
if (appDir && options.ensureAppDir !== false) {
|
|
1212
|
+
await client.ensureDirectory(appDir);
|
|
1213
|
+
}
|
|
1214
|
+
return {
|
|
1215
|
+
client,
|
|
1216
|
+
token,
|
|
1217
|
+
appDir,
|
|
1218
|
+
session,
|
|
1219
|
+
root,
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
async function initDappSession(options) {
|
|
1223
|
+
if (!options.appAuth && !options.webdav) {
|
|
1224
|
+
throw new Error('No init options provided');
|
|
1225
|
+
}
|
|
1226
|
+
const provider = options.provider ||
|
|
1227
|
+
options.appAuth?.provider ||
|
|
1228
|
+
options.webdav?.provider ||
|
|
1229
|
+
(await requireProvider());
|
|
1230
|
+
const result = {
|
|
1231
|
+
provider,
|
|
1232
|
+
address: options.address,
|
|
1233
|
+
};
|
|
1234
|
+
if (options.appAuth) {
|
|
1235
|
+
const appLogin = await loginWithChallenge({
|
|
1236
|
+
...options.appAuth,
|
|
1237
|
+
provider: options.appAuth.provider || provider,
|
|
1238
|
+
address: options.appAuth.address || options.address,
|
|
1239
|
+
});
|
|
1240
|
+
result.appLogin = appLogin;
|
|
1241
|
+
result.address = appLogin.address;
|
|
1242
|
+
}
|
|
1243
|
+
if (options.webdav) {
|
|
1244
|
+
const webdav = await initWebDavStorage({
|
|
1245
|
+
...options.webdav,
|
|
1246
|
+
provider: options.webdav.provider || provider,
|
|
1247
|
+
});
|
|
1248
|
+
result.ucanSession = webdav.session;
|
|
1249
|
+
result.ucanRoot = webdav.root;
|
|
1250
|
+
result.webdavClient = webdav.client;
|
|
1251
|
+
result.webdavToken = webdav.token;
|
|
1252
|
+
result.webdavAppDir = webdav.appDir;
|
|
1253
|
+
}
|
|
1254
|
+
return result;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1017
1257
|
exports.WebDavClient = WebDavClient;
|
|
1018
1258
|
exports.authFetch = authFetch;
|
|
1019
1259
|
exports.authUcanFetch = authUcanFetch;
|
|
@@ -1028,9 +1268,12 @@
|
|
|
1028
1268
|
exports.getAccounts = getAccounts;
|
|
1029
1269
|
exports.getBalance = getBalance;
|
|
1030
1270
|
exports.getChainId = getChainId;
|
|
1271
|
+
exports.getOrCreateUcanRoot = getOrCreateUcanRoot;
|
|
1031
1272
|
exports.getProvider = getProvider;
|
|
1032
1273
|
exports.getStoredUcanRoot = getStoredUcanRoot;
|
|
1033
1274
|
exports.getUcanSession = getUcanSession;
|
|
1275
|
+
exports.initDappSession = initDappSession;
|
|
1276
|
+
exports.initWebDavStorage = initWebDavStorage;
|
|
1034
1277
|
exports.isYeYingProvider = isYeYingProvider;
|
|
1035
1278
|
exports.loginWithChallenge = loginWithChallenge;
|
|
1036
1279
|
exports.logout = logout;
|