@transmitsecurity/platform-web-sdk 1.18.0 → 1.18.2

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/webauthn.js CHANGED
@@ -1,1983 +1 @@
1
-
2
- // Global polyfills for browser compatibility
3
- (function() {
4
- if (typeof globalThis !== 'undefined') return;
5
- if (typeof window !== 'undefined') {
6
- window.globalThis = window;
7
- window.global = window;
8
- } else if (typeof self !== 'undefined') {
9
- self.globalThis = self;
10
- self.global = self;
11
- }
12
- })();
13
- const MODULE_INITIALIZED = Symbol('MODULE_INITIALIZED');
14
-
15
- const events$1 = new Map();
16
- function on(eventName, method) {
17
- var _a;
18
- if (events$1.has(eventName)) {
19
- (_a = events$1.get(eventName)) === null || _a === void 0 ? void 0 : _a.push(method);
20
- }
21
- else {
22
- events$1.set(eventName, [method]);
23
- }
24
- }
25
- function off(eventName, method) {
26
- const eventArray = events$1.get(eventName);
27
- if (!eventArray) {
28
- return;
29
- }
30
- const methodIndex = eventArray.indexOf(method);
31
- if (methodIndex === -1) {
32
- return;
33
- }
34
- eventArray.splice(methodIndex, 1);
35
- }
36
- function emit(eventName, eventData) {
37
- var _a;
38
- (_a = events$1.get(eventName)) === null || _a === void 0 ? void 0 : _a.forEach(safeCallback((callbackMethod) => callbackMethod(eventData)));
39
- }
40
- function safeCallback(callback) {
41
- return (...args) => {
42
- try {
43
- return callback(...args);
44
- }
45
- catch (e) {
46
- console.log(e);
47
- }
48
- };
49
- }
50
-
51
- let initConfig = null;
52
- function getInitConfig() {
53
- return initConfig;
54
- }
55
- function setInitConfig(config) {
56
- initConfig = config;
57
- }
58
-
59
- var moduleMetadata = /*#__PURE__*/Object.freeze({
60
- __proto__: null,
61
- getInitConfig: getInitConfig,
62
- get initConfig () { return initConfig; },
63
- setInitConfig: setInitConfig
64
- });
65
-
66
- function initialize(params) {
67
- setInitConfig(params);
68
- emit(MODULE_INITIALIZED, undefined);
69
- }
70
-
71
- var mainEntry = /*#__PURE__*/Object.freeze({
72
- __proto__: null,
73
- initialize: initialize
74
- });
75
-
76
- function bindMethods(agent, methods) {
77
- return Object.entries(methods).reduce((result, [key, value]) => ({
78
- ...result,
79
- [key]: Agent.isPrototypeOf(value)
80
- ? new value(agent.slug)
81
- : typeof value === 'function'
82
- ? value.bind(agent)
83
- : typeof value === 'object' && !Array.isArray(value) && !!value
84
- ? bindMethods(agent, value)
85
- : value,
86
- }), {});
87
- }
88
- class Agent {
89
- constructor(slug) {
90
- this.slug = slug;
91
- }
92
- static create(method) {
93
- return class extends Agent {
94
- constructor(slug) {
95
- super(slug);
96
- Object.assign(this, bindMethods(this, method(this)));
97
- }
98
- };
99
- }
100
- }
101
-
102
- var agent$1 = /*#__PURE__*/Object.freeze({
103
- __proto__: null,
104
- Agent: Agent
105
- });
106
-
107
- var events = /*#__PURE__*/Object.freeze({
108
- __proto__: null,
109
- MODULE_INITIALIZED: MODULE_INITIALIZED,
110
- emit: emit,
111
- off: off,
112
- on: on
113
- });
114
-
115
- function safeParse(string) {
116
- if (!string)
117
- return {};
118
- try {
119
- return JSON.parse(string);
120
- }
121
- catch (e) {
122
- return {};
123
- }
124
- }
125
- /** @return tuple of `[value, newObject]`
126
- * `value` is `object.path[0].path[1]` etc. while every node in the way is guaranteed to be an object
127
- * `newObject` for given `object` will be itself while the full path to `value` added to it if wasn't already exists
128
- *
129
- * @note - the original `object` might be modified, but you should always use the returned `newObject` for
130
- * case the original one was a premitive or an array.
131
- */
132
- function safeGetObject(object, path) {
133
- const newObject = !object || typeof object !== 'object' || Array.isArray(object) ? {} : object;
134
- return [
135
- path.reduce((object, key) => {
136
- if (key in object) {
137
- const next = object[key];
138
- if (next !== null && typeof next === 'object' && !Array.isArray(next)) {
139
- return next;
140
- }
141
- }
142
- const newValue = {};
143
- object[key] = newValue;
144
- return newValue;
145
- }, newObject),
146
- newObject,
147
- ];
148
- }
149
- function safeHas(object, path) {
150
- let currentObject = object;
151
- return path.every((key) => {
152
- if (!currentObject ||
153
- typeof currentObject !== 'object' ||
154
- Array.isArray(currentObject) ||
155
- !(key in currentObject)) {
156
- return false;
157
- }
158
- currentObject = currentObject[key];
159
- return true;
160
- }, object);
161
- }
162
-
163
- const COMMON_STORAGE_KEY = 'tsec';
164
- const GENERAL_ID_KEY = 'general';
165
- function getClientKey(isGeneral) {
166
- return isGeneral ? GENERAL_ID_KEY : initConfig.clientId;
167
- }
168
- function getStoredObject(sessionOnly) {
169
- const storage = sessionOnly ? sessionStorage : localStorage;
170
- return safeParse(storage.getItem(COMMON_STORAGE_KEY));
171
- }
172
- function setStoredObject(sessionOnly, callback) {
173
- const storage = sessionOnly ? sessionStorage : localStorage;
174
- const storedObject = getStoredObject(sessionOnly);
175
- const newValue = callback(storedObject);
176
- storage.setItem(COMMON_STORAGE_KEY, JSON.stringify(newValue));
177
- }
178
- /**
179
- * Storage module handles local storage and session storgae for multyple modules in
180
- * same storage key, with JSON serialization. It stores data in 'tsec' key, as an
181
- * object with that structure:
182
- * { [moduleSlug]: { [clientId | 'general']: { [key]: value } } }
183
- */
184
- function setValue(key, value, options = {}) {
185
- const idKey = getClientKey(!!options.isGeneral);
186
- setStoredObject(!!options.sessionOnly, (storedObject) => {
187
- const [lastLevel, newObject] = safeGetObject(storedObject, [this.slug.toString(), idKey]);
188
- lastLevel[key] = value;
189
- return newObject;
190
- });
191
- }
192
- function removeValue(key, options = {}) {
193
- const idKey = getClientKey(!!options.isGeneral);
194
- setStoredObject(!!options.sessionOnly, (storedObject) => {
195
- const [lastLevel, newObject] = safeGetObject(storedObject, [this.slug.toString(), idKey]);
196
- delete lastLevel[key];
197
- return newObject;
198
- });
199
- }
200
- function getValue(key, options = {}) {
201
- const idKey = getClientKey(!!options.isGeneral);
202
- const storedObject = getStoredObject(!!options.sessionOnly);
203
- const [lastLevel] = safeGetObject(storedObject, [this.slug.toString(), idKey]);
204
- return lastLevel[key];
205
- }
206
- function hasValue(key, options = {}) {
207
- const idKey = getClientKey(!!options.isGeneral);
208
- const storedObject = getStoredObject(!!options.sessionOnly);
209
- return safeHas(storedObject, [this.slug.toString(), idKey, key]);
210
- }
211
-
212
- var storage = /*#__PURE__*/Object.freeze({
213
- __proto__: null,
214
- COMMON_STORAGE_KEY: COMMON_STORAGE_KEY,
215
- GENERAL_ID_KEY: GENERAL_ID_KEY,
216
- getValue: getValue,
217
- hasValue: hasValue,
218
- removeValue: removeValue,
219
- setValue: setValue
220
- });
221
-
222
- const ASYMMETRIC_ENCRYPTION_ALGORITHM = 'RSA-OAEP';
223
- const ASYMMETRIC_SIGN_ALGORITHM = 'RSA-PSS';
224
- const generateKeyPair = async (algorithm, usages) => {
225
- return await window.crypto.subtle.generateKey({
226
- name: algorithm,
227
- modulusLength: 2048,
228
- publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
229
- hash: 'SHA-256',
230
- }, false, // setting the private key non-extractable
231
- usages);
232
- };
233
- const generateRSAKeyPair = async () => {
234
- return await generateKeyPair(ASYMMETRIC_ENCRYPTION_ALGORITHM, ['encrypt', 'decrypt']);
235
- };
236
- const generateRSASignKeyPair = async () => {
237
- return await generateKeyPair(ASYMMETRIC_SIGN_ALGORITHM, ['sign']);
238
- };
239
- const signAssymetric = async (privateKey, message) => {
240
- const encoded = new TextEncoder().encode(message);
241
- const signature = await window.crypto.subtle.sign({
242
- name: ASYMMETRIC_SIGN_ALGORITHM,
243
- saltLength: 32,
244
- }, privateKey, encoded);
245
- return signature;
246
- };
247
- const verifyAssymetric = async (publicKey, message, signature) => {
248
- const encoded = new TextEncoder().encode(message);
249
- const isValid = await window.crypto.subtle.verify(ASYMMETRIC_SIGN_ALGORITHM, publicKey, signature, encoded);
250
- return isValid;
251
- };
252
-
253
- /**
254
- * @param slug - product name (like 'drs'/'idv' or 'platform' for a global platform shared storage)
255
- * @param dbName - database name, concatinated later after clientId
256
- * @param dbVersion - our own database versioning, note that for any table addition/deletion dbVersion must be bumped - DON'T CHANGE IT IF NOT REALLY NECESSARY.
257
- * @description The database different situations are covered here:
258
- - database wasn't created yet on the user's browser
259
- - database was created, but currently closed before we use it
260
- - database is already opened by another module (extension / this sdk), and requested indexedDB.open with the same version
261
- - database is already opened with different version by another module - pending (promise) until the previous transaction will be closed - then executing
262
- */
263
- class IndexedDBClient {
264
- constructor(slug, dbName, dbVersion) {
265
- this.slug = slug;
266
- this.dbName = dbName;
267
- this.dbVersion = dbVersion;
268
- }
269
- queryObjectStore(objectStoreName, queryStore, options = {}) {
270
- const { attemptToRecoverDB = true } = options;
271
- // One of those databases is supported in any device/browser
272
- const indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
273
- const databaseName = `${this.slug}:${this.dbName}`;
274
- // make it product scoped in case multiple sdks for different products could work in parallel
275
- const openRequest = indexedDB.open(databaseName, this.dbVersion || 1); // Opening (or creating) the database
276
- openRequest.onupgradeneeded = () => {
277
- var _a;
278
- const db = openRequest.result;
279
- if (((_a = db === null || db === void 0 ? void 0 : db.objectStoreNames) === null || _a === void 0 ? void 0 : _a.contains) && !db.objectStoreNames.contains(objectStoreName)) { // if there's no `tableName` store
280
- db.createObjectStore(objectStoreName, { keyPath: 'key' });
281
- }
282
- };
283
- openRequest.onsuccess = () => {
284
- const db = openRequest.result;
285
- let transaction;
286
- try {
287
- transaction = db.transaction(objectStoreName, (options === null || options === void 0 ? void 0 : options.operation) || 'readwrite');
288
- }
289
- catch (error) {
290
- // There is a Safari-specific race condition - the database is created, but the object store is missing.
291
- // It happens when a user stops the script during store creation (e.g. by refreshing the page).
292
- // We recover by deleting the broken database and recreating it with a proper schema.
293
- // There is only one attempt to recover.
294
- if (attemptToRecoverDB && error instanceof DOMException && error.name === 'NotFoundError') {
295
- db.close();
296
- const deleteRequest = indexedDB.deleteDatabase(databaseName);
297
- deleteRequest.onsuccess = () => {
298
- this.queryObjectStore(objectStoreName, queryStore, { ...options, attemptToRecoverDB: false });
299
- };
300
- return;
301
- }
302
- else {
303
- throw error;
304
- }
305
- }
306
- const store = transaction.objectStore(objectStoreName);
307
- queryStore(store);
308
- // Closing the db when the transaction is done
309
- transaction.oncomplete = () => {
310
- db.close();
311
- };
312
- };
313
- }
314
- put(tableName, key, object) {
315
- return new Promise((res, rej) => {
316
- this.queryObjectStore(tableName, (objectStore) => {
317
- const request = objectStore.put({ key, value: object });
318
- request.onsuccess = () => {
319
- res(request.result);
320
- };
321
- request.onerror = (err) => {
322
- rej('Failed adding item to objectStore, err: ' + err);
323
- };
324
- });
325
- });
326
- }
327
- add(tableName, key, object) {
328
- return new Promise((res, rej) => {
329
- this.queryObjectStore(tableName, (objectStore) => {
330
- const request = objectStore.add({ key, value: object });
331
- request.onsuccess = () => {
332
- res(request.result);
333
- };
334
- request.onerror = (err) => {
335
- const error = err.target.error;
336
- rej(error);
337
- };
338
- });
339
- });
340
- }
341
- get(tableName, key) {
342
- return new Promise((res, rej) => {
343
- this.queryObjectStore(tableName, (objectStore) => {
344
- const request = objectStore.get(key);
345
- request.onsuccess = () => {
346
- var _a;
347
- if (request.result) {
348
- // since it can trigger 'request.onsuccess' also when the objectStore exist but no such item found (`request.result` would be undefined)
349
- res((_a = request.result) === null || _a === void 0 ? void 0 : _a.value);
350
- }
351
- else {
352
- res(undefined);
353
- }
354
- };
355
- request.onerror = (err) => {
356
- rej('Failed adding item to objectStore, err: ' + err);
357
- };
358
- });
359
- });
360
- }
361
- getAll(tableName, count) {
362
- return new Promise((res, rej) => {
363
- this.queryObjectStore(tableName, (objectStore) => {
364
- const request = objectStore.getAll(null, count);
365
- request.onsuccess = () => {
366
- if (request.result) {
367
- const itemsList = request.result;
368
- if (itemsList === null || itemsList === void 0 ? void 0 : itemsList.length) {
369
- res(itemsList.map((item) => item === null || item === void 0 ? void 0 : item.value));
370
- }
371
- else {
372
- res(itemsList);
373
- }
374
- }
375
- else {
376
- res([]);
377
- }
378
- };
379
- request.onerror = (err) => {
380
- rej('Failed getting items, err: ' + err);
381
- };
382
- });
383
- });
384
- }
385
- delete(tableName, key) {
386
- return new Promise((res, rej) => {
387
- this.queryObjectStore(tableName, (objectStore) => {
388
- const request = objectStore.delete(key);
389
- request.onsuccess = () => {
390
- res();
391
- };
392
- request.onerror = (err) => {
393
- rej(`Failed deleting key: '${key}' from objectStore, err: ` + err);
394
- };
395
- });
396
- });
397
- }
398
- clear(tableName) {
399
- return new Promise((res, rej) => {
400
- this.queryObjectStore(tableName, (objectStore) => {
401
- const request = objectStore.clear();
402
- request.onsuccess = () => {
403
- res();
404
- };
405
- request.onerror = (err) => {
406
- rej('Failed clearing objectStore, err: ' + err);
407
- };
408
- });
409
- });
410
- }
411
- }
412
-
413
- const PLATFORM_GLOBAL_SLUG = 'platform';
414
- const DEFAULT_KEYSTORE_NAME = 'identifiers_store';
415
- const DEFAULT_DATABASE_NAME = 'ts_crypto_binding';
416
- const DEFAULT_DB_VERSION = 1;
417
- const PLATFORM_GLOBAL_KEYS_DB_VERSION = 1; // Change this only when the platform db-version changes, it will effect all products
418
- const ROTATED_KEYS_SLOT = 'rotated';
419
- const ROTATED_KEYS_SLOT_PENDING = 'rotated_pending';
420
- const EXPIRY_DAYS_THRESHOLD = 30; // The number of days before the expiration of the current key to trigger the rotation
421
- const INIT_ROTATION_RESPONSE = 'init';
422
- const COMPLETED_ROTATION_RESPONSE = 'completed';
423
- const RSA_PUBLIC_KEY_TYPE = 'RSA2048';
424
- const VALID_ROTATION_RESPONSES = [INIT_ROTATION_RESPONSE, COMPLETED_ROTATION_RESPONSE];
425
- /**
426
- * @param keysType - the purpose of the keys, will use different key generator
427
- * @param options - typeof CryptoBindingOptions
428
- */
429
- class CryptoBinding {
430
- constructor(agent, keysType = 'sign', options) {
431
- var _a, _b, _c, _d;
432
- this.agent = agent;
433
- this.keysType = keysType;
434
- this.options = options;
435
- this._extractingKeysPromise = null;
436
- const isGlobal = !((_a = this.options) === null || _a === void 0 ? void 0 : _a.productScope);
437
- this.keysDatabaseName = isGlobal || !((_b = this.options) === null || _b === void 0 ? void 0 : _b.indexedDBName) ? DEFAULT_DATABASE_NAME : this.options.indexedDBName;
438
- this.dbVersion = isGlobal ? PLATFORM_GLOBAL_KEYS_DB_VERSION : (((_c = this.options) === null || _c === void 0 ? void 0 : _c.dbVersion) || DEFAULT_DB_VERSION);
439
- this.keysStoreName = isGlobal || !((_d = this.options) === null || _d === void 0 ? void 0 : _d.keysStoreName) ? DEFAULT_KEYSTORE_NAME : this.options.keysStoreName;
440
- this.indexedDBClient = new IndexedDBClient(isGlobal ? PLATFORM_GLOBAL_SLUG : agent.slug, this.keysDatabaseName, this.dbVersion);
441
- // created a fallback indexedDBClient for crypto-keys migration from old versions (clientId dependent on the dbName):
442
- this.indexedDBClientFallback = new IndexedDBClient((isGlobal ? PLATFORM_GLOBAL_SLUG : agent.slug) + `:${initConfig.clientId}`, this.keysDatabaseName, this.dbVersion);
443
- }
444
- getKeysRecordKey() {
445
- return `${this.keysType}_keys`;
446
- }
447
- getRotatedKeysRecordKey() {
448
- return `${ROTATED_KEYS_SLOT}_${this.keysType}_keys`;
449
- }
450
- getRotatedKeysRecordKeyPending() {
451
- return `${ROTATED_KEYS_SLOT_PENDING}_${this.keysType}_keys`;
452
- }
453
- arrayBufferToBase64(arrayBuffer) {
454
- return window.btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
455
- }
456
- async getPKRepresentations(publicKey) {
457
- const exportedKey = await crypto.subtle.exportKey('spki', publicKey);
458
- return { arrayBufferKey: exportedKey, base64Key: this.arrayBufferToBase64(exportedKey) };
459
- }
460
- async generateKeyPair() {
461
- if (this.keysType == 'sign') {
462
- return await generateRSASignKeyPair();
463
- }
464
- return await generateRSAKeyPair();
465
- }
466
- async calcKeyIdentifier(publicKeyExported) {
467
- const hashBuffer = await crypto.subtle.digest("SHA-256", publicKeyExported);
468
- const hashArray = Array.from(new Uint8Array(hashBuffer));
469
- const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
470
- return hashHex;
471
- }
472
- async extractKeysData() {
473
- // if an extraction is already in progress, return the existing promise
474
- if (this._extractingKeysPromise) {
475
- return this._extractingKeysPromise;
476
- }
477
- this._extractingKeysPromise = (async () => {
478
- var _a, _b;
479
- const keysData = ((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.keyRotation) === null || _b === void 0 ? void 0 : _b.isEnabled)
480
- ? await this.getRotatedKeysData()
481
- : await this.getKeysData();
482
- // update the cache to prevent stale data
483
- const { base64Key } = await this.getPKRepresentations(keysData.publicKey);
484
- this.publicKeyBase64 = base64Key;
485
- this.keyIdentifier = keysData.keyIdentifier;
486
- return keysData;
487
- })();
488
- try {
489
- return await this._extractingKeysPromise;
490
- }
491
- finally {
492
- // reset the promise once done to allow future extractions if needed
493
- this._extractingKeysPromise = null;
494
- }
495
- }
496
- async generateKeyPairData(keyIdentifier) {
497
- const keys = await this.generateKeyPair();
498
- const { arrayBufferKey } = await this.getPKRepresentations(keys.publicKey);
499
- const keyPairIdentifier = keyIdentifier || (await this.calcKeyIdentifier(arrayBufferKey));
500
- const keysData = {
501
- ...keys,
502
- keyIdentifier: keyPairIdentifier,
503
- createdDate: Date.now(),
504
- };
505
- return keysData;
506
- }
507
- shouldKeyBeRotated(keysData) {
508
- var _a;
509
- const keyRotation = (_a = this.options) === null || _a === void 0 ? void 0 : _a.keyRotation;
510
- if (!(keyRotation === null || keyRotation === void 0 ? void 0 : keyRotation.isEnabled) || !keyRotation.expiryDays || keyRotation.startedAt === undefined) {
511
- return false;
512
- }
513
- const expiryDaysMilliseconds = keyRotation.expiryDays * 24 * 60 * 60 * 1000;
514
- const expiryDaysThresholdMilliseconds = EXPIRY_DAYS_THRESHOLD * 24 * 60 * 60 * 1000;
515
- // Count time from:
516
- // - rotation start, if the key was created before rotation was enabled
517
- // - key creation, if it was created after rotation was enabled
518
- const referenceTimestamp = keysData.createdDate && keysData.createdDate >= keyRotation.startedAt
519
- ? keysData.createdDate
520
- : keyRotation.startedAt;
521
- return Date.now() - referenceTimestamp > expiryDaysMilliseconds - expiryDaysThresholdMilliseconds;
522
- }
523
- async extractMainKeysData() {
524
- return await this.indexedDBClient.get(this.keysStoreName, this.getKeysRecordKey());
525
- }
526
- async extractFallbackMainKeysData() {
527
- return await this.indexedDBClientFallback.get(this.keysStoreName, this.getKeysRecordKey());
528
- }
529
- async extractRotatedKeysData() {
530
- return await this.indexedDBClient.get(this.keysStoreName, this.getRotatedKeysRecordKey());
531
- }
532
- async extractPendingRotatedKeysData() {
533
- return await this.indexedDBClient.get(this.keysStoreName, this.getRotatedKeysRecordKeyPending());
534
- }
535
- async saveKeyData(recordKey, keysDataToSave) {
536
- try {
537
- await this.indexedDBClient.add(this.keysStoreName, recordKey, keysDataToSave);
538
- return keysDataToSave;
539
- }
540
- catch (error) {
541
- if (error instanceof DOMException && error.name === 'ConstraintError') {
542
- // duplicate key error, retrieve existing key data
543
- const existingKey = (await this.indexedDBClient.get(this.keysStoreName, recordKey));
544
- if (existingKey) {
545
- return existingKey;
546
- }
547
- }
548
- throw error;
549
- }
550
- }
551
- async getKeysData() {
552
- const recordKey = this.getKeysRecordKey();
553
- let keysData = await this.extractMainKeysData();
554
- if (keysData) {
555
- return keysData;
556
- }
557
- keysData = await this.extractFallbackMainKeysData();
558
- if (keysData) {
559
- return this.saveKeyData(recordKey, keysData);
560
- }
561
- const newKeysData = await this.generateKeyPairData();
562
- return this.saveKeyData(recordKey, newKeysData);
563
- }
564
- async getOrCreateRotatedKeys() {
565
- let currentRotatedKeys = await this.extractRotatedKeysData();
566
- if (!currentRotatedKeys) {
567
- const rotatedRecordKey = this.getRotatedKeysRecordKey();
568
- const mainSlotKeys = await this.getKeysData();
569
- const rotatedKey = {
570
- ...mainSlotKeys,
571
- createdDate: mainSlotKeys.createdDate || Date.now(),
572
- };
573
- currentRotatedKeys = await this.saveKeyData(rotatedRecordKey, rotatedKey);
574
- }
575
- return currentRotatedKeys;
576
- }
577
- async getRotatedKeysData() {
578
- const currentRotatedKeys = await this.getOrCreateRotatedKeys();
579
- if (this.shouldKeyBeRotated(currentRotatedKeys)) {
580
- const pendingRotatedKeys = await this.extractPendingRotatedKeysData();
581
- if (!pendingRotatedKeys) {
582
- const pendingRecordKey = this.getRotatedKeysRecordKeyPending();
583
- const newPendingKeys = await this.generateKeyPairData(currentRotatedKeys.keyIdentifier);
584
- await this.saveKeyData(pendingRecordKey, newPendingKeys);
585
- }
586
- }
587
- return currentRotatedKeys;
588
- }
589
- async getPublicData() {
590
- if (!this.publicKeyBase64 || !this.keyIdentifier) {
591
- await this.extractKeysData();
592
- }
593
- return { publicKey: this.publicKeyBase64, keyIdentifier: this.keyIdentifier };
594
- }
595
- async sign(message) {
596
- if (this.keysType == 'sign') {
597
- const { privateKey } = await this.extractKeysData();
598
- const signatureBuffer = await signAssymetric(privateKey, message);
599
- return this.arrayBufferToBase64(signatureBuffer);
600
- }
601
- throw new Error("keysType must be 'sign' in order to use sign keys");
602
- }
603
- async clearKeys() {
604
- const recordKey = this.getKeysRecordKey();
605
- await this.indexedDBClient.delete(this.keysStoreName, recordKey);
606
- }
607
- getBaseRotationPayload() {
608
- return {
609
- keyIdentifier: this.keyIdentifier,
610
- slot: this.getRotatedKeysRecordKey(),
611
- publicKey: this.publicKeyBase64,
612
- publicKeyType: RSA_PUBLIC_KEY_TYPE,
613
- tenantId: this.options.keyRotation.tenantId,
614
- };
615
- }
616
- async getRotationData() {
617
- var _a, _b;
618
- if (!((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.keyRotation) === null || _b === void 0 ? void 0 : _b.isEnabled)) {
619
- return undefined;
620
- }
621
- // Ensure keys are loaded and cached
622
- if (!this.publicKeyBase64 || !this.keyIdentifier) {
623
- await this.extractKeysData();
624
- }
625
- // The new key is in the pending slot, creating the new key rotation payload
626
- const pendingRotatedKeysData = await this.extractPendingRotatedKeysData();
627
- if (pendingRotatedKeysData) {
628
- const { base64Key: newPublicKey } = await this.getPKRepresentations(pendingRotatedKeysData.publicKey);
629
- const { privateKey: currentActivePrivateKey } = await this.extractKeysData();
630
- const initiateRotationPayload = {
631
- ...this.getBaseRotationPayload(),
632
- newPublicKey,
633
- createdDate: pendingRotatedKeysData.createdDate,
634
- newPublicKeyType: RSA_PUBLIC_KEY_TYPE,
635
- };
636
- const stringifiedPayload = JSON.stringify(initiateRotationPayload);
637
- const signature = await this.signPayload(stringifiedPayload, currentActivePrivateKey); // Sign with the current active key
638
- return { data: stringifiedPayload, signature };
639
- }
640
- // This is solution only for the phase 1, until we sign all the requests
641
- // The first request after the rotation should be signed with the new key to confirm to the backend that the rotation is completed
642
- // The payload doesn't contain the new key, just the current active one
643
- const rotatedKeys = await this.extractRotatedKeysData();
644
- if (rotatedKeys && rotatedKeys.confirmed === false) {
645
- await this.extractKeysData(); // refresh the cache (in case other tab completed the rotation)
646
- const stringifiedBasePayload = JSON.stringify(this.getBaseRotationPayload());
647
- const signature = await this.signPayload(stringifiedBasePayload, rotatedKeys.privateKey); // Sign with the rotated key (currently active)
648
- return { data: stringifiedBasePayload, signature };
649
- }
650
- return undefined;
651
- }
652
- async signPayload(payload, privateKey) {
653
- const signatureBuffer = await signAssymetric(privateKey, payload);
654
- return this.arrayBufferToBase64(signatureBuffer);
655
- }
656
- async handleRotateResponse(response) {
657
- if (!VALID_ROTATION_RESPONSES.includes(response)) {
658
- return;
659
- }
660
- if (response === INIT_ROTATION_RESPONSE) {
661
- const pendingKey = await this.extractPendingRotatedKeysData();
662
- if (pendingKey) {
663
- // Remove the keys from the rotated slot
664
- await this.indexedDBClient.delete(this.keysStoreName, this.getRotatedKeysRecordKey());
665
- // Move the keys from the rotated pending slot to the rotated slot with confirmed: false
666
- const pendingKeyToStore = { ...pendingKey, confirmed: false };
667
- await this.indexedDBClient.put(this.keysStoreName, this.getRotatedKeysRecordKey(), pendingKeyToStore);
668
- await this.indexedDBClient.delete(this.keysStoreName, this.getRotatedKeysRecordKeyPending());
669
- // Refresh cache
670
- const { base64Key } = await this.getPKRepresentations(pendingKey.publicKey);
671
- this.publicKeyBase64 = base64Key;
672
- this.keyIdentifier = pendingKey.keyIdentifier;
673
- }
674
- }
675
- else if (response === COMPLETED_ROTATION_RESPONSE) {
676
- const rotatedKey = await this.extractRotatedKeysData();
677
- if (rotatedKey && rotatedKey.confirmed === false) {
678
- await this.indexedDBClient.put(this.keysStoreName, this.getRotatedKeysRecordKey(), {
679
- ...rotatedKey,
680
- confirmed: true,
681
- });
682
- }
683
- }
684
- }
685
- }
686
- function createCryptoBinding(keysType = 'sign', options) {
687
- return new CryptoBinding(this, keysType, options);
688
- }
689
-
690
- var crypto$1 = /*#__PURE__*/Object.freeze({
691
- __proto__: null,
692
- createCryptoBinding: createCryptoBinding,
693
- generateRSAKeyPair: generateRSAKeyPair,
694
- generateRSASignKeyPair: generateRSASignKeyPair,
695
- signAssymetric: signAssymetric,
696
- verifyAssymetric: verifyAssymetric
697
- });
698
-
699
- var indexedDB = /*#__PURE__*/Object.freeze({
700
- __proto__: null
701
- });
702
-
703
- const agent = Agent.create((agent) => {
704
- class TsError extends Error {
705
- constructor(errorCode, message) {
706
- super(`${agent.slug}-${errorCode} ${message}`);
707
- }
708
- }
709
- class TsInternalError extends TsError {
710
- constructor(errorCode) {
711
- super(errorCode, 'Internal error');
712
- }
713
- }
714
- return { TsError, TsInternalError };
715
- });
716
-
717
- var utils = Agent.create(() => ({
718
- exceptions: agent,
719
- ...agent$1,
720
- }));
721
-
722
- class SdkLogger {
723
- constructor(agent, middlewares = []) {
724
- this.agent = agent;
725
- this.middlewares = middlewares;
726
- this.logs = [];
727
- }
728
- info(message, fields) {
729
- this.pushLog(3, message, fields);
730
- }
731
- warn(message, fields) {
732
- this.pushLog(4, message, fields);
733
- }
734
- error(message, fields) {
735
- this.pushLog(5, message, fields);
736
- }
737
- pushLog(severity, message, fields = {}) {
738
- this.logs.push({
739
- timestamp: Date.now(),
740
- module: this.agent.slug,
741
- severity,
742
- fields,
743
- message,
744
- });
745
- const middlewareReturnValues = this.middlewares.map((middleware) => middleware(this));
746
- Promise.all(middlewareReturnValues).catch(() => {
747
- /* ignore */
748
- });
749
- }
750
- }
751
- function createSdkLogger(middlewares = []) {
752
- return new SdkLogger(this, middlewares);
753
- }
754
-
755
- function consoleMiddleware(logger) {
756
- const log = logger.logs[logger.logs.length - 1];
757
- console.log(`${log.severity} ${log.message}`, log.fields);
758
- }
759
-
760
- var logger$1 = /*#__PURE__*/Object.freeze({
761
- __proto__: null,
762
- consoleMiddleware: consoleMiddleware,
763
- createSdkLogger: createSdkLogger
764
- });
765
-
766
- function calculateJsonSize(json) {
767
- return encodeURI(JSON.stringify(json)).split(/%..|./).length - 1;
768
- }
769
-
770
- function isValidUrl(url) {
771
- try {
772
- new URL(url);
773
- return true;
774
- }
775
- catch (e) {
776
- return false;
777
- }
778
- }
779
- /**
780
- * format URL fragments to ensure correct path, so when both `api/action/something` and `/api/action/something` are valid inputs
781
- * @param path partial URL
782
- * @param search optional search params
783
- * @returns string
784
- */
785
- function urlFragmentFormat(path, search) {
786
- if (!(path === null || path === void 0 ? void 0 : path.trim()))
787
- return '';
788
- if (isValidUrl(path))
789
- return path;
790
- const mockDom = 'http://mock.com';
791
- const mockURL = new URL(mockDom);
792
- mockURL.search = (search === null || search === void 0 ? void 0 : search.toString()) || '';
793
- mockURL.pathname = path;
794
- const res = mockURL.href.replace(mockDom, '');
795
- return res;
796
- }
797
-
798
- const REQUEST_HEADERS = {
799
- 'Content-Type': 'application/json',
800
- 'X-TS-client-time': new Date().toUTCString(),
801
- 'X-TS-ua': navigator.userAgent,
802
- };
803
- function init(method, body, headers) {
804
- var _a;
805
- const size = calculateJsonSize(body || {});
806
- const sizeHeader = {
807
- 'X-TS-body-size': String(size),
808
- };
809
- return {
810
- method,
811
- headers: {
812
- ...sizeHeader,
813
- ...REQUEST_HEADERS,
814
- ...(headers || {}),
815
- },
816
- body: (_a = (body && JSON.stringify(body || {}))) !== null && _a !== void 0 ? _a : undefined,
817
- };
818
- }
819
- // implementation of HTTP fetch API. supports POST/GET and returns a promise of a result/failure.
820
- // full structure for response/failure TBD.
821
- function httpFetchBuilder(path, httpMethod, body, params, headers) {
822
- const reqUrl = urlFragmentFormat(path, params);
823
- const requestInit = init(httpMethod, body, headers);
824
- return fetch(reqUrl, requestInit);
825
- }
826
- async function fetchRequest(path, httpMethod, body, params, headers) {
827
- let response;
828
- if (httpMethod === 'GET' || httpMethod === 'DELETE') {
829
- response = await httpFetchBuilder(path, httpMethod, body, params, headers);
830
- }
831
- else {
832
- response = await httpFetchBuilder(path, httpMethod, body, params, headers);
833
- }
834
- // when debugging, check the response status code and response body
835
- // console.log('response: ', response);
836
- if (!response.ok) {
837
- throw new Error('Request failed');
838
- }
839
- return response;
840
- }
841
- /**
842
- * constructs a `GET` request
843
- * @param path API path
844
- * @param params request parameters
845
- * @returns a promise of the response body if successful and throw an error if failed
846
- */
847
- async function httpGet(path, params, headers) {
848
- const httpRequest = await fetchRequest(path, 'GET', undefined, params, headers);
849
- return { data: await httpRequest.json(), ...httpRequest, headers: httpRequest.headers };
850
- }
851
- /**
852
- * constructs a `POST` request
853
- * @param path API path
854
- * @param data content of the request
855
- * @param params request parameters
856
- * @returns a promise of the response body if successful and throw an error if failed
857
- */
858
- async function httpPost(path, data, params, headers) {
859
- const httpRequest = await fetchRequest(path, 'POST', data, params, headers);
860
- return { data: await httpRequest.json(), ...httpRequest, headers: httpRequest.headers };
861
- }
862
- /**
863
- * constructs a `PUT` request
864
- * @param path API path
865
- * @param data content of the request
866
- * @param params request parameters
867
- * @returns a promise of the response body if successful and throw an error if failed
868
- */
869
- async function httpPut(path, data, params, headers) {
870
- const httpRequest = await fetchRequest(path, 'PUT', data, params, headers);
871
- return { data: await httpRequest.json(), ...httpRequest, headers: httpRequest.headers };
872
- }
873
- /**
874
- * constructs a `DELETE` request
875
- * @param path API path
876
- * @param body content of the request
877
- * @param params request parameters
878
- * @returns a promise of the response body if successful and throw an error if failed
879
- */
880
- async function httpDelete(path, headers) {
881
- const httpRequest = await fetchRequest(path, 'DELETE', undefined, undefined, headers);
882
- return { data: await httpRequest.json(), ...httpRequest, headers: httpRequest.headers };
883
- }
884
-
885
- var http = /*#__PURE__*/Object.freeze({
886
- __proto__: null,
887
- httpDelete: httpDelete,
888
- httpGet: httpGet,
889
- httpPost: httpPost,
890
- httpPut: httpPut,
891
- init: init
892
- });
893
-
894
- var Common = Agent.create(() => ({
895
- events,
896
- moduleMetadata,
897
- mainEntry,
898
- utils,
899
- storage,
900
- crypto: crypto$1,
901
- indexedDB,
902
- logger: logger$1,
903
- http,
904
- }));
905
-
906
- class EncodingUtils {
907
- static arrayBufferToBase64(buffer) {
908
- return btoa(String.fromCharCode(...new Uint8Array(buffer)));
909
- }
910
- static base64ToArrayBuffer(base64) {
911
- return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
912
- }
913
- static stringToBase64(str) {
914
- return btoa(str);
915
- }
916
- static jsonToBase64(json) {
917
- const res = JSON.stringify(json);
918
- return btoa(res);
919
- }
920
- static base64ToJson(str) {
921
- const res = atob(str);
922
- return JSON.parse(res);
923
- }
924
- }
925
-
926
- const logger = {
927
- log: console.log,
928
- error: console.error,
929
- };
930
-
931
- /**
932
- * @enum
933
- */
934
- var ErrorCode;
935
- (function (ErrorCode) {
936
- /**
937
- * Either the SDK init call failed or another function was called before initializing the SDK
938
- */
939
- ErrorCode["NotInitialized"] = "not_initialized";
940
- /**
941
- * When the call to {@link WebauthnApis.startAuthentication} failed
942
- */
943
- ErrorCode["AuthenticationFailed"] = "authentication_failed";
944
- /**
945
- * When {@link WebauthnAuthenticationFlows.modal authenticate.modal} or {@link AutofillHandlers.activate authenticate.autofill.activate} is called and the modal is closed by the user
946
- */
947
- ErrorCode["AuthenticationAbortedTimeout"] = "authentication_aborted_timeout";
948
- /**
949
- * When {@link register} is called and the modal is closed when reaching the timeout
950
- */
951
- ErrorCode["AuthenticationCanceled"] = "webauthn_authentication_canceled";
952
- /**
953
- * When the call to {@link WebauthnApis.startRegistration} failed
954
- */
955
- ErrorCode["RegistrationFailed"] = "registration_failed";
956
- /**
957
- / When The user attempted to register an authenticator that contains one of the credentials already registered with the relying party.
958
- */
959
- ErrorCode["AlreadyRegistered"] = "username_already_registered";
960
- /**
961
- * When {@link register} is called and the modal is closed by the user
962
- */
963
- ErrorCode["RegistrationAbortedTimeout"] = "registration_aborted_timeout";
964
- /**
965
- * When {@link register} is called and the modal is closed when reaching the timeout
966
- */
967
- ErrorCode["RegistrationCanceled"] = "webauthn_registration_canceled";
968
- /**
969
- * Passkey autofill authentication was aborted by {@link AutofillHandlers.abort}
970
- */
971
- ErrorCode["AutofillAuthenticationAborted"] = "autofill_authentication_aborted";
972
- /**
973
- * Passkey authentication is already active. To start a new authentication, abort the current one first by calling {@link AutofillHandlers.abort}
974
- */
975
- ErrorCode["AuthenticationProcessAlreadyActive"] = "authentication_process_already_active";
976
- /**
977
- * The ApprovalData parameter was sent in the wrong format
978
- */
979
- ErrorCode["InvalidApprovalData"] = "invalid_approval_data";
980
- /**
981
- * When the call to {@link WebauthnApis.initCrossDeviceAuthentication} failed */
982
- ErrorCode["FailedToInitCrossDeviceSession"] = "cross_device_init_failed";
983
- /**
984
- * When the call to {@link WebauthnApis.getCrossDeviceTicketStatus} failed */
985
- ErrorCode["FailedToGetCrossDeviceStatus"] = "cross_device_status_failed";
986
- /**
987
- * When the SDK operation fails on an unhandled error
988
- */
989
- ErrorCode["Unknown"] = "unknown";
990
- })(ErrorCode || (ErrorCode = {}));
991
-
992
- class BaseSdkError extends Error {
993
- constructor(message, additionalData) {
994
- super(message);
995
- this.errorCode = ErrorCode.NotInitialized;
996
- this.data = additionalData;
997
- }
998
- }
999
- class NotInitializedError extends BaseSdkError {
1000
- constructor(message, additionalData) {
1001
- super(message !== null && message !== void 0 ? message : 'WebAuthnSdk is not initialized', additionalData);
1002
- this.errorCode = ErrorCode.NotInitialized;
1003
- }
1004
- }
1005
- class AuthenticationFailedError extends BaseSdkError {
1006
- constructor(message, additionalData) {
1007
- super(message !== null && message !== void 0 ? message : 'Authentication failed with an error', additionalData);
1008
- this.errorCode = ErrorCode.AuthenticationFailed;
1009
- }
1010
- }
1011
- class AuthenticationCanceledError extends BaseSdkError {
1012
- constructor(message, additionalData) {
1013
- super(message !== null && message !== void 0 ? message : 'Authentication was canceled by the user or got timeout', additionalData);
1014
- this.errorCode = ErrorCode.AuthenticationCanceled;
1015
- }
1016
- }
1017
- class RegistrationFailedError extends BaseSdkError {
1018
- constructor(message, additionalData) {
1019
- super(message !== null && message !== void 0 ? message : 'Registration failed with an error', additionalData);
1020
- this.errorCode = ErrorCode.RegistrationFailed;
1021
- }
1022
- }
1023
- class RegistrationCanceledError extends BaseSdkError {
1024
- constructor(message, additionalData) {
1025
- super(message !== null && message !== void 0 ? message : 'Registration was canceled by the user or got timeout', additionalData);
1026
- this.errorCode = ErrorCode.RegistrationCanceled;
1027
- }
1028
- }
1029
- class AutofillAuthenticationAbortedError extends BaseSdkError {
1030
- constructor(message) {
1031
- super(message !== null && message !== void 0 ? message : 'Autofill flow was aborted');
1032
- this.errorCode = ErrorCode.AutofillAuthenticationAborted;
1033
- }
1034
- }
1035
- class OperationTimeoutAbortedError extends BaseSdkError {
1036
- constructor(message) {
1037
- super(message !== null && message !== void 0 ? message : 'Operation was aborted by timeout');
1038
- this.errorCode = ErrorCode.AutofillAuthenticationAborted;
1039
- }
1040
- }
1041
- class AlreadyRegisteredError extends BaseSdkError {
1042
- constructor(message) {
1043
- super(message !== null && message !== void 0 ? message : 'Passkey with this username is already registered with the relying party.');
1044
- this.errorCode = ErrorCode.AlreadyRegistered;
1045
- }
1046
- }
1047
- class AuthenticationProcessAlreadyActiveError extends BaseSdkError {
1048
- constructor(message, additionalData) {
1049
- super(message !== null && message !== void 0 ? message : 'Authentication process is already active', additionalData);
1050
- this.errorCode = ErrorCode.AuthenticationProcessAlreadyActive;
1051
- }
1052
- }
1053
- class InvalidApprovalDataError extends BaseSdkError {
1054
- constructor(message, additionalData) {
1055
- super(message !== null && message !== void 0 ? message : 'Invalid approval data', additionalData);
1056
- this.errorCode = ErrorCode.InvalidApprovalData;
1057
- }
1058
- }
1059
- class FailedToInitCrossDeviceAuthenticationError extends BaseSdkError {
1060
- constructor(message, additionalData) {
1061
- super(message !== null && message !== void 0 ? message : 'Failed to init cross device authentication', additionalData);
1062
- this.errorCode = ErrorCode.FailedToInitCrossDeviceSession;
1063
- }
1064
- }
1065
- class FailedToGetCrossDeviceStatusError extends BaseSdkError {
1066
- constructor(message, additionalData) {
1067
- super(message !== null && message !== void 0 ? message : 'Failed to get cross device status', additionalData);
1068
- this.errorCode = ErrorCode.FailedToGetCrossDeviceStatus;
1069
- }
1070
- }
1071
- function isBaseSdkError(error) {
1072
- return error.errorCode && Object.values(ErrorCode).includes(error.errorCode);
1073
- }
1074
-
1075
- /**
1076
- * This is a typed (Storage)[https://developer.mozilla.org/en-US/docs/Web/API/Storage] wrapper.
1077
- * Items are saved in either localstorage or sessionstorage depending on their key. when retrieving an
1078
- * item, it is automatically fetched from the correct storage solution.
1079
- */
1080
- var KeyPersistance;
1081
- (function (KeyPersistance) {
1082
- KeyPersistance[KeyPersistance["persistent"] = 0] = "persistent";
1083
- KeyPersistance[KeyPersistance["session"] = 1] = "session";
1084
- })(KeyPersistance || (KeyPersistance = {}));
1085
- class SdkStorage {
1086
- static get(keyName) {
1087
- return (SdkStorage.getStorageMedium(SdkStorage.allowedKeys[keyName]).getItem(SdkStorage.getStorageKey(keyName)) ||
1088
- undefined);
1089
- }
1090
- static set(keyName, value) {
1091
- return SdkStorage.getStorageMedium(SdkStorage.allowedKeys[keyName]).setItem(SdkStorage.getStorageKey(keyName), value);
1092
- }
1093
- static remove(keyName) {
1094
- SdkStorage.getStorageMedium(SdkStorage.allowedKeys[keyName]).removeItem(SdkStorage.getStorageKey(keyName));
1095
- }
1096
- static clear(retainConfiguration) {
1097
- // We don't want to actually call Storage.clear, since that may clear some of the RP's data as well.
1098
- for (const [key, keyPersistence] of Object.entries(SdkStorage.allowedKeys)) {
1099
- const typedKey = key;
1100
- if (retainConfiguration && this.configurationKeys.includes(typedKey)) {
1101
- continue;
1102
- }
1103
- SdkStorage.getStorageMedium(keyPersistence).removeItem(SdkStorage.getStorageKey(typedKey));
1104
- }
1105
- }
1106
- static getStorageKey(keyName) {
1107
- return `WebAuthnSdk:${keyName}`;
1108
- }
1109
- static getStorageMedium(keyPersistance) {
1110
- switch (keyPersistance) {
1111
- case KeyPersistance.session:
1112
- return sessionStorage;
1113
- default:
1114
- return localStorage;
1115
- }
1116
- }
1117
- }
1118
- SdkStorage.allowedKeys = {
1119
- // please please please keep this in alphabetical order
1120
- clientId: KeyPersistance.session,
1121
- };
1122
- SdkStorage.configurationKeys = [
1123
- // please please please keep this in alphabetical order
1124
- 'clientId',
1125
- ];
1126
-
1127
- const NEW_API_PATH_PREFIX = '/cis';
1128
- class SdkApiClient {
1129
- static isNewApiDomain(hostname) {
1130
- return (hostname &&
1131
- (this.newApiDomains.includes(hostname) ||
1132
- (hostname.startsWith('api.') && hostname.endsWith('.transmitsecurity.io'))));
1133
- }
1134
- static dnsPrefetch(serverPath) {
1135
- const hint = document.createElement('link');
1136
- hint.rel = 'dns-prefetch';
1137
- hint.href = serverPath;
1138
- document.head.appendChild(hint);
1139
- }
1140
- static preconnect(serverPath, crossOrigin) {
1141
- const hint = document.createElement('link');
1142
- hint.rel = 'preconnect';
1143
- hint.href = serverPath;
1144
- if (crossOrigin) {
1145
- hint.crossOrigin = 'anonymous';
1146
- }
1147
- document.head.appendChild(hint);
1148
- }
1149
- static warmupConnection(serverPath) {
1150
- // following https://dev.to/crenshaw_dev/when-the-browser-can-t-take-a-preconnect-hint-6dn
1151
- this.dnsPrefetch(serverPath);
1152
- this.preconnect(serverPath, false);
1153
- this.preconnect(serverPath, true);
1154
- }
1155
- static init(clientId, options) {
1156
- var _a, _b;
1157
- try {
1158
- this._serverPath = new URL(options.serverPath);
1159
- if (this.isNewApiDomain((_a = this._serverPath) === null || _a === void 0 ? void 0 : _a.hostname)) {
1160
- this.warmupConnection(this._serverPath.origin);
1161
- }
1162
- this._apiPaths = (_b = options.webauthnApiPaths) !== null && _b !== void 0 ? _b : this.getDefaultPaths();
1163
- this._clientId = clientId;
1164
- SdkStorage.set('clientId', clientId);
1165
- }
1166
- catch (error) {
1167
- throw new NotInitializedError('Invalid options.serverPath', { error });
1168
- }
1169
- }
1170
- static getDefaultPaths() {
1171
- var _a;
1172
- // In case the user initializes the SDK with the new API gateway, we need to use the new API paths
1173
- const pathPrefix = this.isNewApiDomain((_a = this._serverPath) === null || _a === void 0 ? void 0 : _a.hostname) ? NEW_API_PATH_PREFIX : '';
1174
- return {
1175
- startAuthentication: `${pathPrefix}/v1/auth/webauthn/authenticate/start`,
1176
- startRegistration: `${pathPrefix}/v1/auth/webauthn/register/start`,
1177
- initCrossDeviceAuthentication: `${pathPrefix}/v1/auth/webauthn/cross-device/authenticate/init`,
1178
- startCrossDeviceAuthentication: `${pathPrefix}/v1/auth/webauthn/cross-device/authenticate/start`,
1179
- startCrossDeviceRegistration: `${pathPrefix}/v1/auth/webauthn/cross-device/register/start`,
1180
- getCrossDeviceTicketStatus: `${pathPrefix}/v1/auth/webauthn/cross-device/status`,
1181
- attachDeviceToCrossDeviceSession: `${pathPrefix}/v1/auth/webauthn/cross-device/attach-device`,
1182
- };
1183
- }
1184
- static getApiPaths() {
1185
- return this._apiPaths;
1186
- }
1187
- static async sendRequest(path, request, query) {
1188
- logger.log(`[WebAuthn SDK] Calling ${request.method} ${path}...`);
1189
- const requestUrl = new URL(this._serverPath);
1190
- requestUrl.pathname = path;
1191
- if (query) {
1192
- requestUrl.search = query;
1193
- }
1194
- return fetch(requestUrl.toString(), request);
1195
- }
1196
- static async startRegistration(params) {
1197
- const response = await this.sendRequest(this._apiPaths.startRegistration, {
1198
- method: 'POST',
1199
- headers: {
1200
- 'Content-Type': 'application/json',
1201
- },
1202
- body: JSON.stringify({
1203
- client_id: this.getValidatedClientId(),
1204
- username: params.username,
1205
- display_name: params.displayName,
1206
- ...(params.timeout && { timeout: params.timeout }),
1207
- ...(params.limitSingleCredentialToDevice && {
1208
- limit_single_credential_to_device: params.limitSingleCredentialToDevice,
1209
- }),
1210
- }),
1211
- });
1212
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1213
- throw new AuthenticationFailedError('Failed to start registration', response === null || response === void 0 ? void 0 : response.body);
1214
- }
1215
- return (await response.json());
1216
- }
1217
- static async startAuthentication(params) {
1218
- const response = await this.sendRequest(this._apiPaths.startAuthentication, {
1219
- method: 'POST',
1220
- headers: {
1221
- 'Content-Type': 'application/json',
1222
- },
1223
- body: JSON.stringify({
1224
- client_id: this.getValidatedClientId(),
1225
- ...(params.username && { username: params.username }),
1226
- ...(params.approvalData && { approval_data: params.approvalData }),
1227
- ...(params.timeout && { timeout: params.timeout }),
1228
- }),
1229
- });
1230
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1231
- throw new AuthenticationFailedError('Failed to start authentication', response === null || response === void 0 ? void 0 : response.body);
1232
- }
1233
- return (await response.json());
1234
- }
1235
- static async initCrossDeviceAuthentication(params) {
1236
- const response = await this.sendRequest(this._apiPaths.initCrossDeviceAuthentication, {
1237
- method: 'POST',
1238
- headers: {
1239
- 'Content-Type': 'application/json',
1240
- },
1241
- body: JSON.stringify({
1242
- client_id: this.getValidatedClientId(),
1243
- ...(params.username && { username: params.username }),
1244
- ...(params.approvalData && { approval_data: params.approvalData }),
1245
- }),
1246
- });
1247
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1248
- throw new FailedToInitCrossDeviceAuthenticationError(undefined, response === null || response === void 0 ? void 0 : response.body);
1249
- }
1250
- return (await response.json());
1251
- }
1252
- static async getCrossDeviceTicketStatus(params) {
1253
- const response = await this.sendRequest(this._apiPaths.getCrossDeviceTicketStatus, {
1254
- method: 'GET',
1255
- }, `cross_device_ticket_id=${params.ticketId}`);
1256
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1257
- throw new FailedToGetCrossDeviceStatusError(undefined, response === null || response === void 0 ? void 0 : response.body);
1258
- }
1259
- return (await response.json());
1260
- }
1261
- static async startCrossDeviceAuthentication(params) {
1262
- const response = await this.sendRequest(this._apiPaths.startCrossDeviceAuthentication, {
1263
- method: 'POST',
1264
- headers: {
1265
- 'Content-Type': 'application/json',
1266
- },
1267
- body: JSON.stringify({
1268
- cross_device_ticket_id: params.ticketId,
1269
- }),
1270
- });
1271
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1272
- throw new AuthenticationFailedError('Failed to start cross device authentication', response === null || response === void 0 ? void 0 : response.body);
1273
- }
1274
- return (await response.json());
1275
- }
1276
- static async startCrossDeviceRegistration(params) {
1277
- const response = await this.sendRequest(this._apiPaths.startCrossDeviceRegistration, {
1278
- method: 'POST',
1279
- headers: {
1280
- 'Content-Type': 'application/json',
1281
- },
1282
- body: JSON.stringify({
1283
- cross_device_ticket_id: params.ticketId,
1284
- }),
1285
- });
1286
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1287
- throw new RegistrationFailedError('Failed to start cross device registration', response === null || response === void 0 ? void 0 : response.body);
1288
- }
1289
- return (await response.json());
1290
- }
1291
- static async attachDeviceToCrossDeviceSession(params) {
1292
- const response = await this.sendRequest(this._apiPaths.attachDeviceToCrossDeviceSession, {
1293
- method: 'POST',
1294
- headers: {
1295
- 'Content-Type': 'application/json',
1296
- },
1297
- body: JSON.stringify({
1298
- cross_device_ticket_id: params.ticketId,
1299
- }),
1300
- });
1301
- if (!(response === null || response === void 0 ? void 0 : response.ok)) {
1302
- throw new RegistrationFailedError('Failed to attach device to cross device session', response === null || response === void 0 ? void 0 : response.body);
1303
- }
1304
- return (await response.json());
1305
- }
1306
- static getValidatedClientId() {
1307
- var _a;
1308
- const clientId = (_a = this._clientId) !== null && _a !== void 0 ? _a : SdkStorage.get('clientId');
1309
- if (!clientId) {
1310
- throw new NotInitializedError('Missing clientId');
1311
- }
1312
- return clientId;
1313
- }
1314
- }
1315
- SdkApiClient.newApiDomains = ['api.idsec-dev.com', 'api.idsec-stg.com'];
1316
-
1317
- /**
1318
- * WebAuthn registration response interfaces
1319
- */
1320
- /**
1321
- * WebAuthn authentication mediation type
1322
- */
1323
- var AuthenticationMediationType;
1324
- (function (AuthenticationMediationType) {
1325
- AuthenticationMediationType["InputAutofill"] = "input-autofill";
1326
- AuthenticationMediationType["Modal"] = "modal";
1327
- })(AuthenticationMediationType || (AuthenticationMediationType = {}));
1328
- /**
1329
- * WebAuthn cross device interfaces
1330
- */
1331
- var WebauthnCrossDeviceStatus;
1332
- (function (WebauthnCrossDeviceStatus) {
1333
- WebauthnCrossDeviceStatus["Pending"] = "pending";
1334
- WebauthnCrossDeviceStatus["Scanned"] = "scanned";
1335
- WebauthnCrossDeviceStatus["Success"] = "success";
1336
- WebauthnCrossDeviceStatus["Error"] = "error";
1337
- WebauthnCrossDeviceStatus["Timeout"] = "timeout";
1338
- WebauthnCrossDeviceStatus["Aborted"] = "aborted";
1339
- })(WebauthnCrossDeviceStatus || (WebauthnCrossDeviceStatus = {}));
1340
-
1341
- var SdkErrorParser;
1342
- (function (SdkErrorParser) {
1343
- SdkErrorParser.toAuthenticationError = (error) => {
1344
- if (isBaseSdkError(error)) {
1345
- return error;
1346
- }
1347
- if (error.name === 'NotAllowedError') {
1348
- return new AuthenticationCanceledError();
1349
- }
1350
- if (error.name === 'OperationError') {
1351
- return new AuthenticationProcessAlreadyActiveError(error.message);
1352
- }
1353
- if (error.name === 'SecurityError') {
1354
- return new AuthenticationFailedError(error.message);
1355
- }
1356
- if (error === ErrorCode.AuthenticationAbortedTimeout) {
1357
- return new OperationTimeoutAbortedError();
1358
- }
1359
- if (error.name === 'AbortError' || error === ErrorCode.AutofillAuthenticationAborted) {
1360
- return new AutofillAuthenticationAbortedError();
1361
- }
1362
- return new AuthenticationFailedError('Something went wrong during authentication', { error });
1363
- };
1364
- SdkErrorParser.toRegistrationError = (error) => {
1365
- if (isBaseSdkError(error)) {
1366
- return error;
1367
- }
1368
- if (error.name === 'NotAllowedError') {
1369
- return new RegistrationCanceledError();
1370
- }
1371
- if (error.name === 'SecurityError') {
1372
- return new RegistrationFailedError(error.message);
1373
- }
1374
- if (error.name === 'InvalidStateError') {
1375
- return new AlreadyRegisteredError();
1376
- }
1377
- if (error === ErrorCode.RegistrationAbortedTimeout) {
1378
- return new OperationTimeoutAbortedError();
1379
- }
1380
- return new RegistrationFailedError('Something went wrong during registration', { error });
1381
- };
1382
- })(SdkErrorParser || (SdkErrorParser = {}));
1383
-
1384
- var WebauthnParser;
1385
- (function (WebauthnParser) {
1386
- WebauthnParser.processCredentialRequestOptions = (credentialRequestOptions) => {
1387
- return {
1388
- ...credentialRequestOptions,
1389
- challenge: EncodingUtils.base64ToArrayBuffer(credentialRequestOptions.challenge),
1390
- allowCredentials: credentialRequestOptions.allowCredentials.map((ac) => ({
1391
- ...ac,
1392
- id: EncodingUtils.base64ToArrayBuffer(ac.id),
1393
- })),
1394
- };
1395
- };
1396
- WebauthnParser.processCredentialCreationOptions = (rawCredentialCreationOptions, options) => {
1397
- var _a;
1398
- const credentialCreationOptions = JSON.parse(JSON.stringify(rawCredentialCreationOptions));
1399
- credentialCreationOptions.challenge = EncodingUtils.base64ToArrayBuffer(rawCredentialCreationOptions.challenge);
1400
- credentialCreationOptions.user.id = EncodingUtils.base64ToArrayBuffer(rawCredentialCreationOptions.user.id);
1401
- if (options === null || options === void 0 ? void 0 : options.limitSingleCredentialToDevice) {
1402
- credentialCreationOptions.excludeCredentials = (_a = rawCredentialCreationOptions.excludeCredentials) === null || _a === void 0 ? void 0 : _a.map((ac) => ({
1403
- ...ac,
1404
- id: EncodingUtils.base64ToArrayBuffer(ac.id),
1405
- }));
1406
- }
1407
- if (options === null || options === void 0 ? void 0 : options.registerAsDiscoverable) {
1408
- credentialCreationOptions.authenticatorSelection.residentKey = 'preferred';
1409
- credentialCreationOptions.authenticatorSelection.requireResidentKey = true;
1410
- }
1411
- else {
1412
- credentialCreationOptions.authenticatorSelection.residentKey = 'discouraged';
1413
- credentialCreationOptions.authenticatorSelection.requireResidentKey = false;
1414
- }
1415
- credentialCreationOptions.authenticatorSelection.authenticatorAttachment = (options === null || options === void 0 ? void 0 : options.allowCrossPlatformAuthenticators)
1416
- ? undefined
1417
- : 'platform';
1418
- return credentialCreationOptions;
1419
- };
1420
- WebauthnParser.encodeAuthenticationResult = (credential) => {
1421
- const { authenticatorAttachment } = credential;
1422
- const credentialResponse = credential.response;
1423
- return {
1424
- id: credential.id,
1425
- rawId: EncodingUtils.arrayBufferToBase64(credential.rawId),
1426
- response: {
1427
- authenticatorData: EncodingUtils.arrayBufferToBase64(credentialResponse.authenticatorData),
1428
- clientDataJSON: EncodingUtils.arrayBufferToBase64(credentialResponse.clientDataJSON),
1429
- signature: EncodingUtils.arrayBufferToBase64(credentialResponse.signature),
1430
- userHandle: EncodingUtils.arrayBufferToBase64(credentialResponse.userHandle),
1431
- },
1432
- authenticatorAttachment,
1433
- type: credential.type,
1434
- };
1435
- };
1436
- WebauthnParser.encodeRegistrationResult = (credential) => {
1437
- const { authenticatorAttachment } = credential;
1438
- const credentialResponse = credential.response;
1439
- return {
1440
- id: credential.id,
1441
- rawId: EncodingUtils.arrayBufferToBase64(credential.rawId),
1442
- response: {
1443
- attestationObject: EncodingUtils.arrayBufferToBase64(credentialResponse.attestationObject),
1444
- clientDataJSON: EncodingUtils.arrayBufferToBase64(credentialResponse.clientDataJSON),
1445
- },
1446
- authenticatorAttachment,
1447
- type: credential.type,
1448
- };
1449
- };
1450
- })(WebauthnParser || (WebauthnParser = {}));
1451
-
1452
- class AuthenticationHandler {
1453
- async modal(params) {
1454
- try {
1455
- const result = await this.performAuthentication({
1456
- ...params,
1457
- mediationType: AuthenticationMediationType.Modal,
1458
- });
1459
- return EncodingUtils.jsonToBase64(result);
1460
- }
1461
- catch (err) {
1462
- throw SdkErrorParser.toAuthenticationError(err);
1463
- }
1464
- }
1465
- activateAutofill(handlers, username) {
1466
- const { onSuccess, onError, onReady } = handlers;
1467
- this.performAuthentication({
1468
- username,
1469
- mediationType: AuthenticationMediationType.InputAutofill,
1470
- onReady,
1471
- })
1472
- .then((result) => {
1473
- onSuccess(EncodingUtils.jsonToBase64(result));
1474
- })
1475
- .catch((err) => {
1476
- const error = SdkErrorParser.toAuthenticationError(err);
1477
- if (!onError)
1478
- throw error;
1479
- onError(error);
1480
- });
1481
- }
1482
- abortAutofill() {
1483
- if (this.abortController)
1484
- this.abortController.abort(ErrorCode.AutofillAuthenticationAborted);
1485
- }
1486
- abortAuthentication() {
1487
- if (this.abortController)
1488
- this.abortController.abort(ErrorCode.AuthenticationAbortedTimeout);
1489
- }
1490
- async performAuthentication(params) {
1491
- var _a, _b;
1492
- const startAuthenticationResponse = 'crossDeviceTicketId' in params
1493
- ? await SdkApiClient.startCrossDeviceAuthentication({ ticketId: params.crossDeviceTicketId })
1494
- : await SdkApiClient.startAuthentication({ username: params.username, timeout: (_a = params.options) === null || _a === void 0 ? void 0 : _a.timeout });
1495
- const credentialRequestOptions = startAuthenticationResponse.credential_request_options;
1496
- const processedOptions = WebauthnParser.processCredentialRequestOptions(credentialRequestOptions);
1497
- const mediatedCredentialRequestOptions = this.getMediatedCredentialRequest(processedOptions, params.mediationType);
1498
- if (params.mediationType === AuthenticationMediationType.InputAutofill) {
1499
- (_b = params.onReady) === null || _b === void 0 ? void 0 : _b.call(params);
1500
- }
1501
- const credential = (await navigator.credentials.get(mediatedCredentialRequestOptions).catch((error) => {
1502
- throw SdkErrorParser.toAuthenticationError(error);
1503
- }));
1504
- return {
1505
- webauthnSessionId: startAuthenticationResponse.webauthn_session_id,
1506
- publicKeyCredential: WebauthnParser.encodeAuthenticationResult(credential),
1507
- userAgent: navigator.userAgent,
1508
- };
1509
- }
1510
- getMediatedCredentialRequest(credentialRequestOptions, passkeysMediationType) {
1511
- const mediatedCredentialRequestOptions = { publicKey: credentialRequestOptions };
1512
- this.abortController = new AbortController();
1513
- mediatedCredentialRequestOptions.signal = this.abortController && this.abortController.signal;
1514
- if (passkeysMediationType === AuthenticationMediationType.InputAutofill) {
1515
- mediatedCredentialRequestOptions.mediation = 'conditional';
1516
- }
1517
- else if (credentialRequestOptions.timeout) {
1518
- setTimeout(() => {
1519
- this.abortAuthentication();
1520
- }, credentialRequestOptions.timeout);
1521
- }
1522
- return mediatedCredentialRequestOptions;
1523
- }
1524
- }
1525
-
1526
- function setIntervalWithPromise(target) {
1527
- return async (...args) => {
1528
- if (target.isRunning) {
1529
- return;
1530
- }
1531
- target.isRunning = true;
1532
- await target(...args);
1533
- target.isRunning = false;
1534
- };
1535
- }
1536
- class PollingHandler {
1537
- constructor(handler, intervalInMs) {
1538
- this.handler = handler;
1539
- this.intervalInMs = intervalInMs;
1540
- }
1541
- begin() {
1542
- this.intervalId = window.setInterval(setIntervalWithPromise(this.handler), this.intervalInMs);
1543
- }
1544
- stop() {
1545
- clearInterval(this.intervalId);
1546
- }
1547
- }
1548
-
1549
- const approvalDataMaxLength = 10;
1550
- const approvalDataAllowedChars = /^[A-Za-z0-9\-_.: ]*$/;
1551
- function validateApprovalMaxLength(approvalData) {
1552
- return Object.keys(approvalData).length <= approvalDataMaxLength;
1553
- }
1554
- function validateApprovalAllowedContent(approvalData) {
1555
- const isString = (val) => typeof val === 'string';
1556
- const isContentAllowed = (val) => approvalDataAllowedChars.test(val);
1557
- return Object.keys(approvalData).every((key) => isString(key) && isString(approvalData[key]) && isContentAllowed(key) && isContentAllowed(approvalData[key]));
1558
- }
1559
- function validateApprovalData(approvalData) {
1560
- if (!approvalData) {
1561
- return;
1562
- }
1563
- if (!validateApprovalMaxLength(approvalData) || !validateApprovalAllowedContent(approvalData)) {
1564
- logger.error(`Failed validating approval data`);
1565
- throw new InvalidApprovalDataError(`Provided approval data should have ${approvalDataMaxLength} properties max. Also, it should contain only
1566
- alphanumeric characters, numbers, and the special characters: '-', '_', '.'`);
1567
- }
1568
- }
1569
-
1570
- class WebauthnCrossDeviceHandler {
1571
- constructor(authenticationHandler, registrationHandler, approvalHandler) {
1572
- this.authenticationHandler = authenticationHandler;
1573
- this.registrationHandler = registrationHandler;
1574
- this.approvalHandler = approvalHandler;
1575
- this.init = {
1576
- registration: async (params) => {
1577
- this.ticketStatus = WebauthnCrossDeviceStatus.Pending;
1578
- return this.pollCrossDeviceSession(params.crossDeviceTicketId, params.handlers);
1579
- },
1580
- authentication: async (params) => {
1581
- const { username } = params;
1582
- const initAuthenticationResponse = await SdkApiClient.initCrossDeviceAuthentication({
1583
- ...(username && { username }),
1584
- });
1585
- const ticketId = initAuthenticationResponse.cross_device_ticket_id;
1586
- this.ticketStatus = WebauthnCrossDeviceStatus.Pending;
1587
- return this.pollCrossDeviceSession(ticketId, params.handlers);
1588
- },
1589
- approval: async (params) => {
1590
- const { username, approvalData } = params;
1591
- validateApprovalData(approvalData);
1592
- const initAuthenticationResponse = await SdkApiClient.initCrossDeviceAuthentication({
1593
- username,
1594
- approvalData,
1595
- });
1596
- const ticketId = initAuthenticationResponse.cross_device_ticket_id;
1597
- this.ticketStatus = WebauthnCrossDeviceStatus.Pending;
1598
- return this.pollCrossDeviceSession(ticketId, params.handlers);
1599
- },
1600
- };
1601
- this.authenticate = {
1602
- modal: async (crossDeviceTicketId) => this.authenticationHandler.modal({ crossDeviceTicketId }),
1603
- };
1604
- this.approve = {
1605
- modal: async (crossDeviceTicketId) => this.approvalHandler.modal({ crossDeviceTicketId }),
1606
- };
1607
- }
1608
- async register(crossDeviceTicketId, options) {
1609
- return this.registrationHandler.register({ crossDeviceTicketId }, options);
1610
- }
1611
- async attachDevice(crossDeviceTicketId) {
1612
- const response = await SdkApiClient.attachDeviceToCrossDeviceSession({
1613
- ticketId: crossDeviceTicketId,
1614
- });
1615
- return {
1616
- status: response.status,
1617
- startedAt: response.started_at,
1618
- ...(response.approval_data && { approvalData: response.approval_data }),
1619
- };
1620
- }
1621
- async pollCrossDeviceSession(ticketId, handlers) {
1622
- const pollFunction = async () => {
1623
- var _a, _b;
1624
- const statusResponse = await SdkApiClient.getCrossDeviceTicketStatus({
1625
- ticketId,
1626
- });
1627
- const newStatus = statusResponse.status;
1628
- if (newStatus === this.ticketStatus) {
1629
- return;
1630
- }
1631
- this.ticketStatus = newStatus;
1632
- switch (newStatus) {
1633
- case WebauthnCrossDeviceStatus.Scanned:
1634
- await handlers.onDeviceAttach();
1635
- break;
1636
- case WebauthnCrossDeviceStatus.Error:
1637
- case WebauthnCrossDeviceStatus.Timeout:
1638
- case WebauthnCrossDeviceStatus.Aborted:
1639
- await handlers.onFailure(statusResponse);
1640
- (_a = this.poller) === null || _a === void 0 ? void 0 : _a.stop();
1641
- break;
1642
- case WebauthnCrossDeviceStatus.Success:
1643
- if ('onCredentialRegister' in handlers) {
1644
- await handlers.onCredentialRegister();
1645
- }
1646
- else {
1647
- if (!statusResponse.session_id) {
1648
- throw new FailedToGetCrossDeviceStatusError('Cross device session is complete without returning session_id', statusResponse);
1649
- }
1650
- await handlers.onCredentialAuthenticate(statusResponse.session_id);
1651
- }
1652
- (_b = this.poller) === null || _b === void 0 ? void 0 : _b.stop();
1653
- break;
1654
- }
1655
- };
1656
- this.poller = new PollingHandler(pollFunction, 1000);
1657
- this.poller.begin();
1658
- setTimeout(() => {
1659
- var _a;
1660
- (_a = this.poller) === null || _a === void 0 ? void 0 : _a.stop();
1661
- handlers.onFailure({ status: WebauthnCrossDeviceStatus.Timeout });
1662
- }, 5 * 60 * 1000);
1663
- return {
1664
- crossDeviceTicketId: ticketId,
1665
- stop: () => {
1666
- var _a;
1667
- (_a = this.poller) === null || _a === void 0 ? void 0 : _a.stop();
1668
- },
1669
- };
1670
- }
1671
- }
1672
-
1673
- class RegistrationHandler {
1674
- async register(params, options) {
1675
- this.abortController = new AbortController();
1676
- const isCrossDevice = 'crossDeviceTicketId' in params;
1677
- const registrationOptions = {
1678
- allowCrossPlatformAuthenticators: !isCrossDevice,
1679
- registerAsDiscoverable: true,
1680
- ...options,
1681
- };
1682
- try {
1683
- const startRegistrationResponse = 'crossDeviceTicketId' in params
1684
- ? await SdkApiClient.startCrossDeviceRegistration({ ticketId: params.crossDeviceTicketId })
1685
- : await SdkApiClient.startRegistration({
1686
- username: params.username,
1687
- displayName: (options === null || options === void 0 ? void 0 : options.displayName) || params.username,
1688
- timeout: options === null || options === void 0 ? void 0 : options.timeout,
1689
- limitSingleCredentialToDevice: options === null || options === void 0 ? void 0 : options.limitSingleCredentialToDevice,
1690
- });
1691
- const credentialCreationOptions = WebauthnParser.processCredentialCreationOptions(startRegistrationResponse.credential_creation_options, registrationOptions);
1692
- setTimeout(() => {
1693
- this.abortRegistration();
1694
- }, credentialCreationOptions.timeout);
1695
- const publicKeyCredential = await this.registerCredential(credentialCreationOptions);
1696
- const result = {
1697
- webauthnSessionId: startRegistrationResponse.webauthn_session_id,
1698
- publicKeyCredential,
1699
- userAgent: navigator.userAgent,
1700
- };
1701
- return EncodingUtils.jsonToBase64(result);
1702
- }
1703
- catch (error) {
1704
- throw SdkErrorParser.toRegistrationError(error);
1705
- }
1706
- }
1707
- abortRegistration() {
1708
- if (this.abortController)
1709
- this.abortController.abort(ErrorCode.RegistrationAbortedTimeout);
1710
- }
1711
- async registerCredential(credentialCreationOptions) {
1712
- const credential = (await navigator.credentials
1713
- .create({
1714
- publicKey: credentialCreationOptions,
1715
- signal: this.abortController && this.abortController.signal,
1716
- })
1717
- .catch((error) => {
1718
- throw SdkErrorParser.toRegistrationError(error);
1719
- }));
1720
- return WebauthnParser.encodeRegistrationResult(credential);
1721
- }
1722
- }
1723
-
1724
- function symmetricDifference(arr1, arr2) {
1725
- const set1 = new Set(arr1);
1726
- const set2 = new Set(arr2);
1727
- return [...arr1.filter((x) => !set2.has(x)), ...arr2.filter((x) => !set1.has(x))];
1728
- }
1729
-
1730
- class ApprovalHandler {
1731
- async modal(params) {
1732
- try {
1733
- const result = await this.performApproval(params);
1734
- return EncodingUtils.jsonToBase64(result);
1735
- }
1736
- catch (err) {
1737
- throw SdkErrorParser.toAuthenticationError(err);
1738
- }
1739
- }
1740
- async performApproval(params) {
1741
- if ('approvalData' in params) {
1742
- validateApprovalData(params.approvalData);
1743
- }
1744
- const startAuthenticationResponse = 'crossDeviceTicketId' in params
1745
- ? await SdkApiClient.startCrossDeviceAuthentication({ ticketId: params.crossDeviceTicketId })
1746
- : await SdkApiClient.startAuthentication({
1747
- username: params.username,
1748
- approvalData: params.approvalData,
1749
- });
1750
- const credentialRequestOptions = startAuthenticationResponse.credential_request_options;
1751
- const processedOptions = WebauthnParser.processCredentialRequestOptions(credentialRequestOptions);
1752
- const credential = (await navigator.credentials.get({ publicKey: processedOptions }).catch((error) => {
1753
- throw SdkErrorParser.toAuthenticationError(error);
1754
- }));
1755
- return {
1756
- webauthnSessionId: startAuthenticationResponse.webauthn_session_id,
1757
- publicKeyCredential: WebauthnParser.encodeAuthenticationResult(credential),
1758
- userAgent: navigator.userAgent,
1759
- };
1760
- }
1761
- }
1762
-
1763
- /**
1764
- * WebAuthn SDK implementation
1765
- */
1766
- class WebAuthnSdk {
1767
- constructor() {
1768
- this._initialized = false;
1769
- this._authenticationHandler = new AuthenticationHandler();
1770
- this._registrationHandler = new RegistrationHandler();
1771
- this._approvalHandler = new ApprovalHandler();
1772
- this._crossDeviceHandler = new WebauthnCrossDeviceHandler(this._authenticationHandler, this._registrationHandler, this._approvalHandler);
1773
- this.authenticate = {
1774
- modal: async (username, options) => {
1775
- this.initCheck();
1776
- return this._authenticationHandler.modal({ username, options });
1777
- },
1778
- autofill: {
1779
- activate: (handlers, username) => {
1780
- this.initCheck();
1781
- return this._authenticationHandler.activateAutofill(handlers, username);
1782
- },
1783
- abort: () => {
1784
- return this._authenticationHandler.abortAutofill();
1785
- },
1786
- },
1787
- };
1788
- this.approve = {
1789
- modal: async (username, approvalData) => {
1790
- this.initCheck();
1791
- return this._approvalHandler.modal({ username, approvalData });
1792
- },
1793
- };
1794
- this.register = async (username, options) => {
1795
- this.initCheck();
1796
- return this._registrationHandler.register({ username }, options);
1797
- };
1798
- this.crossDevice = {
1799
- init: {
1800
- registration: async (params) => {
1801
- this.initCheck();
1802
- return this._crossDeviceHandler.init.registration(params);
1803
- },
1804
- authentication: async (params) => {
1805
- this.initCheck();
1806
- return this._crossDeviceHandler.init.authentication(params);
1807
- },
1808
- approval: async (params) => {
1809
- this.initCheck();
1810
- return this._crossDeviceHandler.init.approval(params);
1811
- },
1812
- },
1813
- authenticate: {
1814
- modal: async (crossDeviceTicketId) => {
1815
- this.initCheck();
1816
- return this._crossDeviceHandler.authenticate.modal(crossDeviceTicketId);
1817
- },
1818
- },
1819
- approve: {
1820
- modal: async (crossDeviceTicketId) => {
1821
- this.initCheck();
1822
- return this._crossDeviceHandler.approve.modal(crossDeviceTicketId);
1823
- },
1824
- },
1825
- register: async (crossDeviceTicketId, options) => {
1826
- this.initCheck();
1827
- return this._crossDeviceHandler.register(crossDeviceTicketId, options);
1828
- },
1829
- attachDevice: async (crossDeviceTicketId) => {
1830
- this.initCheck();
1831
- return this._crossDeviceHandler.attachDevice(crossDeviceTicketId);
1832
- },
1833
- };
1834
- this.isPlatformAuthenticatorSupported = async () => {
1835
- var _a;
1836
- try {
1837
- return await ((_a = WebAuthnSdk.StaticPublicKeyCredential) === null || _a === void 0 ? void 0 : _a.isUserVerifyingPlatformAuthenticatorAvailable());
1838
- }
1839
- catch (error) {
1840
- return false;
1841
- }
1842
- };
1843
- this.isAutofillSupported = async () => {
1844
- var _a, _b;
1845
- return !!(((_a = WebAuthnSdk.StaticPublicKeyCredential) === null || _a === void 0 ? void 0 : _a.isConditionalMediationAvailable) &&
1846
- (await ((_b = WebAuthnSdk.StaticPublicKeyCredential) === null || _b === void 0 ? void 0 : _b.isConditionalMediationAvailable())));
1847
- };
1848
- }
1849
- async init(clientId, options) {
1850
- try {
1851
- if (!clientId) {
1852
- throw new NotInitializedError('Invalid clientId', { clientId });
1853
- }
1854
- if (options.webauthnApiPaths) {
1855
- const defaultPaths = SdkApiClient.getDefaultPaths();
1856
- if (symmetricDifference(Object.keys(options.webauthnApiPaths), Object.keys(defaultPaths)).length) {
1857
- throw new NotInitializedError('Invalid custom paths', {
1858
- customApiPaths: options.webauthnApiPaths,
1859
- });
1860
- }
1861
- }
1862
- SdkApiClient.init(clientId, options);
1863
- this._initialized = true;
1864
- }
1865
- catch (error) {
1866
- if (isBaseSdkError(error)) {
1867
- throw error;
1868
- }
1869
- else {
1870
- throw new NotInitializedError('Failed to initialize SDK');
1871
- }
1872
- }
1873
- }
1874
- getDefaultPaths() {
1875
- this.initCheck();
1876
- return SdkApiClient.getDefaultPaths();
1877
- }
1878
- getApiPaths() {
1879
- this.initCheck();
1880
- return SdkApiClient.getApiPaths();
1881
- }
1882
- initCheck() {
1883
- if (!this._initialized) {
1884
- throw new NotInitializedError();
1885
- }
1886
- }
1887
- }
1888
- // We are accessing the PublicKeyCredential from the global scope here in order to make it possibly undefined - for browsers which do not support WebAuthn
1889
- WebAuthnSdk.StaticPublicKeyCredential = window.PublicKeyCredential;
1890
-
1891
- const common = new Common('webauthn');
1892
- const webauthn$1 = new WebAuthnSdk();
1893
- common.events.on(common.events.MODULE_INITIALIZED, () => {
1894
- var _a;
1895
- const config = common.moduleMetadata.getInitConfig();
1896
- if (!((_a = config === null || config === void 0 ? void 0 : config.webauthn) === null || _a === void 0 ? void 0 : _a.serverPath)) {
1897
- return;
1898
- }
1899
- const { clientId, webauthn: webauthnConfig } = config;
1900
- webauthn$1.init(clientId, { ...webauthnConfig });
1901
- });
1902
- /**
1903
- * Returns the authentication flows for webauthn
1904
- */
1905
- const authenticate = {
1906
- modal: async (username, options) => {
1907
- webauthn$1.initCheck();
1908
- return webauthn$1.authenticate.modal(username, options);
1909
- },
1910
- autofill: {
1911
- activate: (handlers, username) => {
1912
- webauthn$1.initCheck();
1913
- webauthn$1.authenticate.autofill.activate(handlers, username);
1914
- },
1915
- abort: () => {
1916
- webauthn$1.initCheck();
1917
- webauthn$1.authenticate.autofill.abort();
1918
- },
1919
- },
1920
- };
1921
- const approve = {
1922
- modal: async (username, approvalData) => {
1923
- webauthn$1.initCheck();
1924
- return webauthn$1.approve.modal(username, approvalData);
1925
- },
1926
- };
1927
- /**
1928
- * Invokes a WebAuthn credential registration for the specified user, including prompting the user for biometrics.
1929
- * If registration is completed successfully, this call will return a promise that resolves to the credential result, which is an object encoded as a base64 string. This encoded result should then be passed to the relevant backend registration endpoint to complete the registration for either a [logged-in user](/openapi/user/backend-webauthn/#operation/webauthn-registration) or [logged-out user](/openapi/user/backend-webauthn/#operation/webauthn-registration-external).
1930
- *
1931
- * If registration fails, an SdkError will be thrown.
1932
- *
1933
- * @param username WebAuthn username to register
1934
- * @param options Additional configuration for registration flow
1935
- * @throws {@link ErrorCode.NotInitialized}
1936
- * @throws {@link ErrorCode.RegistrationFailed}
1937
- * @throws {@link ErrorCode.RegistrationCanceled}
1938
- */
1939
- async function register(username, options) {
1940
- webauthn$1.initCheck();
1941
- return webauthn$1.register(username, options);
1942
- }
1943
- /**
1944
- * Returns webauthn cross device flows
1945
- * @type WebauthnCrossDeviceFlows
1946
- */
1947
- const { crossDevice } = webauthn$1;
1948
- /**
1949
- * Indicates whether this browser supports WebAuthn, and has a platform authenticator
1950
- */
1951
- const { isPlatformAuthenticatorSupported } = webauthn$1;
1952
- /**
1953
- * Indicates whether this browser supports Passkey Autofill
1954
- */
1955
- const { isAutofillSupported } = webauthn$1;
1956
- /**
1957
- * Returns the default API paths for webauthn
1958
- */
1959
- const { getDefaultPaths } = webauthn$1;
1960
- // @ts-ignore
1961
- window.localWebAuthnSDK = webauthn$1;
1962
-
1963
- var moduleExports = /*#__PURE__*/Object.freeze({
1964
- __proto__: null,
1965
- get WebauthnCrossDeviceStatus () { return WebauthnCrossDeviceStatus; },
1966
- approve: approve,
1967
- authenticate: authenticate,
1968
- crossDevice: crossDevice,
1969
- getDefaultPaths: getDefaultPaths,
1970
- isAutofillSupported: isAutofillSupported,
1971
- isPlatformAuthenticatorSupported: isPlatformAuthenticatorSupported,
1972
- register: register
1973
- });
1974
-
1975
- const PACKAGE_VERSION = "1.17.2";
1976
-
1977
- // Create namespace object for tree-shakable import
1978
- const webauthn = {
1979
- initialize: initialize,
1980
- ...moduleExports
1981
- };
1982
-
1983
- export { PACKAGE_VERSION, WebauthnCrossDeviceStatus, approve, authenticate, crossDevice, getDefaultPaths, initialize, isAutofillSupported, isPlatformAuthenticatorSupported, register, webauthn };
1
+ "undefined"==typeof globalThis&&("undefined"!=typeof window?(window.globalThis=window,window.global=window):"undefined"!=typeof self&&(self.globalThis=self,self.global=self));const t=Symbol("MODULE_INITIALIZED"),e=new Map;function i(t,i){var a,n;null===(a=e.get(t))||void 0===a||a.forEach((n=t=>t(i),function(){try{return n(...arguments)}catch(t){console.log(t)}}))}let a=null;function n(t){a=t}var r=Object.freeze({__proto__:null,getInitConfig:function(){return a},get initConfig(){return a},setInitConfig:n});function s(e){n(e),i(t,void 0)}var o=Object.freeze({__proto__:null,initialize:s});function c(t,e,i){return(e=function(t){var e=function(t,e){if("object"!=typeof t||!t)return t;var i=t[Symbol.toPrimitive];if(void 0!==i){var a=i.call(t,e||"default");if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"==typeof e?e:e+""}(e))in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}function l(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,a)}return i}function d(t){for(var e=1;e<arguments.length;e++){var i=null!=arguments[e]?arguments[e]:{};e%2?l(Object(i),!0).forEach((function(e){c(t,e,i[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):l(Object(i)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))}))}return t}function u(t,e){return Object.entries(e).reduce(((e,i)=>{let[a,n]=i;return d(d({},e),{},{[a]:h.isPrototypeOf(n)?new n(t.slug):"function"==typeof n?n.bind(t):"object"==typeof n&&!Array.isArray(n)&&n?u(t,n):n})}),{})}class h{constructor(t){this.slug=t}static create(t){return class extends h{constructor(e){super(e),Object.assign(this,u(this,t(this)))}}}}var y=Object.freeze({__proto__:null,Agent:h}),p=Object.freeze({__proto__:null,MODULE_INITIALIZED:t,emit:i,off:function(t,i){const a=e.get(t);if(!a)return;const n=a.indexOf(i);-1!==n&&a.splice(n,1)},on:function(t,i){var a;e.has(t)?null===(a=e.get(t))||void 0===a||a.push(i):e.set(t,[i])}});function g(t,e){const i=!t||"object"!=typeof t||Array.isArray(t)?{}:t;return[e.reduce(((t,e)=>{if(e in t){const i=t[e];if(null!==i&&"object"==typeof i&&!Array.isArray(i))return i}const i={};return t[e]=i,i}),i),i]}const v="tsec",f="general";function w(t){return t?f:a.clientId}function m(t){return function(t){if(!t)return{};try{return JSON.parse(t)}catch(t){return{}}}((t?sessionStorage:localStorage).getItem(v))}function b(t,e){const i=t?sessionStorage:localStorage,a=e(m(t));i.setItem(v,JSON.stringify(a))}var D=Object.freeze({__proto__:null,COMMON_STORAGE_KEY:v,GENERAL_ID_KEY:f,getValue:function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const i=w(!!e.isGeneral),a=m(!!e.sessionOnly),[n]=g(a,[this.slug.toString(),i]);return n[t]},hasValue:function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const i=w(!!e.isGeneral);return function(t,e){let i=t;return e.every((t=>!(!i||"object"!=typeof i||Array.isArray(i)||!(t in i)||(i=i[t],0))),t)}(m(!!e.sessionOnly),[this.slug.toString(),i,t])},removeValue:function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const i=w(!!e.isGeneral);b(!!e.sessionOnly,(e=>{const[a,n]=g(e,[this.slug.toString(),i]);return delete a[t],n}))},setValue:function(t,e){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const a=w(!!i.isGeneral);b(!!i.sessionOnly,(i=>{const[n,r]=g(i,[this.slug.toString(),a]);return n[t]=e,r}))}});const A="RSA-PSS",_=async(t,e)=>await window.crypto.subtle.generateKey({name:t,modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},!1,e),S=async()=>await _("RSA-OAEP",["encrypt","decrypt"]),C=async()=>await _(A,["sign"]),k=async(t,e)=>{const i=(new TextEncoder).encode(e);return await window.crypto.subtle.sign({name:A,saltLength:32},t,i)};class K{constructor(t,e,i){this.slug=t,this.dbName=e,this.dbVersion=i}queryObjectStore(t,e){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{attemptToRecoverDB:a=!0}=i,n=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB||window.shimIndexedDB,r=`${this.slug}:${this.dbName}`,s=n.open(r,this.dbVersion||1);s.onupgradeneeded=()=>{var e;const i=s.result;(null===(e=null==i?void 0:i.objectStoreNames)||void 0===e?void 0:e.contains)&&!i.objectStoreNames.contains(t)&&i.createObjectStore(t,{keyPath:"key"})},s.onsuccess=()=>{const o=s.result;let c;try{c=o.transaction(t,(null==i?void 0:i.operation)||"readwrite")}catch(s){if(a&&s instanceof DOMException&&"NotFoundError"===s.name){o.close();return void(n.deleteDatabase(r).onsuccess=()=>{this.queryObjectStore(t,e,d(d({},i),{},{attemptToRecoverDB:!1}))})}throw s}const l=c.objectStore(t);e(l,o),c.oncomplete||(c.oncomplete=()=>{o.close()})}}put(t,e,i){return new Promise(((a,n)=>{this.queryObjectStore(t,(t=>{const r=t.put({key:e,value:i});r.onsuccess=()=>{a(r.result)},r.onerror=t=>{n("Failed adding item to objectStore, err: "+t)}}))}))}add(t,e,i){return new Promise(((a,n)=>{this.queryObjectStore(t,(t=>{const r=t.add({key:e,value:i});r.onsuccess=()=>{a(r.result)},r.onerror=t=>{const e=t.target.error;n(e)}}))}))}get(t,e){return new Promise(((i,a)=>{this.queryObjectStore(t,(t=>{const n=t.get(e);n.onsuccess=()=>{var t;n.result?i(null===(t=n.result)||void 0===t?void 0:t.value):i(void 0)},n.onerror=t=>{a("Failed adding item to objectStore, err: "+t)}}))}))}getAll(t,e){return new Promise(((i,a)=>{this.queryObjectStore(t,(t=>{const n=t.getAll(null,e);n.onsuccess=()=>{if(n.result){const t=n.result;(null==t?void 0:t.length)?i(t.map((t=>null==t?void 0:t.value))):i(t)}else i([])},n.onerror=t=>{a("Failed getting items, err: "+t)}}))}))}delete(t,e){return new Promise(((i,a)=>{this.queryObjectStore(t,(t=>{const n=t.delete(e);n.onsuccess=()=>{i()},n.onerror=t=>{a(`Failed deleting key: '${e}' from objectStore, err: `+t)}}))}))}clear(t){return new Promise(((e,i)=>{this.queryObjectStore(t,(t=>{const a=t.clear();a.onsuccess=()=>{e()},a.onerror=t=>{i("Failed clearing objectStore, err: "+t)}}))}))}executeTransaction(t,e){return new Promise(((i,a)=>{this.queryObjectStore(t,((t,n)=>{const r=t.transaction;r.onerror=()=>{a(`Transaction failed: ${r.error}`)},r.onabort=()=>{a("Transaction aborted")},r.oncomplete=()=>{n.close(),i()};for(const i of e){let e;if("delete"===i.type)e=t.delete(i.key);else{if("put"!==i.type)return r.abort(),void a("Unknown operation type");e=t.put({key:i.key,value:i.value})}e.onerror=()=>{r.abort(),a(`Operation failed: ${e.error}`)}}}))}))}}const R="init",P="completed",T="RSA2048",I=[R,P];class O{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"sign",i=arguments.length>2?arguments[2]:void 0;var a,n,r,s,o;this.agent=t,this.keysType=e,this.options=i,this._extractingKeysPromise=null;const c=!(null===(a=this.options)||void 0===a?void 0:a.productScope),l=null===(n=this.options)||void 0===n?void 0:n.fallbackClientId;this.keysDatabaseName=c||!(null===(r=this.options)||void 0===r?void 0:r.indexedDBName)?"ts_crypto_binding":this.options.indexedDBName,this.dbVersion=c?1:(null===(s=this.options)||void 0===s?void 0:s.dbVersion)||1,this.keysStoreName=c||!(null===(o=this.options)||void 0===o?void 0:o.keysStoreName)?"identifiers_store":this.options.keysStoreName;const d=c?"platform":t.slug,u=this.getClientConfiguration(l,d);this.indexedDBClient=new K(u.main,this.keysDatabaseName,this.dbVersion),this.indexedDBClientFallback=new K(u.fallback,this.keysDatabaseName,this.dbVersion)}getClientConfiguration(t,e){return t?{main:e,fallback:`${e}:${t}`}:{main:e,fallback:`${e}:${a.clientId}`}}getKeysRecordKey(){return`${this.keysType}_keys`}getRotatedKeysRecordKey(){return`rotated_${this.keysType}_keys`}getRotatedKeysRecordKeyPending(){return`rotated_pending_${this.keysType}_keys`}arrayBufferToBase64(t){return window.btoa(String.fromCharCode(...new Uint8Array(t)))}async getPKRepresentations(t){const e=await crypto.subtle.exportKey("spki",t);return{arrayBufferKey:e,base64Key:this.arrayBufferToBase64(e)}}async generateKeyPair(){return"sign"==this.keysType?await C():await S()}async calcKeyIdentifier(t){const e=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(e)).map((t=>t.toString(16).padStart(2,"0"))).join("")}async extractKeysData(){if(this._extractingKeysPromise)return this._extractingKeysPromise;this._extractingKeysPromise=(async()=>{var t,e;const i=(null===(e=null===(t=this.options)||void 0===t?void 0:t.keyRotation)||void 0===e?void 0:e.isEnabled)?await this.getRotatedKeysData():await this.getKeysData(),{base64Key:a}=await this.getPKRepresentations(i.publicKey);return this.publicKeyBase64=a,this.keyIdentifier=i.keyIdentifier,i})();try{return await this._extractingKeysPromise}finally{this._extractingKeysPromise=null}}async generateKeyPairData(t){const e=await this.generateKeyPair(),{arrayBufferKey:i}=await this.getPKRepresentations(e.publicKey),a=t||await this.calcKeyIdentifier(i);return d(d({},e),{},{keyIdentifier:a,createdDate:Date.now()})}shouldKeyBeRotated(t){var e;const i=null===(e=this.options)||void 0===e?void 0:e.keyRotation;if(!(null==i?void 0:i.isEnabled)||!i.expiryDays||void 0===i.startedAt)return!1;const a=24*i.expiryDays*60*60*1e3,n=t.createdDate&&t.createdDate>=i.startedAt?t.createdDate:i.startedAt;return Date.now()-n>a-2592e6}async extractMainKeysData(){return await this.indexedDBClient.get(this.keysStoreName,this.getKeysRecordKey())}async extractFallbackMainKeysData(){return await this.indexedDBClientFallback.get(this.keysStoreName,this.getKeysRecordKey())}async extractRotatedKeysData(){return await this.indexedDBClient.get(this.keysStoreName,this.getRotatedKeysRecordKey())}async extractPendingRotatedKeysData(){return await this.indexedDBClient.get(this.keysStoreName,this.getRotatedKeysRecordKeyPending())}async saveKeyData(t,e){try{return await this.indexedDBClient.add(this.keysStoreName,t,e),e}catch(e){if(e instanceof DOMException&&"ConstraintError"===e.name){const e=await this.indexedDBClient.get(this.keysStoreName,t);if(e)return e}throw e}}async getKeysData(){const t=this.getKeysRecordKey();let e=await this.extractMainKeysData();if(e)return e;if(e=await this.extractFallbackMainKeysData(),e)return this.saveKeyData(t,e);const i=await this.generateKeyPairData();return this.saveKeyData(t,i)}async getOrCreateRotatedKeys(){let t=await this.extractRotatedKeysData();if(!t){const e=this.getRotatedKeysRecordKey(),i=await this.getKeysData(),a=d(d({},i),{},{createdDate:i.createdDate||Date.now()});t=await this.saveKeyData(e,a)}return t}async getRotatedKeysData(){const t=await this.getOrCreateRotatedKeys();if(this.shouldKeyBeRotated(t)){if(!await this.extractPendingRotatedKeysData()){const e=this.getRotatedKeysRecordKeyPending(),i=await this.generateKeyPairData(t.keyIdentifier);await this.saveKeyData(e,i)}}return t}async getPublicData(){return this.publicKeyBase64&&this.keyIdentifier||await this.extractKeysData(),{publicKey:this.publicKeyBase64,keyIdentifier:this.keyIdentifier}}async sign(t){if("sign"==this.keysType){const{privateKey:e}=await this.extractKeysData(),i=await k(e,t);return this.arrayBufferToBase64(i)}throw new Error("keysType must be 'sign' in order to use sign keys")}async clearKeys(){const t=this.getKeysRecordKey();await this.indexedDBClient.delete(this.keysStoreName,t)}getBaseRotationPayload(){return{keyIdentifier:this.keyIdentifier,slot:this.getRotatedKeysRecordKey(),publicKey:this.publicKeyBase64,publicKeyType:T,tenantId:this.options.keyRotation.tenantId}}async getRotationData(){var t,e;if(!(null===(e=null===(t=this.options)||void 0===t?void 0:t.keyRotation)||void 0===e?void 0:e.isEnabled))return;this.publicKeyBase64&&this.keyIdentifier||await this.extractKeysData();const i=await this.extractPendingRotatedKeysData();if(i){const{base64Key:t}=await this.getPKRepresentations(i.publicKey),{privateKey:e}=await this.extractKeysData(),a=d(d({},this.getBaseRotationPayload()),{},{newPublicKey:t,createdDate:i.createdDate,newPublicKeyType:T}),n=JSON.stringify(a);return{data:n,signature:await this.signPayload(n,e)}}const a=await this.extractRotatedKeysData();if(a&&!1===a.confirmed){await this.extractKeysData();const t=JSON.stringify(this.getBaseRotationPayload());return{data:t,signature:await this.signPayload(t,a.privateKey)}}}async signPayload(t,e){const i=await k(e,t);return this.arrayBufferToBase64(i)}async handleRotateResponse(t){if(I.includes(t))if(t===R){const t=await this.extractPendingRotatedKeysData();if(t){const e=d(d({},t),{},{confirmed:!1});await this.indexedDBClient.executeTransaction(this.keysStoreName,[{type:"delete",key:this.getRotatedKeysRecordKey()},{type:"put",key:this.getRotatedKeysRecordKey(),value:e},{type:"delete",key:this.getRotatedKeysRecordKeyPending()}]);const{base64Key:i}=await this.getPKRepresentations(t.publicKey);this.publicKeyBase64=i,this.keyIdentifier=t.keyIdentifier}}else if(t===P){const t=await this.extractRotatedKeysData();t&&!1===t.confirmed&&await this.indexedDBClient.put(this.keysStoreName,this.getRotatedKeysRecordKey(),d(d({},t),{},{confirmed:!0}))}}}var j=Object.freeze({__proto__:null,createCryptoBinding:function(){return new O(this,arguments.length>0&&void 0!==arguments[0]?arguments[0]:"sign",arguments.length>1?arguments[1]:void 0)},generateRSAKeyPair:S,generateRSASignKeyPair:C,signAssymetric:k,verifyAssymetric:async(t,e,i)=>{const a=(new TextEncoder).encode(e);return await window.crypto.subtle.verify(A,t,i,a)}}),x=Object.freeze({__proto__:null});const B=h.create((t=>{class e extends Error{constructor(e,i){super(`${t.slug}-${e} ${i}`)}}return{TsError:e,TsInternalError:class extends e{constructor(t){super(t,"Internal error")}}}}));var E=h.create((()=>d({exceptions:B},y)));class N{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];this.agent=t,this.middlewares=e,this.logs=[]}info(t,e){this.pushLog(3,t,e)}warn(t,e){this.pushLog(4,t,e)}error(t,e){this.pushLog(5,t,e)}pushLog(t,e){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};this.logs.push({timestamp:Date.now(),module:this.agent.slug,severity:t,fields:i,message:e});const a=this.middlewares.map((t=>t(this)));Promise.all(a).catch((()=>{}))}}var F=Object.freeze({__proto__:null,consoleMiddleware:function(t){const e=t.logs[t.logs.length-1];console.log(`${e.severity} ${e.message}`,e.fields)},createSdkLogger:function(){return new N(this,arguments.length>0&&void 0!==arguments[0]?arguments[0]:[])}});function H(t,e){if(!(null==t?void 0:t.trim()))return"";if(function(t){try{return new URL(t),!0}catch(t){return!1}}(t))return t;const i="http://mock.com",a=new URL(i);a.search=(null==e?void 0:e.toString())||"",a.pathname=t;return a.href.replace(i,"")}const M={"Content-Type":"application/json","X-TS-client-time":(new Date).toUTCString(),"X-TS-ua":navigator.userAgent};function $(t,e,i){var a;const n=(r=e||{},encodeURI(JSON.stringify(r)).split(/%..|./).length-1);var r;return{method:t,headers:d(d(d({},{"X-TS-body-size":String(n)}),M),i||{}),body:null!==(a=e&&JSON.stringify(e||{}))&&void 0!==a?a:void 0}}function q(t,e,i,a,n){const r=H(t,a),s=$(e,i,n);return fetch(r,s)}async function z(t,e,i,a,n){let r;if(r=await q(t,e,i,a,n),!r.ok)throw new Error("Request failed");return r}var J=Object.freeze({__proto__:null,httpDelete:async function(t,e){const i=await z(t,"DELETE",void 0,void 0,e);return d(d({data:await i.json()},i),{},{headers:i.headers})},httpGet:async function(t,e,i){const a=await z(t,"GET",void 0,e,i);return d(d({data:await a.json()},a),{},{headers:a.headers})},httpPost:async function(t,e,i,a){const n=await z(t,"POST",e,i,a);return d(d({data:await n.json()},n),{},{headers:n.headers})},httpPut:async function(t,e,i,a){const n=await z(t,"PUT",e,i,a);return d(d({data:await n.json()},n),{},{headers:n.headers})},init:$}),L=h.create((()=>({events:p,moduleMetadata:r,mainEntry:o,utils:E,storage:D,crypto:j,indexedDB:x,logger:F,http:J})));class U{static arrayBufferToBase64(t){return btoa(String.fromCharCode(...new Uint8Array(t)))}static base64ToArrayBuffer(t){return Uint8Array.from(atob(t),(t=>t.charCodeAt(0)))}static stringToBase64(t){return btoa(t)}static jsonToBase64(t){const e=JSON.stringify(t);return btoa(e)}static base64ToJson(t){const e=atob(t);return JSON.parse(e)}}const V={log:console.log,error:console.error};var G,W;!function(t){t.NotInitialized="not_initialized",t.AuthenticationFailed="authentication_failed",t.AuthenticationAbortedTimeout="authentication_aborted_timeout",t.AuthenticationCanceled="webauthn_authentication_canceled",t.RegistrationFailed="registration_failed",t.AlreadyRegistered="username_already_registered",t.RegistrationAbortedTimeout="registration_aborted_timeout",t.RegistrationCanceled="webauthn_registration_canceled",t.AutofillAuthenticationAborted="autofill_authentication_aborted",t.AuthenticationProcessAlreadyActive="authentication_process_already_active",t.InvalidApprovalData="invalid_approval_data",t.FailedToInitCrossDeviceSession="cross_device_init_failed",t.FailedToGetCrossDeviceStatus="cross_device_status_failed",t.Unknown="unknown"}(G||(G={}));class Z extends Error{constructor(t,e){super(t),this.errorCode=G.NotInitialized,this.data=e}}class X extends Z{constructor(t,e){super(null!=t?t:"WebAuthnSdk is not initialized",e),this.errorCode=G.NotInitialized}}class Y extends Z{constructor(t,e){super(null!=t?t:"Authentication failed with an error",e),this.errorCode=G.AuthenticationFailed}}class Q extends Z{constructor(t,e){super(null!=t?t:"Authentication was canceled by the user or got timeout",e),this.errorCode=G.AuthenticationCanceled}}class tt extends Z{constructor(t,e){super(null!=t?t:"Registration failed with an error",e),this.errorCode=G.RegistrationFailed}}class et extends Z{constructor(t,e){super(null!=t?t:"Registration was canceled by the user or got timeout",e),this.errorCode=G.RegistrationCanceled}}class it extends Z{constructor(t){super(null!=t?t:"Autofill flow was aborted"),this.errorCode=G.AutofillAuthenticationAborted}}class at extends Z{constructor(t){super(null!=t?t:"Operation was aborted by timeout"),this.errorCode=G.AutofillAuthenticationAborted}}class nt extends Z{constructor(t){super(null!=t?t:"Passkey with this username is already registered with the relying party."),this.errorCode=G.AlreadyRegistered}}class rt extends Z{constructor(t,e){super(null!=t?t:"Authentication process is already active",e),this.errorCode=G.AuthenticationProcessAlreadyActive}}class st extends Z{constructor(t,e){super(null!=t?t:"Invalid approval data",e),this.errorCode=G.InvalidApprovalData}}class ot extends Z{constructor(t,e){super(null!=t?t:"Failed to init cross device authentication",e),this.errorCode=G.FailedToInitCrossDeviceSession}}class ct extends Z{constructor(t,e){super(null!=t?t:"Failed to get cross device status",e),this.errorCode=G.FailedToGetCrossDeviceStatus}}function lt(t){return t.errorCode&&Object.values(G).includes(t.errorCode)}!function(t){t[t.persistent=0]="persistent",t[t.session=1]="session"}(W||(W={}));class dt{static get(t){return dt.getStorageMedium(dt.allowedKeys[t]).getItem(dt.getStorageKey(t))||void 0}static set(t,e){return dt.getStorageMedium(dt.allowedKeys[t]).setItem(dt.getStorageKey(t),e)}static remove(t){dt.getStorageMedium(dt.allowedKeys[t]).removeItem(dt.getStorageKey(t))}static clear(t){for(const[e,i]of Object.entries(dt.allowedKeys)){const a=e;t&&this.configurationKeys.includes(a)||dt.getStorageMedium(i).removeItem(dt.getStorageKey(a))}}static getStorageKey(t){return`WebAuthnSdk:${t}`}static getStorageMedium(t){return t===W.session?sessionStorage:localStorage}}dt.allowedKeys={clientId:W.session},dt.configurationKeys=["clientId"];class ut{static isNewApiDomain(t){return t&&(this.newApiDomains.includes(t)||t.startsWith("api.")&&t.endsWith(".transmitsecurity.io"))}static dnsPrefetch(t){const e=document.createElement("link");e.rel="dns-prefetch",e.href=t,document.head.appendChild(e)}static preconnect(t,e){const i=document.createElement("link");i.rel="preconnect",i.href=t,e&&(i.crossOrigin="anonymous"),document.head.appendChild(i)}static warmupConnection(t){this.dnsPrefetch(t),this.preconnect(t,!1),this.preconnect(t,!0)}static init(t,e){var i,a;try{this._serverPath=new URL(e.serverPath),this.isNewApiDomain(null===(i=this._serverPath)||void 0===i?void 0:i.hostname)&&this.warmupConnection(this._serverPath.origin),this._apiPaths=null!==(a=e.webauthnApiPaths)&&void 0!==a?a:this.getDefaultPaths(),this._clientId=t,dt.set("clientId",t)}catch(t){throw new X("Invalid options.serverPath",{error:t})}}static getDefaultPaths(){var t;const e=this.isNewApiDomain(null===(t=this._serverPath)||void 0===t?void 0:t.hostname)?"/cis":"";return{startAuthentication:`${e}/v1/auth/webauthn/authenticate/start`,startRegistration:`${e}/v1/auth/webauthn/register/start`,initCrossDeviceAuthentication:`${e}/v1/auth/webauthn/cross-device/authenticate/init`,startCrossDeviceAuthentication:`${e}/v1/auth/webauthn/cross-device/authenticate/start`,startCrossDeviceRegistration:`${e}/v1/auth/webauthn/cross-device/register/start`,getCrossDeviceTicketStatus:`${e}/v1/auth/webauthn/cross-device/status`,attachDeviceToCrossDeviceSession:`${e}/v1/auth/webauthn/cross-device/attach-device`}}static getApiPaths(){return this._apiPaths}static async sendRequest(t,e,i){V.log(`[WebAuthn SDK] Calling ${e.method} ${t}...`);const a=new URL(this._serverPath);return a.pathname=t,i&&(a.search=i),fetch(a.toString(),e)}static async startRegistration(t){const e=await this.sendRequest(this._apiPaths.startRegistration,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d(d({client_id:this.getValidatedClientId(),username:t.username,display_name:t.displayName},t.timeout&&{timeout:t.timeout}),t.limitSingleCredentialToDevice&&{limit_single_credential_to_device:t.limitSingleCredentialToDevice}))});if(!(null==e?void 0:e.ok))throw new Y("Failed to start registration",null==e?void 0:e.body);return await e.json()}static async startAuthentication(t){const e=await this.sendRequest(this._apiPaths.startAuthentication,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d(d(d({client_id:this.getValidatedClientId()},t.username&&{username:t.username}),t.approvalData&&{approval_data:t.approvalData}),t.timeout&&{timeout:t.timeout}))});if(!(null==e?void 0:e.ok))throw new Y("Failed to start authentication",null==e?void 0:e.body);return await e.json()}static async initCrossDeviceAuthentication(t){const e=await this.sendRequest(this._apiPaths.initCrossDeviceAuthentication,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d(d({client_id:this.getValidatedClientId()},t.username&&{username:t.username}),t.approvalData&&{approval_data:t.approvalData}))});if(!(null==e?void 0:e.ok))throw new ot(void 0,null==e?void 0:e.body);return await e.json()}static async getCrossDeviceTicketStatus(t){const e=await this.sendRequest(this._apiPaths.getCrossDeviceTicketStatus,{method:"GET"},`cross_device_ticket_id=${t.ticketId}`);if(!(null==e?void 0:e.ok))throw new ct(void 0,null==e?void 0:e.body);return await e.json()}static async startCrossDeviceAuthentication(t){const e=await this.sendRequest(this._apiPaths.startCrossDeviceAuthentication,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cross_device_ticket_id:t.ticketId})});if(!(null==e?void 0:e.ok))throw new Y("Failed to start cross device authentication",null==e?void 0:e.body);return await e.json()}static async startCrossDeviceRegistration(t){const e=await this.sendRequest(this._apiPaths.startCrossDeviceRegistration,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cross_device_ticket_id:t.ticketId})});if(!(null==e?void 0:e.ok))throw new tt("Failed to start cross device registration",null==e?void 0:e.body);return await e.json()}static async attachDeviceToCrossDeviceSession(t){const e=await this.sendRequest(this._apiPaths.attachDeviceToCrossDeviceSession,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cross_device_ticket_id:t.ticketId})});if(!(null==e?void 0:e.ok))throw new tt("Failed to attach device to cross device session",null==e?void 0:e.body);return await e.json()}static getValidatedClientId(){var t;const e=null!==(t=this._clientId)&&void 0!==t?t:dt.get("clientId");if(!e)throw new X("Missing clientId");return e}}var ht,yt,pt,gt;ut.newApiDomains=["api.idsec-dev.com","api.idsec-stg.com"],function(t){t.InputAutofill="input-autofill",t.Modal="modal"}(ht||(ht={})),function(t){t.Pending="pending",t.Scanned="scanned",t.Success="success",t.Error="error",t.Timeout="timeout",t.Aborted="aborted"}(yt||(yt={})),function(t){t.toAuthenticationError=t=>lt(t)?t:"NotAllowedError"===t.name?new Q:"OperationError"===t.name?new rt(t.message):"SecurityError"===t.name?new Y(t.message):t===G.AuthenticationAbortedTimeout?new at:"AbortError"===t.name||t===G.AutofillAuthenticationAborted?new it:new Y("Something went wrong during authentication",{error:t}),t.toRegistrationError=t=>lt(t)?t:"NotAllowedError"===t.name?new et:"SecurityError"===t.name?new tt(t.message):"InvalidStateError"===t.name?new nt:t===G.RegistrationAbortedTimeout?new at:new tt("Something went wrong during registration",{error:t})}(pt||(pt={})),function(t){t.processCredentialRequestOptions=t=>d(d({},t),{},{challenge:U.base64ToArrayBuffer(t.challenge),allowCredentials:t.allowCredentials.map((t=>d(d({},t),{},{id:U.base64ToArrayBuffer(t.id)})))}),t.processCredentialCreationOptions=(t,e)=>{var i;const a=JSON.parse(JSON.stringify(t));return a.challenge=U.base64ToArrayBuffer(t.challenge),a.user.id=U.base64ToArrayBuffer(t.user.id),(null==e?void 0:e.limitSingleCredentialToDevice)&&(a.excludeCredentials=null===(i=t.excludeCredentials)||void 0===i?void 0:i.map((t=>d(d({},t),{},{id:U.base64ToArrayBuffer(t.id)})))),(null==e?void 0:e.registerAsDiscoverable)?(a.authenticatorSelection.residentKey="preferred",a.authenticatorSelection.requireResidentKey=!0):(a.authenticatorSelection.residentKey="discouraged",a.authenticatorSelection.requireResidentKey=!1),a.authenticatorSelection.authenticatorAttachment=(null==e?void 0:e.allowCrossPlatformAuthenticators)?void 0:"platform",a},t.encodeAuthenticationResult=t=>{const{authenticatorAttachment:e}=t,i=t.response;return{id:t.id,rawId:U.arrayBufferToBase64(t.rawId),response:{authenticatorData:U.arrayBufferToBase64(i.authenticatorData),clientDataJSON:U.arrayBufferToBase64(i.clientDataJSON),signature:U.arrayBufferToBase64(i.signature),userHandle:U.arrayBufferToBase64(i.userHandle)},authenticatorAttachment:e,type:t.type}},t.encodeRegistrationResult=t=>{const{authenticatorAttachment:e}=t,i=t.response;return{id:t.id,rawId:U.arrayBufferToBase64(t.rawId),response:{attestationObject:U.arrayBufferToBase64(i.attestationObject),clientDataJSON:U.arrayBufferToBase64(i.clientDataJSON)},authenticatorAttachment:e,type:t.type}}}(gt||(gt={}));class vt{async modal(t){try{const e=await this.performAuthentication(d(d({},t),{},{mediationType:ht.Modal}));return U.jsonToBase64(e)}catch(t){throw pt.toAuthenticationError(t)}}activateAutofill(t,e){const{onSuccess:i,onError:a,onReady:n}=t;this.performAuthentication({username:e,mediationType:ht.InputAutofill,onReady:n}).then((t=>{i(U.jsonToBase64(t))})).catch((t=>{const e=pt.toAuthenticationError(t);if(!a)throw e;a(e)}))}abortAutofill(){this.abortController&&this.abortController.abort(G.AutofillAuthenticationAborted)}abortAuthentication(){this.abortController&&this.abortController.abort(G.AuthenticationAbortedTimeout)}async performAuthentication(t){var e,i;const a="crossDeviceTicketId"in t?await ut.startCrossDeviceAuthentication({ticketId:t.crossDeviceTicketId}):await ut.startAuthentication({username:t.username,timeout:null===(e=t.options)||void 0===e?void 0:e.timeout}),n=a.credential_request_options,r=gt.processCredentialRequestOptions(n),s=this.getMediatedCredentialRequest(r,t.mediationType);t.mediationType===ht.InputAutofill&&(null===(i=t.onReady)||void 0===i||i.call(t));const o=await navigator.credentials.get(s).catch((t=>{throw pt.toAuthenticationError(t)}));return{webauthnSessionId:a.webauthn_session_id,publicKeyCredential:gt.encodeAuthenticationResult(o),userAgent:navigator.userAgent}}getMediatedCredentialRequest(t,e){const i={publicKey:t};return this.abortController=new AbortController,i.signal=this.abortController&&this.abortController.signal,e===ht.InputAutofill?i.mediation="conditional":t.timeout&&setTimeout((()=>{this.abortAuthentication()}),t.timeout),i}}class ft{constructor(t,e){this.handler=t,this.intervalInMs=e}begin(){var t;this.intervalId=window.setInterval((t=this.handler,async function(){t.isRunning||(t.isRunning=!0,await t(...arguments),t.isRunning=!1)}),this.intervalInMs)}stop(){clearInterval(this.intervalId)}}const wt=/^[A-Za-z0-9\-_.: ]*$/;function mt(t){if(t&&(!function(t){return Object.keys(t).length<=10}(t)||!function(t){const e=t=>"string"==typeof t,i=t=>wt.test(t);return Object.keys(t).every((a=>e(a)&&e(t[a])&&i(a)&&i(t[a])))}(t)))throw V.error("Failed validating approval data"),new st("Provided approval data should have 10 properties max. Also, it should contain only \n alphanumeric characters, numbers, and the special characters: '-', '_', '.'")}class bt{constructor(t,e,i){this.authenticationHandler=t,this.registrationHandler=e,this.approvalHandler=i,this.init={registration:async t=>(this.ticketStatus=yt.Pending,this.pollCrossDeviceSession(t.crossDeviceTicketId,t.handlers)),authentication:async t=>{const{username:e}=t,i=(await ut.initCrossDeviceAuthentication(d({},e&&{username:e}))).cross_device_ticket_id;return this.ticketStatus=yt.Pending,this.pollCrossDeviceSession(i,t.handlers)},approval:async t=>{const{username:e,approvalData:i}=t;mt(i);const a=(await ut.initCrossDeviceAuthentication({username:e,approvalData:i})).cross_device_ticket_id;return this.ticketStatus=yt.Pending,this.pollCrossDeviceSession(a,t.handlers)}},this.authenticate={modal:async t=>this.authenticationHandler.modal({crossDeviceTicketId:t})},this.approve={modal:async t=>this.approvalHandler.modal({crossDeviceTicketId:t})}}async register(t,e){return this.registrationHandler.register({crossDeviceTicketId:t},e)}async attachDevice(t){const e=await ut.attachDeviceToCrossDeviceSession({ticketId:t});return d({status:e.status,startedAt:e.started_at},e.approval_data&&{approvalData:e.approval_data})}async pollCrossDeviceSession(t,e){return this.poller=new ft((async()=>{var i,a;const n=await ut.getCrossDeviceTicketStatus({ticketId:t}),r=n.status;if(r!==this.ticketStatus)switch(this.ticketStatus=r,r){case yt.Scanned:await e.onDeviceAttach();break;case yt.Error:case yt.Timeout:case yt.Aborted:await e.onFailure(n),null===(i=this.poller)||void 0===i||i.stop();break;case yt.Success:if("onCredentialRegister"in e)await e.onCredentialRegister();else{if(!n.session_id)throw new ct("Cross device session is complete without returning session_id",n);await e.onCredentialAuthenticate(n.session_id)}null===(a=this.poller)||void 0===a||a.stop()}}),1e3),this.poller.begin(),setTimeout((()=>{var t;null===(t=this.poller)||void 0===t||t.stop(),e.onFailure({status:yt.Timeout})}),3e5),{crossDeviceTicketId:t,stop:()=>{var t;null===(t=this.poller)||void 0===t||t.stop()}}}}class Dt{async register(t,e){this.abortController=new AbortController;const i=d({allowCrossPlatformAuthenticators:!("crossDeviceTicketId"in t),registerAsDiscoverable:!0},e);try{const a="crossDeviceTicketId"in t?await ut.startCrossDeviceRegistration({ticketId:t.crossDeviceTicketId}):await ut.startRegistration({username:t.username,displayName:(null==e?void 0:e.displayName)||t.username,timeout:null==e?void 0:e.timeout,limitSingleCredentialToDevice:null==e?void 0:e.limitSingleCredentialToDevice}),n=gt.processCredentialCreationOptions(a.credential_creation_options,i);setTimeout((()=>{this.abortRegistration()}),n.timeout);const r=await this.registerCredential(n),s={webauthnSessionId:a.webauthn_session_id,publicKeyCredential:r,userAgent:navigator.userAgent};return U.jsonToBase64(s)}catch(t){throw pt.toRegistrationError(t)}}abortRegistration(){this.abortController&&this.abortController.abort(G.RegistrationAbortedTimeout)}async registerCredential(t){const e=await navigator.credentials.create({publicKey:t,signal:this.abortController&&this.abortController.signal}).catch((t=>{throw pt.toRegistrationError(t)}));return gt.encodeRegistrationResult(e)}}class At{async modal(t){try{const e=await this.performApproval(t);return U.jsonToBase64(e)}catch(t){throw pt.toAuthenticationError(t)}}async performApproval(t){"approvalData"in t&&mt(t.approvalData);const e="crossDeviceTicketId"in t?await ut.startCrossDeviceAuthentication({ticketId:t.crossDeviceTicketId}):await ut.startAuthentication({username:t.username,approvalData:t.approvalData}),i=e.credential_request_options,a=gt.processCredentialRequestOptions(i),n=await navigator.credentials.get({publicKey:a}).catch((t=>{throw pt.toAuthenticationError(t)}));return{webauthnSessionId:e.webauthn_session_id,publicKeyCredential:gt.encodeAuthenticationResult(n),userAgent:navigator.userAgent}}}class _t{constructor(){this._initialized=!1,this._authenticationHandler=new vt,this._registrationHandler=new Dt,this._approvalHandler=new At,this._crossDeviceHandler=new bt(this._authenticationHandler,this._registrationHandler,this._approvalHandler),this.authenticate={modal:async(t,e)=>(this.initCheck(),this._authenticationHandler.modal({username:t,options:e})),autofill:{activate:(t,e)=>(this.initCheck(),this._authenticationHandler.activateAutofill(t,e)),abort:()=>this._authenticationHandler.abortAutofill()}},this.approve={modal:async(t,e)=>(this.initCheck(),this._approvalHandler.modal({username:t,approvalData:e}))},this.register=async(t,e)=>(this.initCheck(),this._registrationHandler.register({username:t},e)),this.crossDevice={init:{registration:async t=>(this.initCheck(),this._crossDeviceHandler.init.registration(t)),authentication:async t=>(this.initCheck(),this._crossDeviceHandler.init.authentication(t)),approval:async t=>(this.initCheck(),this._crossDeviceHandler.init.approval(t))},authenticate:{modal:async t=>(this.initCheck(),this._crossDeviceHandler.authenticate.modal(t))},approve:{modal:async t=>(this.initCheck(),this._crossDeviceHandler.approve.modal(t))},register:async(t,e)=>(this.initCheck(),this._crossDeviceHandler.register(t,e)),attachDevice:async t=>(this.initCheck(),this._crossDeviceHandler.attachDevice(t))},this.isPlatformAuthenticatorSupported=async()=>{var t;try{return await(null===(t=_t.StaticPublicKeyCredential)||void 0===t?void 0:t.isUserVerifyingPlatformAuthenticatorAvailable())}catch(t){return!1}},this.isAutofillSupported=async()=>{var t,e;return!(!(null===(t=_t.StaticPublicKeyCredential)||void 0===t?void 0:t.isConditionalMediationAvailable)||!await(null===(e=_t.StaticPublicKeyCredential)||void 0===e?void 0:e.isConditionalMediationAvailable()))}}async init(t,e){try{if(!t)throw new X("Invalid clientId",{clientId:t});if(e.webauthnApiPaths){const t=ut.getDefaultPaths();if(function(t,e){const i=new Set(t),a=new Set(e);return[...t.filter((t=>!a.has(t))),...e.filter((t=>!i.has(t)))]}(Object.keys(e.webauthnApiPaths),Object.keys(t)).length)throw new X("Invalid custom paths",{customApiPaths:e.webauthnApiPaths})}ut.init(t,e),this._initialized=!0}catch(t){throw lt(t)?t:new X("Failed to initialize SDK")}}getDefaultPaths(){return this.initCheck(),ut.getDefaultPaths()}getApiPaths(){return this.initCheck(),ut.getApiPaths()}initCheck(){if(!this._initialized)throw new X}}_t.StaticPublicKeyCredential=window.PublicKeyCredential;const St=new L("webauthn"),Ct=new _t;St.events.on(St.events.MODULE_INITIALIZED,(()=>{var t;const e=St.moduleMetadata.getInitConfig();if(!(null===(t=null==e?void 0:e.webauthn)||void 0===t?void 0:t.serverPath))return;const{clientId:i,webauthn:a}=e;Ct.init(i,d({},a))}));const kt={modal:async(t,e)=>(Ct.initCheck(),Ct.authenticate.modal(t,e)),autofill:{activate:(t,e)=>{Ct.initCheck(),Ct.authenticate.autofill.activate(t,e)},abort:()=>{Ct.initCheck(),Ct.authenticate.autofill.abort()}}},Kt={modal:async(t,e)=>(Ct.initCheck(),Ct.approve.modal(t,e))};async function Rt(t,e){return Ct.initCheck(),Ct.register(t,e)}const{crossDevice:Pt}=Ct,{isPlatformAuthenticatorSupported:Tt}=Ct,{isAutofillSupported:It}=Ct,{getDefaultPaths:Ot}=Ct;window.localWebAuthnSDK=Ct;const jt="1.18.2",xt={initialize:s,...Object.freeze({__proto__:null,get WebauthnCrossDeviceStatus(){return yt},approve:Kt,authenticate:kt,crossDevice:Pt,getDefaultPaths:Ot,isAutofillSupported:It,isPlatformAuthenticatorSupported:Tt,register:Rt})};export{jt as PACKAGE_VERSION,yt as WebauthnCrossDeviceStatus,Kt as approve,kt as authenticate,Pt as crossDevice,Ot as getDefaultPaths,s as initialize,It as isAutofillSupported,Tt as isPlatformAuthenticatorSupported,Rt as register,xt as webauthn};