@lumiapassport/core 1.0.0
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/LICENSE +21 -0
- package/README.md +112 -0
- package/dist/auth/index.cjs +652 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +202 -0
- package/dist/auth/index.d.ts +202 -0
- package/dist/auth/index.js +631 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/bundler/index.cjs +497 -0
- package/dist/bundler/index.cjs.map +1 -0
- package/dist/bundler/index.d.cts +144 -0
- package/dist/bundler/index.d.ts +144 -0
- package/dist/bundler/index.js +465 -0
- package/dist/bundler/index.js.map +1 -0
- package/dist/clients/index.cjs +8 -0
- package/dist/clients/index.cjs.map +1 -0
- package/dist/clients/index.d.cts +7 -0
- package/dist/clients/index.d.ts +7 -0
- package/dist/clients/index.js +6 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/index.cjs +1310 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +1243 -0
- package/dist/index.js.map +1 -0
- package/dist/mpc/index.cjs +8 -0
- package/dist/mpc/index.cjs.map +1 -0
- package/dist/mpc/index.d.cts +7 -0
- package/dist/mpc/index.d.ts +7 -0
- package/dist/mpc/index.js +6 -0
- package/dist/mpc/index.js.map +1 -0
- package/dist/utils/index.cjs +198 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +114 -0
- package/dist/utils/index.d.ts +114 -0
- package/dist/utils/index.js +182 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
// src/auth/base64url.ts
|
|
2
|
+
function arrayBufferToBase64url(buffer) {
|
|
3
|
+
const bytes = new Uint8Array(buffer);
|
|
4
|
+
let binary = "";
|
|
5
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
6
|
+
binary += String.fromCharCode(bytes[i]);
|
|
7
|
+
}
|
|
8
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
9
|
+
}
|
|
10
|
+
function base64urlToUint8Array(base64url) {
|
|
11
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
12
|
+
const pad = base64.length % 4 ? 4 - base64.length % 4 : 0;
|
|
13
|
+
const padded = base64 + "=".repeat(pad);
|
|
14
|
+
const binary = atob(padded);
|
|
15
|
+
const bytes = new Uint8Array(binary.length);
|
|
16
|
+
for (let i = 0; i < binary.length; i++) {
|
|
17
|
+
bytes[i] = binary.charCodeAt(i);
|
|
18
|
+
}
|
|
19
|
+
return bytes;
|
|
20
|
+
}
|
|
21
|
+
function arrayBufferToBase64(buffer) {
|
|
22
|
+
const bytes = new Uint8Array(buffer);
|
|
23
|
+
let binary = "";
|
|
24
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
25
|
+
binary += String.fromCharCode(bytes[i]);
|
|
26
|
+
}
|
|
27
|
+
return btoa(binary);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/auth/storage.ts
|
|
31
|
+
var MemoryStorage = class {
|
|
32
|
+
storage = /* @__PURE__ */ new Map();
|
|
33
|
+
getItem(key) {
|
|
34
|
+
return this.storage.get(key) || null;
|
|
35
|
+
}
|
|
36
|
+
setItem(key, value) {
|
|
37
|
+
this.storage.set(key, value);
|
|
38
|
+
}
|
|
39
|
+
removeItem(key) {
|
|
40
|
+
this.storage.delete(key);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Clear all items from memory storage
|
|
44
|
+
*/
|
|
45
|
+
clear() {
|
|
46
|
+
this.storage.clear();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get all keys in storage
|
|
50
|
+
*/
|
|
51
|
+
keys() {
|
|
52
|
+
return Array.from(this.storage.keys());
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get number of items in storage
|
|
56
|
+
*/
|
|
57
|
+
get size() {
|
|
58
|
+
return this.storage.size;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var LocalStorageAdapter = class {
|
|
62
|
+
fallback = null;
|
|
63
|
+
constructor() {
|
|
64
|
+
if (!this.isLocalStorageAvailable()) {
|
|
65
|
+
console.warn("[Storage] localStorage not available, falling back to memory storage");
|
|
66
|
+
this.fallback = new MemoryStorage();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
isLocalStorageAvailable() {
|
|
70
|
+
try {
|
|
71
|
+
const win = typeof globalThis !== "undefined" && globalThis.window;
|
|
72
|
+
const storage = win ? win.localStorage : void 0;
|
|
73
|
+
if (!storage) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const testKey = "__lumia_storage_test__";
|
|
77
|
+
storage.setItem(testKey, "test");
|
|
78
|
+
storage.removeItem(testKey);
|
|
79
|
+
return true;
|
|
80
|
+
} catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
getItem(key) {
|
|
85
|
+
console.log("[Storage] getItem called for key:", key);
|
|
86
|
+
if (this.fallback) {
|
|
87
|
+
console.log("[Storage] Using fallback memory storage");
|
|
88
|
+
return this.fallback.getItem(key);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const win = typeof globalThis !== "undefined" && globalThis.window;
|
|
92
|
+
const value = win?.localStorage?.getItem(key) || null;
|
|
93
|
+
console.log("[Storage] Read from localStorage:", {
|
|
94
|
+
key,
|
|
95
|
+
hasValue: !!value,
|
|
96
|
+
valueLength: value?.length,
|
|
97
|
+
allKeys: win?.localStorage ? Object.keys(win.localStorage) : []
|
|
98
|
+
});
|
|
99
|
+
return value;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error("[Storage] Error reading from localStorage:", error);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
setItem(key, value) {
|
|
106
|
+
console.log("[Storage] setItem called:", { key, valueLength: value.length });
|
|
107
|
+
if (this.fallback) {
|
|
108
|
+
console.log("[Storage] Using fallback memory storage for write");
|
|
109
|
+
this.fallback.setItem(key, value);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const win = typeof globalThis !== "undefined" && globalThis.window;
|
|
114
|
+
win?.localStorage?.setItem(key, value);
|
|
115
|
+
console.log("[Storage] Successfully wrote to localStorage");
|
|
116
|
+
const verification = win?.localStorage?.getItem(key);
|
|
117
|
+
if (!verification) {
|
|
118
|
+
console.error("[Storage] \u26A0\uFE0F VERIFICATION FAILED: Value not found after write!");
|
|
119
|
+
} else if (verification !== value) {
|
|
120
|
+
console.error("[Storage] \u26A0\uFE0F VERIFICATION FAILED: Value mismatch after write!");
|
|
121
|
+
} else {
|
|
122
|
+
console.log("[Storage] \u2705 Write verified successfully");
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error("[Storage] Error writing to localStorage:", error);
|
|
126
|
+
if (!this.fallback) {
|
|
127
|
+
this.fallback = new MemoryStorage();
|
|
128
|
+
this.fallback.setItem(key, value);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
removeItem(key) {
|
|
133
|
+
if (this.fallback) {
|
|
134
|
+
this.fallback.removeItem(key);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const win = typeof globalThis !== "undefined" && globalThis.window;
|
|
139
|
+
win?.localStorage?.removeItem(key);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("[Storage] Error removing from localStorage:", error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
async function storageGet(storage, key) {
|
|
146
|
+
const result = storage.getItem(key);
|
|
147
|
+
return result instanceof Promise ? await result : result;
|
|
148
|
+
}
|
|
149
|
+
async function storageSet(storage, key, value) {
|
|
150
|
+
const result = storage.setItem(key, value);
|
|
151
|
+
if (result instanceof Promise) {
|
|
152
|
+
await result;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function storageRemove(storage, key) {
|
|
156
|
+
const result = storage.removeItem(key);
|
|
157
|
+
if (result instanceof Promise) {
|
|
158
|
+
await result;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function getProjectId() {
|
|
162
|
+
if (typeof globalThis !== "undefined" && globalThis.window) {
|
|
163
|
+
return globalThis.window.__LUMIA_PROJECT_ID__;
|
|
164
|
+
}
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
function addProjectIdToUrl(url, projectId) {
|
|
168
|
+
try {
|
|
169
|
+
const pid = projectId || getProjectId();
|
|
170
|
+
if (pid) {
|
|
171
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
172
|
+
return `${url}${separator}projectId=${encodeURIComponent(pid)}`;
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
}
|
|
176
|
+
return url;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/auth/jwt.ts
|
|
180
|
+
var TOKEN_STORAGE_KEY = "lumia-jwt-tokens";
|
|
181
|
+
var USER_ID_KEY = "lumia-current-user-id";
|
|
182
|
+
var tssUrlProvider;
|
|
183
|
+
function configureJwtModule(config) {
|
|
184
|
+
if (config.tssUrl) {
|
|
185
|
+
tssUrlProvider = () => config.tssUrl;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
var BUILD_TSS_URL = "http://localhost:9256";
|
|
189
|
+
function getTssUrl() {
|
|
190
|
+
if (tssUrlProvider) {
|
|
191
|
+
return tssUrlProvider();
|
|
192
|
+
}
|
|
193
|
+
if (typeof globalThis !== "undefined" && globalThis.window) {
|
|
194
|
+
const services = globalThis.window.__LUMIA_SERVICES__;
|
|
195
|
+
if (services?.tssUrl) {
|
|
196
|
+
return services.tssUrl;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
{
|
|
200
|
+
return BUILD_TSS_URL;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
var JwtTokenManager = class {
|
|
204
|
+
tokens = null;
|
|
205
|
+
storage;
|
|
206
|
+
refreshPromise = null;
|
|
207
|
+
// Mutex for refresh operations
|
|
208
|
+
constructor(storage) {
|
|
209
|
+
this.storage = storage || new LocalStorageAdapter();
|
|
210
|
+
console.log("[JWT] JwtTokenManager initializing...");
|
|
211
|
+
this.loadTokensFromStorage();
|
|
212
|
+
}
|
|
213
|
+
async loadTokensFromStorage() {
|
|
214
|
+
try {
|
|
215
|
+
const stored = await this.storage.getItem(TOKEN_STORAGE_KEY);
|
|
216
|
+
console.log("[JWT] Loading tokens from storage:", !!stored);
|
|
217
|
+
if (stored) {
|
|
218
|
+
this.tokens = JSON.parse(stored);
|
|
219
|
+
console.log("[JWT] Parsed tokens:", {
|
|
220
|
+
hasAccessToken: !!this.tokens?.accessToken,
|
|
221
|
+
hasRefreshToken: !!this.tokens?.refreshToken,
|
|
222
|
+
userId: this.tokens?.userId,
|
|
223
|
+
expiresAt: this.tokens?.expiresAt,
|
|
224
|
+
currentTime: Date.now(),
|
|
225
|
+
timeToExpiry: this.tokens?.expiresAt ? (this.tokens.expiresAt - Date.now()) / 1e3 : "N/A"
|
|
226
|
+
});
|
|
227
|
+
if (this.tokens && this.isTokenExpired()) {
|
|
228
|
+
console.log("[JWT] Access token is expired");
|
|
229
|
+
if (this.tokens.refreshToken) {
|
|
230
|
+
console.log("[JWT] Refresh token available, will attempt renewal when needed");
|
|
231
|
+
} else {
|
|
232
|
+
console.log("[JWT] No refresh token available, clearing tokens");
|
|
233
|
+
await this.clearTokens();
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
console.log("[JWT] Access token is valid, keeping tokens");
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
console.log("[JWT] No tokens found in storage");
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error("[JWT] Error loading tokens from storage:", error);
|
|
243
|
+
await this.clearTokens();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async saveTokensToStorage() {
|
|
247
|
+
try {
|
|
248
|
+
if (this.tokens) {
|
|
249
|
+
const tokenString = JSON.stringify(this.tokens);
|
|
250
|
+
console.log("[JWT] Saving to storage with key:", TOKEN_STORAGE_KEY);
|
|
251
|
+
console.log("[JWT] Token data being saved:", {
|
|
252
|
+
hasAccessToken: !!this.tokens.accessToken,
|
|
253
|
+
hasRefreshToken: !!this.tokens.refreshToken,
|
|
254
|
+
userId: this.tokens.userId,
|
|
255
|
+
expiresAt: this.tokens.expiresAt,
|
|
256
|
+
tokenStringLength: tokenString.length
|
|
257
|
+
});
|
|
258
|
+
await this.storage.setItem(TOKEN_STORAGE_KEY, tokenString);
|
|
259
|
+
await this.storage.setItem(USER_ID_KEY, this.tokens.userId);
|
|
260
|
+
console.log("[JWT] Tokens saved to storage");
|
|
261
|
+
} else {
|
|
262
|
+
console.warn("[JWT] No tokens to save");
|
|
263
|
+
}
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error("[JWT] Failed to save tokens to storage:", error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async setTokens(response) {
|
|
269
|
+
console.log("[JWT] \u2705 setTokens() called - Stack trace:");
|
|
270
|
+
console.trace("[JWT] Set tokens stack trace");
|
|
271
|
+
console.log("[JWT] Setting tokens from response:", {
|
|
272
|
+
hasAccessToken: !!response.accessToken,
|
|
273
|
+
hasRefreshToken: !!response.refreshToken,
|
|
274
|
+
userId: response.userId,
|
|
275
|
+
expiresIn: response.expiresIn
|
|
276
|
+
});
|
|
277
|
+
const expiresAt = Date.now() + response.expiresIn * 1e3;
|
|
278
|
+
this.tokens = {
|
|
279
|
+
accessToken: response.accessToken,
|
|
280
|
+
refreshToken: response.refreshToken,
|
|
281
|
+
userId: response.userId,
|
|
282
|
+
expiresIn: response.expiresIn,
|
|
283
|
+
expiresAt,
|
|
284
|
+
hasKeyshare: response.hasKeyshare,
|
|
285
|
+
isNewUser: response.isNewUser,
|
|
286
|
+
avatar: response.avatar ?? null,
|
|
287
|
+
displayName: response.displayName ?? null
|
|
288
|
+
};
|
|
289
|
+
console.log("[JWT] Tokens object created");
|
|
290
|
+
await this.saveTokensToStorage();
|
|
291
|
+
console.log("[JWT] Tokens saved to storage successfully");
|
|
292
|
+
}
|
|
293
|
+
getAccessToken() {
|
|
294
|
+
if (!this.tokens) return null;
|
|
295
|
+
return this.tokens.accessToken;
|
|
296
|
+
}
|
|
297
|
+
getRefreshToken() {
|
|
298
|
+
return this.tokens?.refreshToken || null;
|
|
299
|
+
}
|
|
300
|
+
getUserId() {
|
|
301
|
+
return this.tokens?.userId || null;
|
|
302
|
+
}
|
|
303
|
+
getHasKeyshare() {
|
|
304
|
+
return this.tokens?.hasKeyshare ?? null;
|
|
305
|
+
}
|
|
306
|
+
getAvatar() {
|
|
307
|
+
return this.tokens?.avatar || null;
|
|
308
|
+
}
|
|
309
|
+
getDisplayName() {
|
|
310
|
+
return this.tokens?.displayName || null;
|
|
311
|
+
}
|
|
312
|
+
getTokens() {
|
|
313
|
+
return this.tokens;
|
|
314
|
+
}
|
|
315
|
+
async updateKeyshareStatus(hasKeyshare) {
|
|
316
|
+
if (this.tokens) {
|
|
317
|
+
this.tokens.hasKeyshare = hasKeyshare;
|
|
318
|
+
await this.saveTokensToStorage();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async updateDisplayName(displayName) {
|
|
322
|
+
if (this.tokens) {
|
|
323
|
+
this.tokens.displayName = displayName;
|
|
324
|
+
await this.saveTokensToStorage();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
isTokenExpired() {
|
|
328
|
+
if (!this.tokens) {
|
|
329
|
+
console.log("[JWT] No tokens available, considering expired");
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
const buffer = 30 * 1e3;
|
|
333
|
+
const now = Date.now();
|
|
334
|
+
const expiresAt = this.tokens.expiresAt;
|
|
335
|
+
const isExpired = now > expiresAt - buffer;
|
|
336
|
+
console.log("[JWT] Token expiry check:", {
|
|
337
|
+
currentTime: now,
|
|
338
|
+
expiresAt,
|
|
339
|
+
buffer,
|
|
340
|
+
timeToExpiry: (expiresAt - now) / 1e3,
|
|
341
|
+
isExpired
|
|
342
|
+
});
|
|
343
|
+
return isExpired;
|
|
344
|
+
}
|
|
345
|
+
isAuthenticated() {
|
|
346
|
+
if (!this.tokens) return false;
|
|
347
|
+
if (!this.isTokenExpired()) {
|
|
348
|
+
return !!this.tokens.accessToken;
|
|
349
|
+
}
|
|
350
|
+
return !!this.tokens.refreshToken;
|
|
351
|
+
}
|
|
352
|
+
async clearTokens() {
|
|
353
|
+
console.log("[JWT] \u26A0\uFE0F clearTokens() called - Stack trace:");
|
|
354
|
+
console.trace("[JWT] Clear tokens stack trace");
|
|
355
|
+
console.log("[JWT] Clearing tokens from memory and storage");
|
|
356
|
+
this.tokens = null;
|
|
357
|
+
await this.storage.removeItem(TOKEN_STORAGE_KEY);
|
|
358
|
+
await this.storage.removeItem(USER_ID_KEY);
|
|
359
|
+
}
|
|
360
|
+
async refreshAccessToken() {
|
|
361
|
+
if (this.refreshPromise) {
|
|
362
|
+
console.log("[JWT] Refresh already in progress, waiting for existing operation...");
|
|
363
|
+
return this.refreshPromise;
|
|
364
|
+
}
|
|
365
|
+
const refreshToken = this.getRefreshToken();
|
|
366
|
+
if (!refreshToken) {
|
|
367
|
+
console.warn("[JWT] No refresh token available for refresh");
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
console.log("[JWT] Starting new token refresh operation...");
|
|
371
|
+
this.refreshPromise = (async () => {
|
|
372
|
+
try {
|
|
373
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/refresh`), {
|
|
374
|
+
method: "POST",
|
|
375
|
+
headers: { "Content-Type": "application/json" },
|
|
376
|
+
body: JSON.stringify({ refreshToken })
|
|
377
|
+
});
|
|
378
|
+
if (!response.ok) {
|
|
379
|
+
console.log("[JWT] Token refresh failed with status:", response.status);
|
|
380
|
+
if (response.status === 401) {
|
|
381
|
+
try {
|
|
382
|
+
const errorData = await response.json();
|
|
383
|
+
console.log("[JWT] Refresh 401 Error details:", errorData);
|
|
384
|
+
switch (errorData.error_code) {
|
|
385
|
+
case "SESSION_NOT_FOUND":
|
|
386
|
+
console.log("[JWT] Refresh token session not found, clearing tokens");
|
|
387
|
+
await this.clearTokens();
|
|
388
|
+
return false;
|
|
389
|
+
case "INVALID_TOKEN":
|
|
390
|
+
default:
|
|
391
|
+
console.log("[JWT] Invalid refresh token, clearing tokens");
|
|
392
|
+
await this.clearTokens();
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
} catch (parseError) {
|
|
396
|
+
console.warn("[JWT] Could not parse refresh 401 error response:", parseError);
|
|
397
|
+
await this.clearTokens();
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
console.log("[JWT] Non-401 error during refresh, keeping tokens (might be network error)");
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const refreshResponse = await response.json();
|
|
406
|
+
console.log("[JWT] Token refresh successful, new expiry in:", refreshResponse.expiresIn, "seconds");
|
|
407
|
+
if (this.tokens) {
|
|
408
|
+
this.tokens.accessToken = refreshResponse.accessToken;
|
|
409
|
+
this.tokens.refreshToken = refreshResponse.refreshToken;
|
|
410
|
+
this.tokens.expiresIn = refreshResponse.expiresIn;
|
|
411
|
+
this.tokens.expiresAt = Date.now() + refreshResponse.expiresIn * 1e3;
|
|
412
|
+
await this.saveTokensToStorage();
|
|
413
|
+
console.log("[JWT] Refreshed tokens saved to storage");
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
console.error("[JWT] No existing tokens to update");
|
|
417
|
+
return false;
|
|
418
|
+
} catch (error) {
|
|
419
|
+
console.error("[JWT] Token refresh network error:", error);
|
|
420
|
+
return false;
|
|
421
|
+
} finally {
|
|
422
|
+
this.refreshPromise = null;
|
|
423
|
+
console.log("[JWT] Refresh operation completed, mutex cleared");
|
|
424
|
+
}
|
|
425
|
+
})();
|
|
426
|
+
return this.refreshPromise;
|
|
427
|
+
}
|
|
428
|
+
getAuthHeader() {
|
|
429
|
+
const token = this.getAccessToken();
|
|
430
|
+
return token ? `Bearer ${token}` : null;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
var jwtTokenManager = new JwtTokenManager();
|
|
434
|
+
function createJwtTokenManager(storage) {
|
|
435
|
+
return new JwtTokenManager(storage);
|
|
436
|
+
}
|
|
437
|
+
async function logout(manager = jwtTokenManager) {
|
|
438
|
+
try {
|
|
439
|
+
const authHeader = manager.getAuthHeader();
|
|
440
|
+
if (authHeader) {
|
|
441
|
+
await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/logout`), {
|
|
442
|
+
method: "POST",
|
|
443
|
+
headers: {
|
|
444
|
+
Authorization: authHeader,
|
|
445
|
+
"Content-Type": "application/json"
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.error("[JWT] Logout error:", error);
|
|
451
|
+
} finally {
|
|
452
|
+
await manager.clearTokens();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function verifyToken(manager = jwtTokenManager) {
|
|
456
|
+
const authHeader = manager.getAuthHeader();
|
|
457
|
+
if (!authHeader) {
|
|
458
|
+
console.log("[JWT] No auth header available for verification");
|
|
459
|
+
return { valid: false };
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/verify`), {
|
|
463
|
+
method: "GET",
|
|
464
|
+
headers: { Authorization: authHeader }
|
|
465
|
+
});
|
|
466
|
+
if (!response.ok) {
|
|
467
|
+
console.log("[JWT] Token verification failed:", response.status);
|
|
468
|
+
if (response.status === 401) {
|
|
469
|
+
try {
|
|
470
|
+
const errorData = await response.json();
|
|
471
|
+
console.log("[JWT] 401 Error details:", errorData);
|
|
472
|
+
switch (errorData.error_code) {
|
|
473
|
+
case "TOKEN_EXPIRED":
|
|
474
|
+
console.log("[JWT] Access token expired, attempting refresh...");
|
|
475
|
+
const refreshSuccess = await manager.refreshAccessToken();
|
|
476
|
+
if (refreshSuccess) {
|
|
477
|
+
console.log("[JWT] Token refreshed successfully, retrying verification");
|
|
478
|
+
return await verifyToken(manager);
|
|
479
|
+
} else {
|
|
480
|
+
console.log("[JWT] Token refresh failed, clearing tokens");
|
|
481
|
+
await manager.clearTokens();
|
|
482
|
+
return { valid: false };
|
|
483
|
+
}
|
|
484
|
+
case "SESSION_NOT_FOUND":
|
|
485
|
+
console.log("[JWT] Session not found or revoked, clearing tokens");
|
|
486
|
+
await manager.clearTokens();
|
|
487
|
+
return { valid: false };
|
|
488
|
+
case "INVALID_TOKEN":
|
|
489
|
+
default:
|
|
490
|
+
console.log("[JWT] Invalid token, clearing tokens");
|
|
491
|
+
await manager.clearTokens();
|
|
492
|
+
return { valid: false };
|
|
493
|
+
}
|
|
494
|
+
} catch (parseError) {
|
|
495
|
+
console.warn("[JWT] Could not parse 401 error response:", parseError);
|
|
496
|
+
await manager.clearTokens();
|
|
497
|
+
return { valid: false };
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
console.log("[JWT] Non-401 error during verification, keeping tokens");
|
|
501
|
+
return { valid: false };
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const verifyResponse = await response.json();
|
|
505
|
+
console.log("[JWT] Token verification successful:", verifyResponse);
|
|
506
|
+
if (verifyResponse.valid) {
|
|
507
|
+
if (typeof verifyResponse.hasKeyshare === "boolean") {
|
|
508
|
+
await manager.updateKeyshareStatus(verifyResponse.hasKeyshare);
|
|
509
|
+
}
|
|
510
|
+
if (manager.getTokens()) {
|
|
511
|
+
if (verifyResponse.displayName !== void 0) {
|
|
512
|
+
await manager.updateDisplayName(verifyResponse.displayName);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return verifyResponse;
|
|
517
|
+
} catch (error) {
|
|
518
|
+
console.error("[JWT] Token verification network error:", error);
|
|
519
|
+
return { valid: false };
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async function ensureValidToken(manager = jwtTokenManager) {
|
|
523
|
+
console.log("[JWT] ensureValidToken() called - Stack trace:");
|
|
524
|
+
console.trace("[JWT] ensureValidToken stack trace");
|
|
525
|
+
console.log("[JWT] Checking token validity...");
|
|
526
|
+
if (manager.isAuthenticated() && !manager.isTokenExpired()) {
|
|
527
|
+
console.log("[JWT] Access token is valid");
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
console.log("[JWT] Access token expired or missing, attempting refresh...");
|
|
531
|
+
const refreshToken = manager.getRefreshToken();
|
|
532
|
+
if (refreshToken) {
|
|
533
|
+
console.log("[JWT] Refresh token available, attempting to refresh access token");
|
|
534
|
+
const refreshSuccess = await manager.refreshAccessToken();
|
|
535
|
+
console.log("[JWT] Refresh attempt result:", refreshSuccess);
|
|
536
|
+
return refreshSuccess;
|
|
537
|
+
}
|
|
538
|
+
console.log("[JWT] No refresh token available, user needs to re-authenticate");
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
async function authenticatedFetch(url, options = {}, manager = jwtTokenManager) {
|
|
542
|
+
const hasValidToken = await ensureValidToken(manager);
|
|
543
|
+
if (!hasValidToken) {
|
|
544
|
+
throw new Error("No valid authentication token available");
|
|
545
|
+
}
|
|
546
|
+
const authHeader = manager.getAuthHeader();
|
|
547
|
+
if (!authHeader) {
|
|
548
|
+
throw new Error("Failed to get authentication header");
|
|
549
|
+
}
|
|
550
|
+
const urlWithProjectId = addProjectIdToUrl(url);
|
|
551
|
+
const requestOptions = {
|
|
552
|
+
...options,
|
|
553
|
+
headers: {
|
|
554
|
+
...options.headers,
|
|
555
|
+
Authorization: authHeader,
|
|
556
|
+
"Content-Type": "application/json"
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
const response = await fetch(urlWithProjectId, requestOptions);
|
|
560
|
+
if (response.status === 401) {
|
|
561
|
+
const refreshSuccess = await manager.refreshAccessToken();
|
|
562
|
+
if (refreshSuccess) {
|
|
563
|
+
const newAuthHeader = manager.getAuthHeader();
|
|
564
|
+
if (newAuthHeader) {
|
|
565
|
+
requestOptions.headers = {
|
|
566
|
+
...requestOptions.headers,
|
|
567
|
+
Authorization: newAuthHeader
|
|
568
|
+
};
|
|
569
|
+
return fetch(urlWithProjectId, requestOptions);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return response;
|
|
574
|
+
}
|
|
575
|
+
async function loginWithUserId(userId) {
|
|
576
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/login`), {
|
|
577
|
+
method: "POST",
|
|
578
|
+
headers: { "Content-Type": "application/json" },
|
|
579
|
+
body: JSON.stringify({ userId })
|
|
580
|
+
});
|
|
581
|
+
if (!response.ok) {
|
|
582
|
+
const errorText = await response.text().catch(() => "Login failed");
|
|
583
|
+
throw new Error(`Login failed: ${response.status} ${errorText}`);
|
|
584
|
+
}
|
|
585
|
+
const loginResponse = await response.json();
|
|
586
|
+
await jwtTokenManager.setTokens(loginResponse);
|
|
587
|
+
return loginResponse;
|
|
588
|
+
}
|
|
589
|
+
async function loginWithEmail(email, code) {
|
|
590
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/email/verify-code`), {
|
|
591
|
+
method: "POST",
|
|
592
|
+
headers: { "Content-Type": "application/json" },
|
|
593
|
+
body: JSON.stringify({ email, code })
|
|
594
|
+
});
|
|
595
|
+
if (!response.ok) {
|
|
596
|
+
const errorText = await response.text().catch(() => "Email verification failed");
|
|
597
|
+
throw new Error(`Email verification failed: ${response.status} ${errorText}`);
|
|
598
|
+
}
|
|
599
|
+
const loginResponse = await response.json();
|
|
600
|
+
await jwtTokenManager.setTokens(loginResponse);
|
|
601
|
+
return loginResponse;
|
|
602
|
+
}
|
|
603
|
+
async function loginWithTelegram(telegramData) {
|
|
604
|
+
const response = await fetch(addProjectIdToUrl(`${getTssUrl()}/api/auth/telegram/login`), {
|
|
605
|
+
method: "POST",
|
|
606
|
+
headers: { "Content-Type": "application/json" },
|
|
607
|
+
body: JSON.stringify(telegramData)
|
|
608
|
+
});
|
|
609
|
+
if (!response.ok) {
|
|
610
|
+
const errorText = await response.text().catch(() => "Telegram login failed");
|
|
611
|
+
throw new Error(`Telegram login failed: ${response.status} ${errorText}`);
|
|
612
|
+
}
|
|
613
|
+
const loginResponse = await response.json();
|
|
614
|
+
await jwtTokenManager.setTokens(loginResponse);
|
|
615
|
+
return loginResponse;
|
|
616
|
+
}
|
|
617
|
+
async function syncKeyshareStatus(manager = jwtTokenManager) {
|
|
618
|
+
try {
|
|
619
|
+
const verification = await verifyToken(manager);
|
|
620
|
+
if (verification?.valid && typeof verification.hasKeyshare === "boolean") {
|
|
621
|
+
return verification.hasKeyshare;
|
|
622
|
+
}
|
|
623
|
+
return false;
|
|
624
|
+
} catch {
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
export { JwtTokenManager, LocalStorageAdapter, MemoryStorage, arrayBufferToBase64, arrayBufferToBase64url, authenticatedFetch, base64urlToUint8Array, configureJwtModule, createJwtTokenManager, ensureValidToken, jwtTokenManager, loginWithEmail, loginWithTelegram, loginWithUserId, logout, storageGet, storageRemove, storageSet, syncKeyshareStatus, verifyToken };
|
|
630
|
+
//# sourceMappingURL=index.js.map
|
|
631
|
+
//# sourceMappingURL=index.js.map
|