@authsignal/browser 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/passkey-api-client.d.ts +1 -2
- package/dist/api/types.d.ts +1 -1
- package/dist/authsignal.d.ts +2 -0
- package/dist/index.js +873 -1354
- package/dist/index.min.js +1 -2
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -90,663 +90,125 @@ var AuthsignalWindowMessage;
|
|
|
90
90
|
AuthsignalWindowMessage["AUTHSIGNAL_CLOSE_POPUP"] = "AUTHSIGNAL_CLOSE_POPUP";
|
|
91
91
|
})(AuthsignalWindowMessage || (AuthsignalWindowMessage = {}));
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
93
|
+
/******************************************************************************
|
|
94
|
+
Copyright (c) Microsoft Corporation.
|
|
95
|
+
|
|
96
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
97
|
+
purpose with or without fee is hereby granted.
|
|
98
|
+
|
|
99
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
100
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
101
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
102
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
103
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
104
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
105
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
106
|
+
***************************************************************************** */
|
|
107
|
+
|
|
108
|
+
function __rest(s, e) {
|
|
109
|
+
var t = {};
|
|
110
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
111
|
+
t[p] = s[p];
|
|
112
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
113
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
114
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
115
|
+
t[p[i]] = s[p[i]];
|
|
116
|
+
}
|
|
117
|
+
return t;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
121
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
122
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
123
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
124
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
125
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
126
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function __generator(thisArg, body) {
|
|
131
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
132
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
133
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
134
|
+
function step(op) {
|
|
135
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
136
|
+
while (_) try {
|
|
137
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
138
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
139
|
+
switch (op[0]) {
|
|
140
|
+
case 0: case 1: t = op; break;
|
|
141
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
142
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
143
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
144
|
+
default:
|
|
145
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
146
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
147
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
148
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
149
|
+
if (t[2]) _.ops.pop();
|
|
150
|
+
_.trys.pop(); continue;
|
|
151
|
+
}
|
|
152
|
+
op = body.call(thisArg, _);
|
|
153
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
154
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
155
|
+
}
|
|
124
156
|
}
|
|
125
157
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])',
|
|
130
|
-
'input[type="radio"]:not([disabled]):not([tabindex^="-"])',
|
|
131
|
-
'select:not([disabled]):not([tabindex^="-"])',
|
|
132
|
-
'textarea:not([disabled]):not([tabindex^="-"])',
|
|
133
|
-
'button:not([disabled]):not([tabindex^="-"])',
|
|
134
|
-
'iframe:not([tabindex^="-"])',
|
|
135
|
-
'audio[controls]:not([tabindex^="-"])',
|
|
136
|
-
'video[controls]:not([tabindex^="-"])',
|
|
137
|
-
'[contenteditable]:not([tabindex^="-"])',
|
|
138
|
-
'[tabindex]:not([tabindex^="-"])',
|
|
139
|
-
];
|
|
140
|
-
|
|
141
|
-
var TAB_KEY = 'Tab';
|
|
142
|
-
var ESCAPE_KEY = 'Escape';
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Define the constructor to instantiate a dialog
|
|
146
|
-
*
|
|
147
|
-
* @constructor
|
|
148
|
-
* @param {Element} element
|
|
149
|
-
*/
|
|
150
|
-
function A11yDialog(element) {
|
|
151
|
-
// Prebind the functions that will be bound in addEventListener and
|
|
152
|
-
// removeEventListener to avoid losing references
|
|
153
|
-
this._show = this.show.bind(this);
|
|
154
|
-
this._hide = this.hide.bind(this);
|
|
155
|
-
this._maintainFocus = this._maintainFocus.bind(this);
|
|
156
|
-
this._bindKeypress = this._bindKeypress.bind(this);
|
|
157
|
-
|
|
158
|
-
this.$el = element;
|
|
159
|
-
this.shown = false;
|
|
160
|
-
this._id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;
|
|
161
|
-
this._previouslyFocused = null;
|
|
162
|
-
this._listeners = {};
|
|
163
|
-
|
|
164
|
-
// Initialise everything needed for the dialog to work properly
|
|
165
|
-
this.create();
|
|
158
|
+
/* [@simplewebauthn/browser@9.0.1] */
|
|
159
|
+
function utf8StringToBuffer(value) {
|
|
160
|
+
return new TextEncoder().encode(value);
|
|
166
161
|
}
|
|
167
162
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.$el.setAttribute('tabindex', -1);
|
|
178
|
-
|
|
179
|
-
if (!this.$el.hasAttribute('role')) {
|
|
180
|
-
this.$el.setAttribute('role', 'dialog');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Keep a collection of dialog openers, each of which will be bound a click
|
|
184
|
-
// event listener to open the dialog
|
|
185
|
-
this._openers = $$('[data-a11y-dialog-show="' + this._id + '"]');
|
|
186
|
-
this._openers.forEach(
|
|
187
|
-
function (opener) {
|
|
188
|
-
opener.addEventListener('click', this._show);
|
|
189
|
-
}.bind(this)
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
// Keep a collection of dialog closers, each of which will be bound a click
|
|
193
|
-
// event listener to close the dialog
|
|
194
|
-
const $el = this.$el;
|
|
195
|
-
|
|
196
|
-
this._closers = $$('[data-a11y-dialog-hide]', this.$el)
|
|
197
|
-
// This filter is necessary in case there are nested dialogs, so that
|
|
198
|
-
// only closers from the current dialog are retrieved and effective
|
|
199
|
-
.filter(function (closer) {
|
|
200
|
-
// Testing for `[aria-modal="true"]` is not enough since this attribute
|
|
201
|
-
// and the collect of closers is done at instantation time, when nested
|
|
202
|
-
// dialogs might not have yet been instantiated. Note that if the dialogs
|
|
203
|
-
// are manually instantiated, this could still fail because none of these
|
|
204
|
-
// selectors would match; this would cause closers to close all parent
|
|
205
|
-
// dialogs instead of just the current one
|
|
206
|
-
return closer.closest('[aria-modal="true"], [data-a11y-dialog]') === $el
|
|
207
|
-
})
|
|
208
|
-
.concat($$('[data-a11y-dialog-hide="' + this._id + '"]'));
|
|
209
|
-
|
|
210
|
-
this._closers.forEach(
|
|
211
|
-
function (closer) {
|
|
212
|
-
closer.addEventListener('click', this._hide);
|
|
213
|
-
}.bind(this)
|
|
214
|
-
);
|
|
163
|
+
function bufferToBase64URLString(buffer) {
|
|
164
|
+
const bytes = new Uint8Array(buffer);
|
|
165
|
+
let str = '';
|
|
166
|
+
for (const charCode of bytes) {
|
|
167
|
+
str += String.fromCharCode(charCode);
|
|
168
|
+
}
|
|
169
|
+
const base64String = btoa(str);
|
|
170
|
+
return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
171
|
+
}
|
|
215
172
|
|
|
216
|
-
|
|
217
|
-
|
|
173
|
+
function base64URLStringToBuffer(base64URLString) {
|
|
174
|
+
const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
|
|
175
|
+
const padLength = (4 - (base64.length % 4)) % 4;
|
|
176
|
+
const padded = base64.padEnd(base64.length + padLength, '=');
|
|
177
|
+
const binary = atob(padded);
|
|
178
|
+
const buffer = new ArrayBuffer(binary.length);
|
|
179
|
+
const bytes = new Uint8Array(buffer);
|
|
180
|
+
for (let i = 0; i < binary.length; i++) {
|
|
181
|
+
bytes[i] = binary.charCodeAt(i);
|
|
182
|
+
}
|
|
183
|
+
return buffer;
|
|
184
|
+
}
|
|
218
185
|
|
|
219
|
-
|
|
220
|
-
|
|
186
|
+
function browserSupportsWebAuthn() {
|
|
187
|
+
return (window?.PublicKeyCredential !== undefined &&
|
|
188
|
+
typeof window.PublicKeyCredential === 'function');
|
|
189
|
+
}
|
|
221
190
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
A11yDialog.prototype.show = function (event) {
|
|
231
|
-
// If the dialog is already open, abort
|
|
232
|
-
if (this.shown) {
|
|
233
|
-
return this
|
|
234
|
-
}
|
|
191
|
+
function toPublicKeyCredentialDescriptor(descriptor) {
|
|
192
|
+
const { id } = descriptor;
|
|
193
|
+
return {
|
|
194
|
+
...descriptor,
|
|
195
|
+
id: base64URLStringToBuffer(id),
|
|
196
|
+
transports: descriptor.transports,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
235
199
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.shown = true;
|
|
200
|
+
function isValidDomain(hostname) {
|
|
201
|
+
return (hostname === 'localhost' ||
|
|
202
|
+
/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname));
|
|
203
|
+
}
|
|
241
204
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
document.addEventListener('keydown', this._bindKeypress);
|
|
250
|
-
|
|
251
|
-
// Execute all callbacks registered for the `show` event
|
|
252
|
-
this._fire('show', event);
|
|
253
|
-
|
|
254
|
-
return this
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Hide the dialog element, enable all the targets (siblings), restore the
|
|
259
|
-
* focus to the previously active element, stop listening for some specific
|
|
260
|
-
* key presses and fire all registered callbacks for `hide` event
|
|
261
|
-
*
|
|
262
|
-
* @param {CustomEvent} event
|
|
263
|
-
* @return {this}
|
|
264
|
-
*/
|
|
265
|
-
A11yDialog.prototype.hide = function (event) {
|
|
266
|
-
// If the dialog is already closed, abort
|
|
267
|
-
if (!this.shown) {
|
|
268
|
-
return this
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
this.shown = false;
|
|
272
|
-
this.$el.setAttribute('aria-hidden', 'true');
|
|
273
|
-
|
|
274
|
-
// If there was a focused element before the dialog was opened (and it has a
|
|
275
|
-
// `focus` method), restore the focus back to it
|
|
276
|
-
// See: https://github.com/KittyGiraudel/a11y-dialog/issues/108
|
|
277
|
-
if (this._previouslyFocused && this._previouslyFocused.focus) {
|
|
278
|
-
this._previouslyFocused.focus();
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Remove the focus event listener to the body element and stop listening
|
|
282
|
-
// for specific key presses
|
|
283
|
-
document.body.removeEventListener('focus', this._maintainFocus, true);
|
|
284
|
-
document.removeEventListener('keydown', this._bindKeypress);
|
|
285
|
-
|
|
286
|
-
// Execute all callbacks registered for the `hide` event
|
|
287
|
-
this._fire('hide', event);
|
|
288
|
-
|
|
289
|
-
return this
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Destroy the current instance (after making sure the dialog has been hidden)
|
|
294
|
-
* and remove all associated listeners from dialog openers and closers
|
|
295
|
-
*
|
|
296
|
-
* @return {this}
|
|
297
|
-
*/
|
|
298
|
-
A11yDialog.prototype.destroy = function () {
|
|
299
|
-
// Hide the dialog to avoid destroying an open instance
|
|
300
|
-
this.hide();
|
|
301
|
-
|
|
302
|
-
// Remove the click event listener from all dialog openers
|
|
303
|
-
this._openers.forEach(
|
|
304
|
-
function (opener) {
|
|
305
|
-
opener.removeEventListener('click', this._show);
|
|
306
|
-
}.bind(this)
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
// Remove the click event listener from all dialog closers
|
|
310
|
-
this._closers.forEach(
|
|
311
|
-
function (closer) {
|
|
312
|
-
closer.removeEventListener('click', this._hide);
|
|
313
|
-
}.bind(this)
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
// Execute all callbacks registered for the `destroy` event
|
|
317
|
-
this._fire('destroy');
|
|
318
|
-
|
|
319
|
-
// Keep an object of listener types mapped to callback functions
|
|
320
|
-
this._listeners = {};
|
|
321
|
-
|
|
322
|
-
return this
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Register a new callback for the given event type
|
|
327
|
-
*
|
|
328
|
-
* @param {string} type
|
|
329
|
-
* @param {Function} handler
|
|
330
|
-
*/
|
|
331
|
-
A11yDialog.prototype.on = function (type, handler) {
|
|
332
|
-
if (typeof this._listeners[type] === 'undefined') {
|
|
333
|
-
this._listeners[type] = [];
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
this._listeners[type].push(handler);
|
|
337
|
-
|
|
338
|
-
return this
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Unregister an existing callback for the given event type
|
|
343
|
-
*
|
|
344
|
-
* @param {string} type
|
|
345
|
-
* @param {Function} handler
|
|
346
|
-
*/
|
|
347
|
-
A11yDialog.prototype.off = function (type, handler) {
|
|
348
|
-
var index = (this._listeners[type] || []).indexOf(handler);
|
|
349
|
-
|
|
350
|
-
if (index > -1) {
|
|
351
|
-
this._listeners[type].splice(index, 1);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return this
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Iterate over all registered handlers for given type and call them all with
|
|
359
|
-
* the dialog element as first argument, event as second argument (if any). Also
|
|
360
|
-
* dispatch a custom event on the DOM element itself to make it possible to
|
|
361
|
-
* react to the lifecycle of auto-instantiated dialogs.
|
|
362
|
-
*
|
|
363
|
-
* @access private
|
|
364
|
-
* @param {string} type
|
|
365
|
-
* @param {CustomEvent} event
|
|
366
|
-
*/
|
|
367
|
-
A11yDialog.prototype._fire = function (type, event) {
|
|
368
|
-
var listeners = this._listeners[type] || [];
|
|
369
|
-
var domEvent = new CustomEvent(type, { detail: event });
|
|
370
|
-
|
|
371
|
-
this.$el.dispatchEvent(domEvent);
|
|
372
|
-
|
|
373
|
-
listeners.forEach(
|
|
374
|
-
function (listener) {
|
|
375
|
-
listener(this.$el, event);
|
|
376
|
-
}.bind(this)
|
|
377
|
-
);
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Private event handler used when listening to some specific key presses
|
|
382
|
-
* (namely ESCAPE and TAB)
|
|
383
|
-
*
|
|
384
|
-
* @access private
|
|
385
|
-
* @param {Event} event
|
|
386
|
-
*/
|
|
387
|
-
A11yDialog.prototype._bindKeypress = function (event) {
|
|
388
|
-
// This is an escape hatch in case there are nested dialogs, so the keypresses
|
|
389
|
-
// are only reacted to for the most recent one
|
|
390
|
-
const focused = document.activeElement;
|
|
391
|
-
if (focused && focused.closest('[aria-modal="true"]') !== this.$el) return
|
|
392
|
-
|
|
393
|
-
// If the dialog is shown and the ESCAPE key is being pressed, prevent any
|
|
394
|
-
// further effects from the ESCAPE key and hide the dialog, unless its role
|
|
395
|
-
// is 'alertdialog', which should be modal
|
|
396
|
-
if (
|
|
397
|
-
this.shown &&
|
|
398
|
-
event.key === ESCAPE_KEY &&
|
|
399
|
-
this.$el.getAttribute('role') !== 'alertdialog'
|
|
400
|
-
) {
|
|
401
|
-
event.preventDefault();
|
|
402
|
-
this.hide(event);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// If the dialog is shown and the TAB key is being pressed, make sure the
|
|
406
|
-
// focus stays trapped within the dialog element
|
|
407
|
-
if (this.shown && event.key === TAB_KEY) {
|
|
408
|
-
trapTabKey(this.$el, event);
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Private event handler used when making sure the focus stays within the
|
|
414
|
-
* currently open dialog
|
|
415
|
-
*
|
|
416
|
-
* @access private
|
|
417
|
-
* @param {Event} event
|
|
418
|
-
*/
|
|
419
|
-
A11yDialog.prototype._maintainFocus = function (event) {
|
|
420
|
-
// If the dialog is shown and the focus is not within a dialog element (either
|
|
421
|
-
// this one or another one in case of nested dialogs) or within an element
|
|
422
|
-
// with the `data-a11y-dialog-focus-trap-ignore` attribute, move it back to
|
|
423
|
-
// its first focusable child.
|
|
424
|
-
// See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
|
|
425
|
-
if (
|
|
426
|
-
this.shown &&
|
|
427
|
-
!event.target.closest('[aria-modal="true"]') &&
|
|
428
|
-
!event.target.closest('[data-a11y-dialog-ignore-focus-trap]')
|
|
429
|
-
) {
|
|
430
|
-
moveFocusToDialog(this.$el);
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Convert a NodeList into an array
|
|
436
|
-
*
|
|
437
|
-
* @param {NodeList} collection
|
|
438
|
-
* @return {Array<Element>}
|
|
439
|
-
*/
|
|
440
|
-
function toArray(collection) {
|
|
441
|
-
return Array.prototype.slice.call(collection)
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Query the DOM for nodes matching the given selector, scoped to context (or
|
|
446
|
-
* the whole document)
|
|
447
|
-
*
|
|
448
|
-
* @param {String} selector
|
|
449
|
-
* @param {Element} [context = document]
|
|
450
|
-
* @return {Array<Element>}
|
|
451
|
-
*/
|
|
452
|
-
function $$(selector, context) {
|
|
453
|
-
return toArray((context || document).querySelectorAll(selector))
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Set the focus to the first element with `autofocus` with the element or the
|
|
458
|
-
* element itself
|
|
459
|
-
*
|
|
460
|
-
* @param {Element} node
|
|
461
|
-
*/
|
|
462
|
-
function moveFocusToDialog(node) {
|
|
463
|
-
var focused = node.querySelector('[autofocus]') || node;
|
|
464
|
-
|
|
465
|
-
focused.focus();
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Get the focusable children of the given element
|
|
470
|
-
*
|
|
471
|
-
* @param {Element} node
|
|
472
|
-
* @return {Array<Element>}
|
|
473
|
-
*/
|
|
474
|
-
function getFocusableChildren(node) {
|
|
475
|
-
return $$(focusableSelectors.join(','), node).filter(function (child) {
|
|
476
|
-
return !!(
|
|
477
|
-
child.offsetWidth ||
|
|
478
|
-
child.offsetHeight ||
|
|
479
|
-
child.getClientRects().length
|
|
480
|
-
)
|
|
481
|
-
})
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* Trap the focus inside the given element
|
|
486
|
-
*
|
|
487
|
-
* @param {Element} node
|
|
488
|
-
* @param {Event} event
|
|
489
|
-
*/
|
|
490
|
-
function trapTabKey(node, event) {
|
|
491
|
-
var focusableChildren = getFocusableChildren(node);
|
|
492
|
-
var focusedItemIndex = focusableChildren.indexOf(document.activeElement);
|
|
493
|
-
|
|
494
|
-
// If the SHIFT key is being pressed while tabbing (moving backwards) and
|
|
495
|
-
// the currently focused item is the first one, move the focus to the last
|
|
496
|
-
// focusable item from the dialog element
|
|
497
|
-
if (event.shiftKey && focusedItemIndex === 0) {
|
|
498
|
-
focusableChildren[focusableChildren.length - 1].focus();
|
|
499
|
-
event.preventDefault();
|
|
500
|
-
// If the SHIFT key is not being pressed (moving forwards) and the currently
|
|
501
|
-
// focused item is the last one, move the focus to the first focusable item
|
|
502
|
-
// from the dialog element
|
|
503
|
-
} else if (
|
|
504
|
-
!event.shiftKey &&
|
|
505
|
-
focusedItemIndex === focusableChildren.length - 1
|
|
506
|
-
) {
|
|
507
|
-
focusableChildren[0].focus();
|
|
508
|
-
event.preventDefault();
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
function instantiateDialogs() {
|
|
513
|
-
$$('[data-a11y-dialog]').forEach(function (node) {
|
|
514
|
-
new A11yDialog(node);
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
if (typeof document !== 'undefined') {
|
|
519
|
-
if (document.readyState === 'loading') {
|
|
520
|
-
document.addEventListener('DOMContentLoaded', instantiateDialogs);
|
|
521
|
-
} else {
|
|
522
|
-
if (window.requestAnimationFrame) {
|
|
523
|
-
window.requestAnimationFrame(instantiateDialogs);
|
|
524
|
-
} else {
|
|
525
|
-
window.setTimeout(instantiateDialogs, 16);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
var CONTAINER_ID = "__authsignal-popup-container";
|
|
531
|
-
var CONTENT_ID = "__authsignal-popup-content";
|
|
532
|
-
var OVERLAY_ID = "__authsignal-popup-overlay";
|
|
533
|
-
var STYLE_ID = "__authsignal-popup-style";
|
|
534
|
-
var IFRAME_ID = "__authsignal-popup-iframe";
|
|
535
|
-
var DEFAULT_WIDTH = "385px";
|
|
536
|
-
var INITIAL_HEIGHT = "384px";
|
|
537
|
-
var PopupHandler = /** @class */ (function () {
|
|
538
|
-
function PopupHandler(_a) {
|
|
539
|
-
var width = _a.width;
|
|
540
|
-
this.popup = null;
|
|
541
|
-
if (document.querySelector("#".concat(CONTAINER_ID))) {
|
|
542
|
-
throw new Error("Multiple instances of Authsignal popup is not supported.");
|
|
543
|
-
}
|
|
544
|
-
this.create({ width: width });
|
|
545
|
-
}
|
|
546
|
-
PopupHandler.prototype.create = function (_a) {
|
|
547
|
-
var _this = this;
|
|
548
|
-
var _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH : _b;
|
|
549
|
-
var isWidthValidCSSValue = CSS.supports("width", width);
|
|
550
|
-
var popupWidth = width;
|
|
551
|
-
if (!isWidthValidCSSValue) {
|
|
552
|
-
console.warn("Invalid CSS value for `popupOptions.width`. Using default value instead.");
|
|
553
|
-
popupWidth = DEFAULT_WIDTH;
|
|
554
|
-
}
|
|
555
|
-
// Create dialog container
|
|
556
|
-
var container = document.createElement("div");
|
|
557
|
-
container.setAttribute("id", CONTAINER_ID);
|
|
558
|
-
container.setAttribute("aria-hidden", "true");
|
|
559
|
-
// Create dialog overlay
|
|
560
|
-
var overlay = document.createElement("div");
|
|
561
|
-
overlay.setAttribute("id", OVERLAY_ID);
|
|
562
|
-
overlay.setAttribute("data-a11y-dialog-hide", "true");
|
|
563
|
-
// Create dialog content
|
|
564
|
-
var content = document.createElement("div");
|
|
565
|
-
content.setAttribute("id", CONTENT_ID);
|
|
566
|
-
document.body.appendChild(container);
|
|
567
|
-
// Create CSS for dialog
|
|
568
|
-
var style = document.createElement("style");
|
|
569
|
-
style.setAttribute("id", STYLE_ID);
|
|
570
|
-
style.textContent = "\n #".concat(CONTAINER_ID, ",\n #").concat(OVERLAY_ID, " {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n\n #").concat(CONTAINER_ID, " {\n z-index: 2147483647;\n display: flex;\n }\n\n #").concat(CONTAINER_ID, "[aria-hidden='true'] {\n display: none;\n }\n\n #").concat(OVERLAY_ID, " {\n background-color: rgba(0, 0, 0, 0.18);\n }\n\n #").concat(CONTENT_ID, " {\n margin: auto;\n z-index: 2147483647;\n position: relative;\n background-color: transparent;\n border-radius: 8px;\n width: ").concat(popupWidth, ";\n }\n\n #").concat(CONTENT_ID, " iframe {\n width: 1px;\n min-width: 100%;\n border-radius: inherit;\n max-height: 95vh;\n height: ").concat(INITIAL_HEIGHT, ";\n }\n ");
|
|
571
|
-
// Attach the created elements
|
|
572
|
-
document.head.insertAdjacentElement("beforeend", style);
|
|
573
|
-
container.appendChild(overlay);
|
|
574
|
-
container.appendChild(content);
|
|
575
|
-
this.popup = new A11yDialog(container);
|
|
576
|
-
// Make sure to remove any trace of the dialog on hide
|
|
577
|
-
this.popup.on("hide", function () {
|
|
578
|
-
_this.destroy();
|
|
579
|
-
});
|
|
580
|
-
};
|
|
581
|
-
PopupHandler.prototype.destroy = function () {
|
|
582
|
-
var dialogEl = document.querySelector("#".concat(CONTAINER_ID));
|
|
583
|
-
var styleEl = document.querySelector("#".concat(STYLE_ID));
|
|
584
|
-
if (dialogEl && styleEl) {
|
|
585
|
-
document.body.removeChild(dialogEl);
|
|
586
|
-
document.head.removeChild(styleEl);
|
|
587
|
-
}
|
|
588
|
-
window.removeEventListener("message", resizeIframe);
|
|
589
|
-
};
|
|
590
|
-
PopupHandler.prototype.show = function (_a) {
|
|
591
|
-
var _b;
|
|
592
|
-
var url = _a.url;
|
|
593
|
-
if (!this.popup) {
|
|
594
|
-
throw new Error("Popup is not initialized");
|
|
595
|
-
}
|
|
596
|
-
var iframe = document.createElement("iframe");
|
|
597
|
-
iframe.setAttribute("id", IFRAME_ID);
|
|
598
|
-
iframe.setAttribute("name", "authsignal");
|
|
599
|
-
iframe.setAttribute("title", "Authsignal multi-factor authentication");
|
|
600
|
-
iframe.setAttribute("src", url);
|
|
601
|
-
iframe.setAttribute("frameborder", "0");
|
|
602
|
-
iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *; clipboard-write");
|
|
603
|
-
var dialogContent = document.querySelector("#".concat(CONTENT_ID));
|
|
604
|
-
if (dialogContent) {
|
|
605
|
-
dialogContent.appendChild(iframe);
|
|
606
|
-
}
|
|
607
|
-
window.addEventListener("message", resizeIframe);
|
|
608
|
-
(_b = this.popup) === null || _b === void 0 ? void 0 : _b.show();
|
|
609
|
-
};
|
|
610
|
-
PopupHandler.prototype.close = function () {
|
|
611
|
-
if (!this.popup) {
|
|
612
|
-
throw new Error("Popup is not initialized");
|
|
613
|
-
}
|
|
614
|
-
this.popup.hide();
|
|
615
|
-
};
|
|
616
|
-
PopupHandler.prototype.on = function (event, handler) {
|
|
617
|
-
if (!this.popup) {
|
|
618
|
-
throw new Error("Popup is not initialized");
|
|
619
|
-
}
|
|
620
|
-
this.popup.on(event, handler);
|
|
621
|
-
};
|
|
622
|
-
return PopupHandler;
|
|
623
|
-
}());
|
|
624
|
-
function resizeIframe(event) {
|
|
625
|
-
var iframeEl = document.querySelector("#".concat(IFRAME_ID));
|
|
626
|
-
if (iframeEl && event.data.height) {
|
|
627
|
-
iframeEl.style.height = event.data.height + "px";
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
/******************************************************************************
|
|
632
|
-
Copyright (c) Microsoft Corporation.
|
|
633
|
-
|
|
634
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
635
|
-
purpose with or without fee is hereby granted.
|
|
636
|
-
|
|
637
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
638
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
639
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
640
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
641
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
642
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
643
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
644
|
-
***************************************************************************** */
|
|
645
|
-
|
|
646
|
-
function __rest(s, e) {
|
|
647
|
-
var t = {};
|
|
648
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
649
|
-
t[p] = s[p];
|
|
650
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
651
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
652
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
653
|
-
t[p[i]] = s[p[i]];
|
|
654
|
-
}
|
|
655
|
-
return t;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
659
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
660
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
661
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
662
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
663
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
664
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
function __generator(thisArg, body) {
|
|
669
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
670
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
671
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
672
|
-
function step(op) {
|
|
673
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
674
|
-
while (_) try {
|
|
675
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
676
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
677
|
-
switch (op[0]) {
|
|
678
|
-
case 0: case 1: t = op; break;
|
|
679
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
680
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
681
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
682
|
-
default:
|
|
683
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
684
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
685
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
686
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
687
|
-
if (t[2]) _.ops.pop();
|
|
688
|
-
_.trys.pop(); continue;
|
|
689
|
-
}
|
|
690
|
-
op = body.call(thisArg, _);
|
|
691
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
692
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/* [@simplewebauthn/browser@8.2.1] */
|
|
697
|
-
function utf8StringToBuffer(value) {
|
|
698
|
-
return new TextEncoder().encode(value);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
function bufferToBase64URLString(buffer) {
|
|
702
|
-
const bytes = new Uint8Array(buffer);
|
|
703
|
-
let str = '';
|
|
704
|
-
for (const charCode of bytes) {
|
|
705
|
-
str += String.fromCharCode(charCode);
|
|
706
|
-
}
|
|
707
|
-
const base64String = btoa(str);
|
|
708
|
-
return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
function base64URLStringToBuffer(base64URLString) {
|
|
712
|
-
const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
|
|
713
|
-
const padLength = (4 - (base64.length % 4)) % 4;
|
|
714
|
-
const padded = base64.padEnd(base64.length + padLength, '=');
|
|
715
|
-
const binary = atob(padded);
|
|
716
|
-
const buffer = new ArrayBuffer(binary.length);
|
|
717
|
-
const bytes = new Uint8Array(buffer);
|
|
718
|
-
for (let i = 0; i < binary.length; i++) {
|
|
719
|
-
bytes[i] = binary.charCodeAt(i);
|
|
720
|
-
}
|
|
721
|
-
return buffer;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function browserSupportsWebAuthn() {
|
|
725
|
-
return (window?.PublicKeyCredential !== undefined &&
|
|
726
|
-
typeof window.PublicKeyCredential === 'function');
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
function toPublicKeyCredentialDescriptor(descriptor) {
|
|
730
|
-
const { id } = descriptor;
|
|
731
|
-
return {
|
|
732
|
-
...descriptor,
|
|
733
|
-
id: base64URLStringToBuffer(id),
|
|
734
|
-
transports: descriptor.transports,
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
function isValidDomain(hostname) {
|
|
739
|
-
return (hostname === 'localhost' ||
|
|
740
|
-
/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname));
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
class WebAuthnError extends Error {
|
|
744
|
-
constructor({ message, code, cause, name, }) {
|
|
745
|
-
super(message, { cause });
|
|
746
|
-
this.name = name ?? cause.name;
|
|
747
|
-
this.code = code;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
205
|
+
class WebAuthnError extends Error {
|
|
206
|
+
constructor({ message, code, cause, name, }) {
|
|
207
|
+
super(message, { cause });
|
|
208
|
+
this.name = name ?? cause.name;
|
|
209
|
+
this.code = code;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
750
212
|
|
|
751
213
|
function identifyRegistrationError({ error, options, }) {
|
|
752
214
|
const { publicKey } = options;
|
|
@@ -843,7 +305,7 @@ function identifyRegistrationError({ error, options, }) {
|
|
|
843
305
|
return error;
|
|
844
306
|
}
|
|
845
307
|
|
|
846
|
-
class
|
|
308
|
+
class BaseWebAuthnAbortService {
|
|
847
309
|
createNewAbortSignal() {
|
|
848
310
|
if (this.controller) {
|
|
849
311
|
const abortError = new Error('Cancelling existing WebAuthn API call for new one');
|
|
@@ -854,8 +316,16 @@ class WebAuthnAbortService {
|
|
|
854
316
|
this.controller = newController;
|
|
855
317
|
return newController.signal;
|
|
856
318
|
}
|
|
319
|
+
cancelCeremony() {
|
|
320
|
+
if (this.controller) {
|
|
321
|
+
const abortError = new Error('Manually cancelling existing WebAuthn API call');
|
|
322
|
+
abortError.name = 'AbortError';
|
|
323
|
+
this.controller.abort(abortError);
|
|
324
|
+
this.controller = undefined;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
857
327
|
}
|
|
858
|
-
const
|
|
328
|
+
const WebAuthnAbortService = new BaseWebAuthnAbortService();
|
|
859
329
|
|
|
860
330
|
const attachments = ['cross-platform', 'platform'];
|
|
861
331
|
function toAuthenticatorAttachment(attachment) {
|
|
@@ -882,7 +352,7 @@ async function startRegistration(creationOptionsJSON) {
|
|
|
882
352
|
excludeCredentials: creationOptionsJSON.excludeCredentials?.map(toPublicKeyCredentialDescriptor),
|
|
883
353
|
};
|
|
884
354
|
const options = { publicKey };
|
|
885
|
-
options.signal =
|
|
355
|
+
options.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
886
356
|
let credential;
|
|
887
357
|
try {
|
|
888
358
|
credential = (await navigator.credentials.create(options));
|
|
@@ -997,754 +467,769 @@ function identifyAuthenticationError({ error, options, }) {
|
|
|
997
467
|
code: 'ERROR_INVALID_RP_ID',
|
|
998
468
|
cause: error,
|
|
999
469
|
});
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
else if (error.name === 'UnknownError') {
|
|
1003
|
-
return new WebAuthnError({
|
|
1004
|
-
message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature',
|
|
1005
|
-
code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
|
|
1006
|
-
cause: error,
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else if (error.name === 'UnknownError') {
|
|
473
|
+
return new WebAuthnError({
|
|
474
|
+
message: 'The authenticator was unable to process the specified options, or could not create a new assertion signature',
|
|
475
|
+
code: 'ERROR_AUTHENTICATOR_GENERAL_ERROR',
|
|
476
|
+
cause: error,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
return error;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function startAuthentication(requestOptionsJSON, useBrowserAutofill = false) {
|
|
483
|
+
if (!browserSupportsWebAuthn()) {
|
|
484
|
+
throw new Error('WebAuthn is not supported in this browser');
|
|
485
|
+
}
|
|
486
|
+
let allowCredentials;
|
|
487
|
+
if (requestOptionsJSON.allowCredentials?.length !== 0) {
|
|
488
|
+
allowCredentials = requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
|
|
489
|
+
}
|
|
490
|
+
const publicKey = {
|
|
491
|
+
...requestOptionsJSON,
|
|
492
|
+
challenge: base64URLStringToBuffer(requestOptionsJSON.challenge),
|
|
493
|
+
allowCredentials,
|
|
494
|
+
};
|
|
495
|
+
const options = {};
|
|
496
|
+
if (useBrowserAutofill) {
|
|
497
|
+
if (!(await browserSupportsWebAuthnAutofill())) {
|
|
498
|
+
throw Error('Browser does not support WebAuthn autofill');
|
|
499
|
+
}
|
|
500
|
+
const eligibleInputs = document.querySelectorAll('input[autocomplete$=\'webauthn\']');
|
|
501
|
+
if (eligibleInputs.length < 1) {
|
|
502
|
+
throw Error('No <input> with "webauthn" as the only or last value in its `autocomplete` attribute was detected');
|
|
503
|
+
}
|
|
504
|
+
options.mediation = 'conditional';
|
|
505
|
+
publicKey.allowCredentials = [];
|
|
506
|
+
}
|
|
507
|
+
options.publicKey = publicKey;
|
|
508
|
+
options.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
509
|
+
let credential;
|
|
510
|
+
try {
|
|
511
|
+
credential = (await navigator.credentials.get(options));
|
|
512
|
+
}
|
|
513
|
+
catch (err) {
|
|
514
|
+
throw identifyAuthenticationError({ error: err, options });
|
|
515
|
+
}
|
|
516
|
+
if (!credential) {
|
|
517
|
+
throw new Error('Authentication was not completed');
|
|
518
|
+
}
|
|
519
|
+
const { id, rawId, response, type } = credential;
|
|
520
|
+
let userHandle = undefined;
|
|
521
|
+
if (response.userHandle) {
|
|
522
|
+
userHandle = bufferToUTF8String(response.userHandle);
|
|
523
|
+
}
|
|
524
|
+
return {
|
|
525
|
+
id,
|
|
526
|
+
rawId: bufferToBase64URLString(rawId),
|
|
527
|
+
response: {
|
|
528
|
+
authenticatorData: bufferToBase64URLString(response.authenticatorData),
|
|
529
|
+
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
530
|
+
signature: bufferToBase64URLString(response.signature),
|
|
531
|
+
userHandle,
|
|
532
|
+
},
|
|
533
|
+
type,
|
|
534
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
535
|
+
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
var PasskeyApiClient = /** @class */ (function () {
|
|
540
|
+
function PasskeyApiClient(_a) {
|
|
541
|
+
var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
|
|
542
|
+
this.tenantId = tenantId;
|
|
543
|
+
this.baseUrl = baseUrl;
|
|
544
|
+
}
|
|
545
|
+
PasskeyApiClient.prototype.registrationOptions = function (_a) {
|
|
546
|
+
var token = _a.token, userName = _a.userName;
|
|
547
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
548
|
+
var request;
|
|
549
|
+
return __generator(this, function (_b) {
|
|
550
|
+
switch (_b.label) {
|
|
551
|
+
case 0:
|
|
552
|
+
request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey/registration-options"), {
|
|
553
|
+
method: "POST",
|
|
554
|
+
headers: this.buildHeaders(token),
|
|
555
|
+
body: JSON.stringify({ username: userName })
|
|
556
|
+
});
|
|
557
|
+
return [4 /*yield*/, request];
|
|
558
|
+
case 1: return [2 /*return*/, (_b.sent()).json()];
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
};
|
|
563
|
+
PasskeyApiClient.prototype.authenticationOptions = function (_a) {
|
|
564
|
+
var token = _a.token;
|
|
565
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
566
|
+
var request;
|
|
567
|
+
return __generator(this, function (_b) {
|
|
568
|
+
switch (_b.label) {
|
|
569
|
+
case 0:
|
|
570
|
+
request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey/authentication-options"), {
|
|
571
|
+
method: "POST",
|
|
572
|
+
headers: this.buildHeaders(token),
|
|
573
|
+
body: JSON.stringify({})
|
|
574
|
+
});
|
|
575
|
+
return [4 /*yield*/, request];
|
|
576
|
+
case 1: return [2 /*return*/, (_b.sent()).json()];
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
};
|
|
581
|
+
PasskeyApiClient.prototype.addAuthenticator = function (_a) {
|
|
582
|
+
var token = _a.token, rest = __rest(_a, ["token"]);
|
|
583
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
584
|
+
var request;
|
|
585
|
+
return __generator(this, function (_b) {
|
|
586
|
+
switch (_b.label) {
|
|
587
|
+
case 0:
|
|
588
|
+
request = fetch("".concat(this.baseUrl, "/client/user-authenticators/passkey"), {
|
|
589
|
+
method: "POST",
|
|
590
|
+
headers: this.buildHeaders(token),
|
|
591
|
+
body: JSON.stringify(rest)
|
|
592
|
+
});
|
|
593
|
+
return [4 /*yield*/, request];
|
|
594
|
+
case 1: return [2 /*return*/, (_b.sent()).json()];
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
};
|
|
599
|
+
PasskeyApiClient.prototype.verify = function (_a) {
|
|
600
|
+
var token = _a.token, rest = __rest(_a, ["token"]);
|
|
601
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
602
|
+
var request;
|
|
603
|
+
return __generator(this, function (_b) {
|
|
604
|
+
switch (_b.label) {
|
|
605
|
+
case 0:
|
|
606
|
+
request = fetch("".concat(this.baseUrl, "/client/verify/passkey"), {
|
|
607
|
+
method: "POST",
|
|
608
|
+
headers: this.buildHeaders(token),
|
|
609
|
+
body: JSON.stringify(rest)
|
|
610
|
+
});
|
|
611
|
+
return [4 /*yield*/, request];
|
|
612
|
+
case 1: return [2 /*return*/, (_b.sent()).json()];
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
};
|
|
617
|
+
PasskeyApiClient.prototype.buildHeaders = function (token) {
|
|
618
|
+
var authorizationHeader = token ? "Bearer ".concat(token) : "Basic ".concat(window.btoa(encodeURIComponent(this.tenantId)));
|
|
619
|
+
return {
|
|
620
|
+
"Content-Type": "application/json",
|
|
621
|
+
Authorization: authorizationHeader
|
|
622
|
+
};
|
|
623
|
+
};
|
|
624
|
+
return PasskeyApiClient;
|
|
625
|
+
}());
|
|
626
|
+
|
|
627
|
+
var Passkey = /** @class */ (function () {
|
|
628
|
+
function Passkey(_a) {
|
|
629
|
+
var baseUrl = _a.baseUrl, tenantId = _a.tenantId;
|
|
630
|
+
this.api = new PasskeyApiClient({ baseUrl: baseUrl, tenantId: tenantId });
|
|
631
|
+
}
|
|
632
|
+
Passkey.prototype.signUp = function (_a) {
|
|
633
|
+
var userName = _a.userName, token = _a.token;
|
|
634
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
635
|
+
var optionsResponse, registrationResponse, addAuthenticatorResponse;
|
|
636
|
+
return __generator(this, function (_b) {
|
|
637
|
+
switch (_b.label) {
|
|
638
|
+
case 0: return [4 /*yield*/, this.api.registrationOptions({ userName: userName, token: token })];
|
|
639
|
+
case 1:
|
|
640
|
+
optionsResponse = _b.sent();
|
|
641
|
+
return [4 /*yield*/, startRegistration(optionsResponse.options)];
|
|
642
|
+
case 2:
|
|
643
|
+
registrationResponse = _b.sent();
|
|
644
|
+
return [4 /*yield*/, this.api.addAuthenticator({
|
|
645
|
+
challengeId: optionsResponse.challengeId,
|
|
646
|
+
registrationCredential: registrationResponse,
|
|
647
|
+
token: token
|
|
648
|
+
})];
|
|
649
|
+
case 3:
|
|
650
|
+
addAuthenticatorResponse = _b.sent();
|
|
651
|
+
return [2 /*return*/, addAuthenticatorResponse === null || addAuthenticatorResponse === void 0 ? void 0 : addAuthenticatorResponse.accessToken];
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
};
|
|
656
|
+
Passkey.prototype.signIn = function (params) {
|
|
657
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
658
|
+
var optionsResponse, authenticationResponse, verifyResponse;
|
|
659
|
+
return __generator(this, function (_a) {
|
|
660
|
+
switch (_a.label) {
|
|
661
|
+
case 0:
|
|
662
|
+
if ((params === null || params === void 0 ? void 0 : params.token) && params.autofill) {
|
|
663
|
+
throw new Error("Autofill is not supported when providing a token");
|
|
664
|
+
}
|
|
665
|
+
return [4 /*yield*/, this.api.authenticationOptions({ token: params === null || params === void 0 ? void 0 : params.token })];
|
|
666
|
+
case 1:
|
|
667
|
+
optionsResponse = _a.sent();
|
|
668
|
+
return [4 /*yield*/, startAuthentication(optionsResponse.options, params === null || params === void 0 ? void 0 : params.autofill)];
|
|
669
|
+
case 2:
|
|
670
|
+
authenticationResponse = _a.sent();
|
|
671
|
+
return [4 /*yield*/, this.api.verify({
|
|
672
|
+
challengeId: optionsResponse.challengeId,
|
|
673
|
+
authenticationCredential: authenticationResponse,
|
|
674
|
+
token: params === null || params === void 0 ? void 0 : params.token
|
|
675
|
+
})];
|
|
676
|
+
case 3:
|
|
677
|
+
verifyResponse = _a.sent();
|
|
678
|
+
return [2 /*return*/, verifyResponse === null || verifyResponse === void 0 ? void 0 : verifyResponse.accessToken];
|
|
679
|
+
}
|
|
680
|
+
});
|
|
1007
681
|
});
|
|
1008
|
-
}
|
|
1009
|
-
return
|
|
1010
|
-
}
|
|
682
|
+
};
|
|
683
|
+
return Passkey;
|
|
684
|
+
}());
|
|
1011
685
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
if (requestOptionsJSON.allowCredentials?.length !== 0) {
|
|
1018
|
-
allowCredentials = requestOptionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
|
|
686
|
+
var DEFAULT_WIDTH$1 = 400;
|
|
687
|
+
var DEFAULT_HEIGHT = 500;
|
|
688
|
+
var WindowHandler = /** @class */ (function () {
|
|
689
|
+
function WindowHandler() {
|
|
690
|
+
this.windowRef = null;
|
|
1019
691
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const options = {};
|
|
1026
|
-
if (useBrowserAutofill) {
|
|
1027
|
-
if (!(await browserSupportsWebAuthnAutofill())) {
|
|
1028
|
-
throw Error('Browser does not support WebAuthn autofill');
|
|
692
|
+
WindowHandler.prototype.show = function (_a) {
|
|
693
|
+
var url = _a.url, _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH$1 : _b, _c = _a.height, height = _c === void 0 ? DEFAULT_HEIGHT : _c;
|
|
694
|
+
var windowRef = openWindow({ url: url, width: width, height: height, win: window });
|
|
695
|
+
if (!windowRef) {
|
|
696
|
+
throw new Error("Window is not initialized");
|
|
1029
697
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
698
|
+
this.windowRef = windowRef;
|
|
699
|
+
return windowRef;
|
|
700
|
+
};
|
|
701
|
+
WindowHandler.prototype.close = function () {
|
|
702
|
+
if (!this.windowRef) {
|
|
703
|
+
throw new Error("Window is not initialized");
|
|
1033
704
|
}
|
|
1034
|
-
|
|
1035
|
-
publicKey.allowCredentials = [];
|
|
1036
|
-
}
|
|
1037
|
-
options.publicKey = publicKey;
|
|
1038
|
-
options.signal = webauthnAbortService.createNewAbortSignal();
|
|
1039
|
-
let credential;
|
|
1040
|
-
try {
|
|
1041
|
-
credential = (await navigator.credentials.get(options));
|
|
1042
|
-
}
|
|
1043
|
-
catch (err) {
|
|
1044
|
-
throw identifyAuthenticationError({ error: err, options });
|
|
1045
|
-
}
|
|
1046
|
-
if (!credential) {
|
|
1047
|
-
throw new Error('Authentication was not completed');
|
|
1048
|
-
}
|
|
1049
|
-
const { id, rawId, response, type } = credential;
|
|
1050
|
-
let userHandle = undefined;
|
|
1051
|
-
if (response.userHandle) {
|
|
1052
|
-
userHandle = bufferToUTF8String(response.userHandle);
|
|
1053
|
-
}
|
|
1054
|
-
return {
|
|
1055
|
-
id,
|
|
1056
|
-
rawId: bufferToBase64URLString(rawId),
|
|
1057
|
-
response: {
|
|
1058
|
-
authenticatorData: bufferToBase64URLString(response.authenticatorData),
|
|
1059
|
-
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
1060
|
-
signature: bufferToBase64URLString(response.signature),
|
|
1061
|
-
userHandle,
|
|
1062
|
-
},
|
|
1063
|
-
type,
|
|
1064
|
-
clientExtensionResults: credential.getClientExtensionResults(),
|
|
1065
|
-
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment),
|
|
705
|
+
this.windowRef.close();
|
|
1066
706
|
};
|
|
707
|
+
return WindowHandler;
|
|
708
|
+
}());
|
|
709
|
+
function openWindow(_a) {
|
|
710
|
+
var url = _a.url, width = _a.width, height = _a.height, win = _a.win;
|
|
711
|
+
if (!win.top) {
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
var y = win.top.outerHeight / 2 + win.top.screenY - height / 2;
|
|
715
|
+
var x = win.top.outerWidth / 2 + win.top.screenX - width / 2;
|
|
716
|
+
return window.open(url, "", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=".concat(width, ", height=").concat(height, ", top=").concat(y, ", left=").concat(x));
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
var focusableSelectors = [
|
|
720
|
+
'a[href]:not([tabindex^="-"])',
|
|
721
|
+
'area[href]:not([tabindex^="-"])',
|
|
722
|
+
'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])',
|
|
723
|
+
'input[type="radio"]:not([disabled]):not([tabindex^="-"])',
|
|
724
|
+
'select:not([disabled]):not([tabindex^="-"])',
|
|
725
|
+
'textarea:not([disabled]):not([tabindex^="-"])',
|
|
726
|
+
'button:not([disabled]):not([tabindex^="-"])',
|
|
727
|
+
'iframe:not([tabindex^="-"])',
|
|
728
|
+
'audio[controls]:not([tabindex^="-"])',
|
|
729
|
+
'video[controls]:not([tabindex^="-"])',
|
|
730
|
+
'[contenteditable]:not([tabindex^="-"])',
|
|
731
|
+
'[tabindex]:not([tabindex^="-"])',
|
|
732
|
+
];
|
|
733
|
+
|
|
734
|
+
var TAB_KEY = 'Tab';
|
|
735
|
+
var ESCAPE_KEY = 'Escape';
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Define the constructor to instantiate a dialog
|
|
739
|
+
*
|
|
740
|
+
* @constructor
|
|
741
|
+
* @param {Element} element
|
|
742
|
+
*/
|
|
743
|
+
function A11yDialog(element) {
|
|
744
|
+
// Prebind the functions that will be bound in addEventListener and
|
|
745
|
+
// removeEventListener to avoid losing references
|
|
746
|
+
this._show = this.show.bind(this);
|
|
747
|
+
this._hide = this.hide.bind(this);
|
|
748
|
+
this._maintainFocus = this._maintainFocus.bind(this);
|
|
749
|
+
this._bindKeypress = this._bindKeypress.bind(this);
|
|
750
|
+
|
|
751
|
+
this.$el = element;
|
|
752
|
+
this.shown = false;
|
|
753
|
+
this._id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;
|
|
754
|
+
this._previouslyFocused = null;
|
|
755
|
+
this._listeners = {};
|
|
756
|
+
|
|
757
|
+
// Initialise everything needed for the dialog to work properly
|
|
758
|
+
this.create();
|
|
1067
759
|
}
|
|
1068
760
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
761
|
+
/**
|
|
762
|
+
* Set up everything necessary for the dialog to be functioning
|
|
763
|
+
*
|
|
764
|
+
* @param {(NodeList | Element | string)} targets
|
|
765
|
+
* @return {this}
|
|
766
|
+
*/
|
|
767
|
+
A11yDialog.prototype.create = function () {
|
|
768
|
+
this.$el.setAttribute('aria-hidden', true);
|
|
769
|
+
this.$el.setAttribute('aria-modal', true);
|
|
770
|
+
this.$el.setAttribute('tabindex', -1);
|
|
771
|
+
|
|
772
|
+
if (!this.$el.hasAttribute('role')) {
|
|
773
|
+
this.$el.setAttribute('role', 'dialog');
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Keep a collection of dialog openers, each of which will be bound a click
|
|
777
|
+
// event listener to open the dialog
|
|
778
|
+
this._openers = $$('[data-a11y-dialog-show="' + this._id + '"]');
|
|
779
|
+
this._openers.forEach(
|
|
780
|
+
function (opener) {
|
|
781
|
+
opener.addEventListener('click', this._show);
|
|
782
|
+
}.bind(this)
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
// Keep a collection of dialog closers, each of which will be bound a click
|
|
786
|
+
// event listener to close the dialog
|
|
787
|
+
const $el = this.$el;
|
|
788
|
+
|
|
789
|
+
this._closers = $$('[data-a11y-dialog-hide]', this.$el)
|
|
790
|
+
// This filter is necessary in case there are nested dialogs, so that
|
|
791
|
+
// only closers from the current dialog are retrieved and effective
|
|
792
|
+
.filter(function (closer) {
|
|
793
|
+
// Testing for `[aria-modal="true"]` is not enough since this attribute
|
|
794
|
+
// and the collect of closers is done at instantation time, when nested
|
|
795
|
+
// dialogs might not have yet been instantiated. Note that if the dialogs
|
|
796
|
+
// are manually instantiated, this could still fail because none of these
|
|
797
|
+
// selectors would match; this would cause closers to close all parent
|
|
798
|
+
// dialogs instead of just the current one
|
|
799
|
+
return closer.closest('[aria-modal="true"], [data-a11y-dialog]') === $el
|
|
800
|
+
})
|
|
801
|
+
.concat($$('[data-a11y-dialog-hide="' + this._id + '"]'));
|
|
802
|
+
|
|
803
|
+
this._closers.forEach(
|
|
804
|
+
function (closer) {
|
|
805
|
+
closer.addEventListener('click', this._hide);
|
|
806
|
+
}.bind(this)
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
// Execute all callbacks registered for the `create` event
|
|
810
|
+
this._fire('create');
|
|
811
|
+
|
|
812
|
+
return this
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Show the dialog element, disable all the targets (siblings), trap the
|
|
817
|
+
* current focus within it, listen for some specific key presses and fire all
|
|
818
|
+
* registered callbacks for `show` event
|
|
819
|
+
*
|
|
820
|
+
* @param {CustomEvent} event
|
|
821
|
+
* @return {this}
|
|
822
|
+
*/
|
|
823
|
+
A11yDialog.prototype.show = function (event) {
|
|
824
|
+
// If the dialog is already open, abort
|
|
825
|
+
if (this.shown) {
|
|
826
|
+
return this
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Keep a reference to the currently focused element to be able to restore
|
|
830
|
+
// it later
|
|
831
|
+
this._previouslyFocused = document.activeElement;
|
|
832
|
+
this.$el.removeAttribute('aria-hidden');
|
|
833
|
+
this.shown = true;
|
|
834
|
+
|
|
835
|
+
// Set the focus to the dialog element
|
|
836
|
+
moveFocusToDialog(this.$el);
|
|
837
|
+
|
|
838
|
+
// Bind a focus event listener to the body element to make sure the focus
|
|
839
|
+
// stays trapped inside the dialog while open, and start listening for some
|
|
840
|
+
// specific key presses (TAB and ESC)
|
|
841
|
+
document.body.addEventListener('focus', this._maintainFocus, true);
|
|
842
|
+
document.addEventListener('keydown', this._bindKeypress);
|
|
843
|
+
|
|
844
|
+
// Execute all callbacks registered for the `show` event
|
|
845
|
+
this._fire('show', event);
|
|
846
|
+
|
|
847
|
+
return this
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Hide the dialog element, enable all the targets (siblings), restore the
|
|
852
|
+
* focus to the previously active element, stop listening for some specific
|
|
853
|
+
* key presses and fire all registered callbacks for `hide` event
|
|
854
|
+
*
|
|
855
|
+
* @param {CustomEvent} event
|
|
856
|
+
* @return {this}
|
|
857
|
+
*/
|
|
858
|
+
A11yDialog.prototype.hide = function (event) {
|
|
859
|
+
// If the dialog is already closed, abort
|
|
860
|
+
if (!this.shown) {
|
|
861
|
+
return this
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
this.shown = false;
|
|
865
|
+
this.$el.setAttribute('aria-hidden', 'true');
|
|
866
|
+
|
|
867
|
+
// If there was a focused element before the dialog was opened (and it has a
|
|
868
|
+
// `focus` method), restore the focus back to it
|
|
869
|
+
// See: https://github.com/KittyGiraudel/a11y-dialog/issues/108
|
|
870
|
+
if (this._previouslyFocused && this._previouslyFocused.focus) {
|
|
871
|
+
this._previouslyFocused.focus();
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Remove the focus event listener to the body element and stop listening
|
|
875
|
+
// for specific key presses
|
|
876
|
+
document.body.removeEventListener('focus', this._maintainFocus, true);
|
|
877
|
+
document.removeEventListener('keydown', this._bindKeypress);
|
|
878
|
+
|
|
879
|
+
// Execute all callbacks registered for the `hide` event
|
|
880
|
+
this._fire('hide', event);
|
|
881
|
+
|
|
882
|
+
return this
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Destroy the current instance (after making sure the dialog has been hidden)
|
|
887
|
+
* and remove all associated listeners from dialog openers and closers
|
|
888
|
+
*
|
|
889
|
+
* @return {this}
|
|
890
|
+
*/
|
|
891
|
+
A11yDialog.prototype.destroy = function () {
|
|
892
|
+
// Hide the dialog to avoid destroying an open instance
|
|
893
|
+
this.hide();
|
|
1101
894
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
writable: true,
|
|
1109
|
-
value: void 0
|
|
1110
|
-
});
|
|
1111
|
-
this.name = 'TimeoutError';
|
|
1112
|
-
this.request = request;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
895
|
+
// Remove the click event listener from all dialog openers
|
|
896
|
+
this._openers.forEach(
|
|
897
|
+
function (opener) {
|
|
898
|
+
opener.removeEventListener('click', this._show);
|
|
899
|
+
}.bind(this)
|
|
900
|
+
);
|
|
1115
901
|
|
|
1116
|
-
//
|
|
1117
|
-
|
|
902
|
+
// Remove the click event listener from all dialog closers
|
|
903
|
+
this._closers.forEach(
|
|
904
|
+
function (closer) {
|
|
905
|
+
closer.removeEventListener('click', this._hide);
|
|
906
|
+
}.bind(this)
|
|
907
|
+
);
|
|
1118
908
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
909
|
+
// Execute all callbacks registered for the `destroy` event
|
|
910
|
+
this._fire('destroy');
|
|
911
|
+
|
|
912
|
+
// Keep an object of listener types mapped to callback functions
|
|
913
|
+
this._listeners = {};
|
|
914
|
+
|
|
915
|
+
return this
|
|
1126
916
|
};
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Register a new callback for the given event type
|
|
920
|
+
*
|
|
921
|
+
* @param {string} type
|
|
922
|
+
* @param {Function} handler
|
|
923
|
+
*/
|
|
924
|
+
A11yDialog.prototype.on = function (type, handler) {
|
|
925
|
+
if (typeof this._listeners[type] === 'undefined') {
|
|
926
|
+
this._listeners[type] = [];
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
this._listeners[type].push(handler);
|
|
930
|
+
|
|
931
|
+
return this
|
|
1140
932
|
};
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
}
|
|
1157
|
-
returnValue = { ...returnValue, [key]: value };
|
|
1158
|
-
}
|
|
1159
|
-
if (isObject(source.headers)) {
|
|
1160
|
-
headers = mergeHeaders(headers, source.headers);
|
|
1161
|
-
returnValue.headers = headers;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
return returnValue;
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Unregister an existing callback for the given event type
|
|
936
|
+
*
|
|
937
|
+
* @param {string} type
|
|
938
|
+
* @param {Function} handler
|
|
939
|
+
*/
|
|
940
|
+
A11yDialog.prototype.off = function (type, handler) {
|
|
941
|
+
var index = (this._listeners[type] || []).indexOf(handler);
|
|
942
|
+
|
|
943
|
+
if (index > -1) {
|
|
944
|
+
this._listeners[type].splice(index, 1);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
return this
|
|
1166
948
|
};
|
|
1167
949
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete'];
|
|
1190
|
-
const responseTypes = {
|
|
1191
|
-
json: 'application/json',
|
|
1192
|
-
text: 'text/*',
|
|
1193
|
-
formData: 'multipart/form-data',
|
|
1194
|
-
arrayBuffer: '*/*',
|
|
1195
|
-
blob: '*/*',
|
|
950
|
+
/**
|
|
951
|
+
* Iterate over all registered handlers for given type and call them all with
|
|
952
|
+
* the dialog element as first argument, event as second argument (if any). Also
|
|
953
|
+
* dispatch a custom event on the DOM element itself to make it possible to
|
|
954
|
+
* react to the lifecycle of auto-instantiated dialogs.
|
|
955
|
+
*
|
|
956
|
+
* @access private
|
|
957
|
+
* @param {string} type
|
|
958
|
+
* @param {CustomEvent} event
|
|
959
|
+
*/
|
|
960
|
+
A11yDialog.prototype._fire = function (type, event) {
|
|
961
|
+
var listeners = this._listeners[type] || [];
|
|
962
|
+
var domEvent = new CustomEvent(type, { detail: event });
|
|
963
|
+
|
|
964
|
+
this.$el.dispatchEvent(domEvent);
|
|
965
|
+
|
|
966
|
+
listeners.forEach(
|
|
967
|
+
function (listener) {
|
|
968
|
+
listener(this.$el, event);
|
|
969
|
+
}.bind(this)
|
|
970
|
+
);
|
|
1196
971
|
};
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Private event handler used when listening to some specific key presses
|
|
975
|
+
* (namely ESCAPE and TAB)
|
|
976
|
+
*
|
|
977
|
+
* @access private
|
|
978
|
+
* @param {Event} event
|
|
979
|
+
*/
|
|
980
|
+
A11yDialog.prototype._bindKeypress = function (event) {
|
|
981
|
+
// This is an escape hatch in case there are nested dialogs, so the keypresses
|
|
982
|
+
// are only reacted to for the most recent one
|
|
983
|
+
const focused = document.activeElement;
|
|
984
|
+
if (focused && focused.closest('[aria-modal="true"]') !== this.$el) return
|
|
985
|
+
|
|
986
|
+
// If the dialog is shown and the ESCAPE key is being pressed, prevent any
|
|
987
|
+
// further effects from the ESCAPE key and hide the dialog, unless its role
|
|
988
|
+
// is 'alertdialog', which should be modal
|
|
989
|
+
if (
|
|
990
|
+
this.shown &&
|
|
991
|
+
event.key === ESCAPE_KEY &&
|
|
992
|
+
this.$el.getAttribute('role') !== 'alertdialog'
|
|
993
|
+
) {
|
|
994
|
+
event.preventDefault();
|
|
995
|
+
this.hide(event);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// If the dialog is shown and the TAB key is being pressed, make sure the
|
|
999
|
+
// focus stays trapped within the dialog element
|
|
1000
|
+
if (this.shown && event.key === TAB_KEY) {
|
|
1001
|
+
trapTabKey(this.$el, event);
|
|
1002
|
+
}
|
|
1212
1003
|
};
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Private event handler used when making sure the focus stays within the
|
|
1007
|
+
* currently open dialog
|
|
1008
|
+
*
|
|
1009
|
+
* @access private
|
|
1010
|
+
* @param {Event} event
|
|
1011
|
+
*/
|
|
1012
|
+
A11yDialog.prototype._maintainFocus = function (event) {
|
|
1013
|
+
// If the dialog is shown and the focus is not within a dialog element (either
|
|
1014
|
+
// this one or another one in case of nested dialogs) or within an element
|
|
1015
|
+
// with the `data-a11y-dialog-focus-trap-ignore` attribute, move it back to
|
|
1016
|
+
// its first focusable child.
|
|
1017
|
+
// See: https://github.com/KittyGiraudel/a11y-dialog/issues/177
|
|
1018
|
+
if (
|
|
1019
|
+
this.shown &&
|
|
1020
|
+
!event.target.closest('[aria-modal="true"]') &&
|
|
1021
|
+
!event.target.closest('[data-a11y-dialog-ignore-focus-trap]')
|
|
1022
|
+
) {
|
|
1023
|
+
moveFocusToDialog(this.$el);
|
|
1024
|
+
}
|
|
1231
1025
|
};
|
|
1232
1026
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
}, options.timeout);
|
|
1242
|
-
void options
|
|
1243
|
-
.fetch(request)
|
|
1244
|
-
.then(resolve)
|
|
1245
|
-
.catch(reject)
|
|
1246
|
-
.then(() => {
|
|
1247
|
-
clearTimeout(timeoutId);
|
|
1248
|
-
});
|
|
1249
|
-
});
|
|
1027
|
+
/**
|
|
1028
|
+
* Convert a NodeList into an array
|
|
1029
|
+
*
|
|
1030
|
+
* @param {NodeList} collection
|
|
1031
|
+
* @return {Array<Element>}
|
|
1032
|
+
*/
|
|
1033
|
+
function toArray(collection) {
|
|
1034
|
+
return Array.prototype.slice.call(collection)
|
|
1250
1035
|
}
|
|
1251
1036
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
return new DOMException(signal?.reason ?? 'The operation was aborted.', 'AbortError');
|
|
1263
|
-
}
|
|
1264
|
-
// DOMException not supported. Fall back to use of error and override name.
|
|
1265
|
-
const error = new Error(signal?.reason ?? 'The operation was aborted.');
|
|
1266
|
-
error.name = 'AbortError';
|
|
1267
|
-
return error;
|
|
1037
|
+
/**
|
|
1038
|
+
* Query the DOM for nodes matching the given selector, scoped to context (or
|
|
1039
|
+
* the whole document)
|
|
1040
|
+
*
|
|
1041
|
+
* @param {String} selector
|
|
1042
|
+
* @param {Element} [context = document]
|
|
1043
|
+
* @return {Array<Element>}
|
|
1044
|
+
*/
|
|
1045
|
+
function $$(selector, context) {
|
|
1046
|
+
return toArray((context || document).querySelectorAll(selector))
|
|
1268
1047
|
}
|
|
1269
1048
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
function handleAbort() {
|
|
1281
|
-
reject(composeAbortError(signal));
|
|
1282
|
-
clearTimeout(timeoutId);
|
|
1283
|
-
}
|
|
1284
|
-
const timeoutId = setTimeout(() => {
|
|
1285
|
-
signal?.removeEventListener('abort', handleAbort);
|
|
1286
|
-
resolve();
|
|
1287
|
-
}, ms);
|
|
1288
|
-
});
|
|
1049
|
+
/**
|
|
1050
|
+
* Set the focus to the first element with `autofocus` with the element or the
|
|
1051
|
+
* element itself
|
|
1052
|
+
*
|
|
1053
|
+
* @param {Element} node
|
|
1054
|
+
*/
|
|
1055
|
+
function moveFocusToDialog(node) {
|
|
1056
|
+
var focused = node.querySelector('[autofocus]') || node;
|
|
1057
|
+
|
|
1058
|
+
focused.focus();
|
|
1289
1059
|
}
|
|
1290
1060
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
for (const [type, mimeType] of Object.entries(responseTypes)) {
|
|
1334
|
-
result[type] = async () => {
|
|
1335
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
1336
|
-
ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
|
|
1337
|
-
const awaitedResult = await result;
|
|
1338
|
-
const response = awaitedResult.clone();
|
|
1339
|
-
if (type === 'json') {
|
|
1340
|
-
if (response.status === 204) {
|
|
1341
|
-
return '';
|
|
1342
|
-
}
|
|
1343
|
-
const arrayBuffer = await response.clone().arrayBuffer();
|
|
1344
|
-
const responseSize = arrayBuffer.byteLength;
|
|
1345
|
-
if (responseSize === 0) {
|
|
1346
|
-
return '';
|
|
1347
|
-
}
|
|
1348
|
-
if (options.parseJson) {
|
|
1349
|
-
return options.parseJson(await response.text());
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
return response[type]();
|
|
1353
|
-
};
|
|
1354
|
-
}
|
|
1355
|
-
return result;
|
|
1356
|
-
}
|
|
1357
|
-
// eslint-disable-next-line complexity
|
|
1358
|
-
constructor(input, options = {}) {
|
|
1359
|
-
Object.defineProperty(this, "request", {
|
|
1360
|
-
enumerable: true,
|
|
1361
|
-
configurable: true,
|
|
1362
|
-
writable: true,
|
|
1363
|
-
value: void 0
|
|
1364
|
-
});
|
|
1365
|
-
Object.defineProperty(this, "abortController", {
|
|
1366
|
-
enumerable: true,
|
|
1367
|
-
configurable: true,
|
|
1368
|
-
writable: true,
|
|
1369
|
-
value: void 0
|
|
1370
|
-
});
|
|
1371
|
-
Object.defineProperty(this, "_retryCount", {
|
|
1372
|
-
enumerable: true,
|
|
1373
|
-
configurable: true,
|
|
1374
|
-
writable: true,
|
|
1375
|
-
value: 0
|
|
1376
|
-
});
|
|
1377
|
-
Object.defineProperty(this, "_input", {
|
|
1378
|
-
enumerable: true,
|
|
1379
|
-
configurable: true,
|
|
1380
|
-
writable: true,
|
|
1381
|
-
value: void 0
|
|
1382
|
-
});
|
|
1383
|
-
Object.defineProperty(this, "_options", {
|
|
1384
|
-
enumerable: true,
|
|
1385
|
-
configurable: true,
|
|
1386
|
-
writable: true,
|
|
1387
|
-
value: void 0
|
|
1388
|
-
});
|
|
1389
|
-
this._input = input;
|
|
1390
|
-
this._options = {
|
|
1391
|
-
// TODO: credentials can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
|
|
1392
|
-
credentials: this._input.credentials || 'same-origin',
|
|
1393
|
-
...options,
|
|
1394
|
-
headers: mergeHeaders(this._input.headers, options.headers),
|
|
1395
|
-
hooks: deepMerge({
|
|
1396
|
-
beforeRequest: [],
|
|
1397
|
-
beforeRetry: [],
|
|
1398
|
-
beforeError: [],
|
|
1399
|
-
afterResponse: [],
|
|
1400
|
-
}, options.hooks),
|
|
1401
|
-
method: normalizeRequestMethod(options.method ?? this._input.method),
|
|
1402
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
1403
|
-
prefixUrl: String(options.prefixUrl || ''),
|
|
1404
|
-
retry: normalizeRetryOptions(options.retry),
|
|
1405
|
-
throwHttpErrors: options.throwHttpErrors !== false,
|
|
1406
|
-
timeout: typeof options.timeout === 'undefined' ? 10000 : options.timeout,
|
|
1407
|
-
fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
|
|
1408
|
-
};
|
|
1409
|
-
if (typeof this._input !== 'string' && !(this._input instanceof URL || this._input instanceof globalThis.Request)) {
|
|
1410
|
-
throw new TypeError('`input` must be a string, URL, or Request');
|
|
1411
|
-
}
|
|
1412
|
-
if (this._options.prefixUrl && typeof this._input === 'string') {
|
|
1413
|
-
if (this._input.startsWith('/')) {
|
|
1414
|
-
throw new Error('`input` must not begin with a slash when using `prefixUrl`');
|
|
1415
|
-
}
|
|
1416
|
-
if (!this._options.prefixUrl.endsWith('/')) {
|
|
1417
|
-
this._options.prefixUrl += '/';
|
|
1418
|
-
}
|
|
1419
|
-
this._input = this._options.prefixUrl + this._input;
|
|
1420
|
-
}
|
|
1421
|
-
if (supportsAbortController) {
|
|
1422
|
-
this.abortController = new globalThis.AbortController();
|
|
1423
|
-
if (this._options.signal) {
|
|
1424
|
-
const originalSignal = this._options.signal;
|
|
1425
|
-
this._options.signal.addEventListener('abort', () => {
|
|
1426
|
-
this.abortController.abort(originalSignal.reason);
|
|
1427
|
-
});
|
|
1428
|
-
}
|
|
1429
|
-
this._options.signal = this.abortController.signal;
|
|
1430
|
-
}
|
|
1431
|
-
if (supportsRequestStreams) {
|
|
1432
|
-
// @ts-expect-error - Types are outdated.
|
|
1433
|
-
this._options.duplex = 'half';
|
|
1434
|
-
}
|
|
1435
|
-
this.request = new globalThis.Request(this._input, this._options);
|
|
1436
|
-
if (this._options.searchParams) {
|
|
1437
|
-
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
1438
|
-
const textSearchParams = typeof this._options.searchParams === 'string'
|
|
1439
|
-
? this._options.searchParams.replace(/^\?/, '')
|
|
1440
|
-
: new URLSearchParams(this._options.searchParams).toString();
|
|
1441
|
-
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
1442
|
-
const searchParams = '?' + textSearchParams;
|
|
1443
|
-
const url = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, searchParams);
|
|
1444
|
-
// To provide correct form boundary, Content-Type header should be deleted each time when new Request instantiated from another one
|
|
1445
|
-
if (((supportsFormData && this._options.body instanceof globalThis.FormData)
|
|
1446
|
-
|| this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
|
|
1447
|
-
this.request.headers.delete('content-type');
|
|
1448
|
-
}
|
|
1449
|
-
// The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
|
|
1450
|
-
this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
|
|
1451
|
-
}
|
|
1452
|
-
if (this._options.json !== undefined) {
|
|
1453
|
-
this._options.body = JSON.stringify(this._options.json);
|
|
1454
|
-
this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
|
|
1455
|
-
this.request = new globalThis.Request(this.request, { body: this._options.body });
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
_calculateRetryDelay(error) {
|
|
1459
|
-
this._retryCount++;
|
|
1460
|
-
if (this._retryCount < this._options.retry.limit && !(error instanceof TimeoutError)) {
|
|
1461
|
-
if (error instanceof HTTPError) {
|
|
1462
|
-
if (!this._options.retry.statusCodes.includes(error.response.status)) {
|
|
1463
|
-
return 0;
|
|
1464
|
-
}
|
|
1465
|
-
const retryAfter = error.response.headers.get('Retry-After');
|
|
1466
|
-
if (retryAfter && this._options.retry.afterStatusCodes.includes(error.response.status)) {
|
|
1467
|
-
let after = Number(retryAfter);
|
|
1468
|
-
if (Number.isNaN(after)) {
|
|
1469
|
-
after = Date.parse(retryAfter) - Date.now();
|
|
1470
|
-
}
|
|
1471
|
-
else {
|
|
1472
|
-
after *= 1000;
|
|
1473
|
-
}
|
|
1474
|
-
if (typeof this._options.retry.maxRetryAfter !== 'undefined' && after > this._options.retry.maxRetryAfter) {
|
|
1475
|
-
return 0;
|
|
1476
|
-
}
|
|
1477
|
-
return after;
|
|
1478
|
-
}
|
|
1479
|
-
if (error.response.status === 413) {
|
|
1480
|
-
return 0;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
const BACKOFF_FACTOR = 0.3;
|
|
1484
|
-
return Math.min(this._options.retry.backoffLimit, BACKOFF_FACTOR * (2 ** (this._retryCount - 1)) * 1000);
|
|
1485
|
-
}
|
|
1486
|
-
return 0;
|
|
1487
|
-
}
|
|
1488
|
-
_decorateResponse(response) {
|
|
1489
|
-
if (this._options.parseJson) {
|
|
1490
|
-
response.json = async () => this._options.parseJson(await response.text());
|
|
1491
|
-
}
|
|
1492
|
-
return response;
|
|
1493
|
-
}
|
|
1494
|
-
async _retry(fn) {
|
|
1495
|
-
try {
|
|
1496
|
-
return await fn();
|
|
1497
|
-
// eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
|
|
1498
|
-
}
|
|
1499
|
-
catch (error) {
|
|
1500
|
-
const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
|
|
1501
|
-
if (ms !== 0 && this._retryCount > 0) {
|
|
1502
|
-
await delay(ms, { signal: this._options.signal });
|
|
1503
|
-
for (const hook of this._options.hooks.beforeRetry) {
|
|
1504
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1505
|
-
const hookResult = await hook({
|
|
1506
|
-
request: this.request,
|
|
1507
|
-
options: this._options,
|
|
1508
|
-
error: error,
|
|
1509
|
-
retryCount: this._retryCount,
|
|
1510
|
-
});
|
|
1511
|
-
// If `stop` is returned from the hook, the retry process is stopped
|
|
1512
|
-
if (hookResult === stop) {
|
|
1513
|
-
return;
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
return this._retry(fn);
|
|
1517
|
-
}
|
|
1518
|
-
throw error;
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
async _fetch() {
|
|
1522
|
-
for (const hook of this._options.hooks.beforeRequest) {
|
|
1523
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1524
|
-
const result = await hook(this.request, this._options);
|
|
1525
|
-
if (result instanceof Request) {
|
|
1526
|
-
this.request = result;
|
|
1527
|
-
break;
|
|
1528
|
-
}
|
|
1529
|
-
if (result instanceof Response) {
|
|
1530
|
-
return result;
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
if (this._options.timeout === false) {
|
|
1534
|
-
return this._options.fetch(this.request.clone());
|
|
1535
|
-
}
|
|
1536
|
-
return timeout(this.request.clone(), this.abortController, this._options);
|
|
1537
|
-
}
|
|
1538
|
-
/* istanbul ignore next */
|
|
1539
|
-
_stream(response, onDownloadProgress) {
|
|
1540
|
-
const totalBytes = Number(response.headers.get('content-length')) || 0;
|
|
1541
|
-
let transferredBytes = 0;
|
|
1542
|
-
if (response.status === 204) {
|
|
1543
|
-
if (onDownloadProgress) {
|
|
1544
|
-
onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
|
|
1545
|
-
}
|
|
1546
|
-
return new globalThis.Response(null, {
|
|
1547
|
-
status: response.status,
|
|
1548
|
-
statusText: response.statusText,
|
|
1549
|
-
headers: response.headers,
|
|
1550
|
-
});
|
|
1551
|
-
}
|
|
1552
|
-
return new globalThis.Response(new globalThis.ReadableStream({
|
|
1553
|
-
async start(controller) {
|
|
1554
|
-
const reader = response.body.getReader();
|
|
1555
|
-
if (onDownloadProgress) {
|
|
1556
|
-
onDownloadProgress({ percent: 0, transferredBytes: 0, totalBytes }, new Uint8Array());
|
|
1557
|
-
}
|
|
1558
|
-
async function read() {
|
|
1559
|
-
const { done, value } = await reader.read();
|
|
1560
|
-
if (done) {
|
|
1561
|
-
controller.close();
|
|
1562
|
-
return;
|
|
1563
|
-
}
|
|
1564
|
-
if (onDownloadProgress) {
|
|
1565
|
-
transferredBytes += value.byteLength;
|
|
1566
|
-
const percent = totalBytes === 0 ? 0 : transferredBytes / totalBytes;
|
|
1567
|
-
onDownloadProgress({ percent, transferredBytes, totalBytes }, value);
|
|
1568
|
-
}
|
|
1569
|
-
controller.enqueue(value);
|
|
1570
|
-
await read();
|
|
1571
|
-
}
|
|
1572
|
-
await read();
|
|
1573
|
-
},
|
|
1574
|
-
}), {
|
|
1575
|
-
status: response.status,
|
|
1576
|
-
statusText: response.statusText,
|
|
1577
|
-
headers: response.headers,
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Get the focusable children of the given element
|
|
1063
|
+
*
|
|
1064
|
+
* @param {Element} node
|
|
1065
|
+
* @return {Array<Element>}
|
|
1066
|
+
*/
|
|
1067
|
+
function getFocusableChildren(node) {
|
|
1068
|
+
return $$(focusableSelectors.join(','), node).filter(function (child) {
|
|
1069
|
+
return !!(
|
|
1070
|
+
child.offsetWidth ||
|
|
1071
|
+
child.offsetHeight ||
|
|
1072
|
+
child.getClientRects().length
|
|
1073
|
+
)
|
|
1074
|
+
})
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Trap the focus inside the given element
|
|
1079
|
+
*
|
|
1080
|
+
* @param {Element} node
|
|
1081
|
+
* @param {Event} event
|
|
1082
|
+
*/
|
|
1083
|
+
function trapTabKey(node, event) {
|
|
1084
|
+
var focusableChildren = getFocusableChildren(node);
|
|
1085
|
+
var focusedItemIndex = focusableChildren.indexOf(document.activeElement);
|
|
1086
|
+
|
|
1087
|
+
// If the SHIFT key is being pressed while tabbing (moving backwards) and
|
|
1088
|
+
// the currently focused item is the first one, move the focus to the last
|
|
1089
|
+
// focusable item from the dialog element
|
|
1090
|
+
if (event.shiftKey && focusedItemIndex === 0) {
|
|
1091
|
+
focusableChildren[focusableChildren.length - 1].focus();
|
|
1092
|
+
event.preventDefault();
|
|
1093
|
+
// If the SHIFT key is not being pressed (moving forwards) and the currently
|
|
1094
|
+
// focused item is the last one, move the focus to the first focusable item
|
|
1095
|
+
// from the dialog element
|
|
1096
|
+
} else if (
|
|
1097
|
+
!event.shiftKey &&
|
|
1098
|
+
focusedItemIndex === focusableChildren.length - 1
|
|
1099
|
+
) {
|
|
1100
|
+
focusableChildren[0].focus();
|
|
1101
|
+
event.preventDefault();
|
|
1102
|
+
}
|
|
1580
1103
|
}
|
|
1581
1104
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1105
|
+
function instantiateDialogs() {
|
|
1106
|
+
$$('[data-a11y-dialog]').forEach(function (node) {
|
|
1107
|
+
new A11yDialog(node);
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
if (typeof document !== 'undefined') {
|
|
1112
|
+
if (document.readyState === 'loading') {
|
|
1113
|
+
document.addEventListener('DOMContentLoaded', instantiateDialogs);
|
|
1114
|
+
} else {
|
|
1115
|
+
if (window.requestAnimationFrame) {
|
|
1116
|
+
window.requestAnimationFrame(instantiateDialogs);
|
|
1117
|
+
} else {
|
|
1118
|
+
window.setTimeout(instantiateDialogs, 16);
|
|
1589
1119
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
ky.stop = stop;
|
|
1593
|
-
return ky;
|
|
1594
|
-
};
|
|
1595
|
-
const ky = createInstance();
|
|
1596
|
-
var ky$1 = ky;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1597
1122
|
|
|
1598
|
-
var
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1123
|
+
var CONTAINER_ID = "__authsignal-popup-container";
|
|
1124
|
+
var CONTENT_ID = "__authsignal-popup-content";
|
|
1125
|
+
var OVERLAY_ID = "__authsignal-popup-overlay";
|
|
1126
|
+
var STYLE_ID = "__authsignal-popup-style";
|
|
1127
|
+
var IFRAME_ID = "__authsignal-popup-iframe";
|
|
1128
|
+
var DEFAULT_WIDTH = "385px";
|
|
1129
|
+
var INITIAL_HEIGHT = "384px";
|
|
1130
|
+
var PopupHandler = /** @class */ (function () {
|
|
1131
|
+
function PopupHandler(_a) {
|
|
1132
|
+
var width = _a.width;
|
|
1133
|
+
this.popup = null;
|
|
1134
|
+
if (document.querySelector("#".concat(CONTAINER_ID))) {
|
|
1135
|
+
throw new Error("Multiple instances of Authsignal popup is not supported.");
|
|
1136
|
+
}
|
|
1137
|
+
this.create({ width: width });
|
|
1605
1138
|
}
|
|
1606
|
-
|
|
1607
|
-
var
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1139
|
+
PopupHandler.prototype.create = function (_a) {
|
|
1140
|
+
var _this = this;
|
|
1141
|
+
var _b = _a.width, width = _b === void 0 ? DEFAULT_WIDTH : _b;
|
|
1142
|
+
var isWidthValidCSSValue = CSS.supports("width", width);
|
|
1143
|
+
var popupWidth = width;
|
|
1144
|
+
if (!isWidthValidCSSValue) {
|
|
1145
|
+
console.warn("Invalid CSS value for `popupOptions.width`. Using default value instead.");
|
|
1146
|
+
popupWidth = DEFAULT_WIDTH;
|
|
1147
|
+
}
|
|
1148
|
+
// Create dialog container
|
|
1149
|
+
var container = document.createElement("div");
|
|
1150
|
+
container.setAttribute("id", CONTAINER_ID);
|
|
1151
|
+
container.setAttribute("aria-hidden", "true");
|
|
1152
|
+
// Create dialog overlay
|
|
1153
|
+
var overlay = document.createElement("div");
|
|
1154
|
+
overlay.setAttribute("id", OVERLAY_ID);
|
|
1155
|
+
overlay.setAttribute("data-a11y-dialog-hide", "true");
|
|
1156
|
+
// Create dialog content
|
|
1157
|
+
var content = document.createElement("div");
|
|
1158
|
+
content.setAttribute("id", CONTENT_ID);
|
|
1159
|
+
document.body.appendChild(container);
|
|
1160
|
+
// Create CSS for dialog
|
|
1161
|
+
var style = document.createElement("style");
|
|
1162
|
+
style.setAttribute("id", STYLE_ID);
|
|
1163
|
+
style.textContent = "\n #".concat(CONTAINER_ID, ",\n #").concat(OVERLAY_ID, " {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n\n #").concat(CONTAINER_ID, " {\n z-index: 2147483647;\n display: flex;\n }\n\n #").concat(CONTAINER_ID, "[aria-hidden='true'] {\n display: none;\n }\n\n #").concat(OVERLAY_ID, " {\n background-color: rgba(0, 0, 0, 0.18);\n }\n\n #").concat(CONTENT_ID, " {\n margin: auto;\n z-index: 2147483647;\n position: relative;\n background-color: transparent;\n border-radius: 8px;\n width: ").concat(popupWidth, ";\n }\n\n #").concat(CONTENT_ID, " iframe {\n width: 1px;\n min-width: 100%;\n border-radius: inherit;\n max-height: 95vh;\n height: ").concat(INITIAL_HEIGHT, ";\n }\n ");
|
|
1164
|
+
// Attach the created elements
|
|
1165
|
+
document.head.insertAdjacentElement("beforeend", style);
|
|
1166
|
+
container.appendChild(overlay);
|
|
1167
|
+
container.appendChild(content);
|
|
1168
|
+
this.popup = new A11yDialog(container);
|
|
1169
|
+
// Make sure to remove any trace of the dialog on hide
|
|
1170
|
+
this.popup.on("hide", function () {
|
|
1171
|
+
_this.destroy();
|
|
1621
1172
|
});
|
|
1622
1173
|
};
|
|
1623
|
-
|
|
1624
|
-
var
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
headers: this.buildHeaders(token)
|
|
1632
|
-
})];
|
|
1633
|
-
case 1:
|
|
1634
|
-
response = _b.sent();
|
|
1635
|
-
return [2 /*return*/, response.json()];
|
|
1636
|
-
}
|
|
1637
|
-
});
|
|
1638
|
-
});
|
|
1174
|
+
PopupHandler.prototype.destroy = function () {
|
|
1175
|
+
var dialogEl = document.querySelector("#".concat(CONTAINER_ID));
|
|
1176
|
+
var styleEl = document.querySelector("#".concat(STYLE_ID));
|
|
1177
|
+
if (dialogEl && styleEl) {
|
|
1178
|
+
document.body.removeChild(dialogEl);
|
|
1179
|
+
document.head.removeChild(styleEl);
|
|
1180
|
+
}
|
|
1181
|
+
window.removeEventListener("message", resizeIframe);
|
|
1639
1182
|
};
|
|
1640
|
-
|
|
1641
|
-
var
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1183
|
+
PopupHandler.prototype.show = function (_a) {
|
|
1184
|
+
var _b;
|
|
1185
|
+
var url = _a.url;
|
|
1186
|
+
if (!this.popup) {
|
|
1187
|
+
throw new Error("Popup is not initialized");
|
|
1188
|
+
}
|
|
1189
|
+
var iframe = document.createElement("iframe");
|
|
1190
|
+
iframe.setAttribute("id", IFRAME_ID);
|
|
1191
|
+
iframe.setAttribute("name", "authsignal");
|
|
1192
|
+
iframe.setAttribute("title", "Authsignal multi-factor authentication");
|
|
1193
|
+
iframe.setAttribute("src", url);
|
|
1194
|
+
iframe.setAttribute("frameborder", "0");
|
|
1195
|
+
iframe.setAttribute("allow", "publickey-credentials-get *; publickey-credentials-create *; clipboard-write");
|
|
1196
|
+
var dialogContent = document.querySelector("#".concat(CONTENT_ID));
|
|
1197
|
+
if (dialogContent) {
|
|
1198
|
+
dialogContent.appendChild(iframe);
|
|
1199
|
+
}
|
|
1200
|
+
window.addEventListener("message", resizeIframe);
|
|
1201
|
+
(_b = this.popup) === null || _b === void 0 ? void 0 : _b.show();
|
|
1656
1202
|
};
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
switch (_b.label) {
|
|
1663
|
-
case 0: return [4 /*yield*/, this.api.post("client/verify/passkey", {
|
|
1664
|
-
json: rest,
|
|
1665
|
-
headers: this.buildHeaders(token)
|
|
1666
|
-
})];
|
|
1667
|
-
case 1:
|
|
1668
|
-
response = _b.sent();
|
|
1669
|
-
return [2 /*return*/, response.json()];
|
|
1670
|
-
}
|
|
1671
|
-
});
|
|
1672
|
-
});
|
|
1203
|
+
PopupHandler.prototype.close = function () {
|
|
1204
|
+
if (!this.popup) {
|
|
1205
|
+
throw new Error("Popup is not initialized");
|
|
1206
|
+
}
|
|
1207
|
+
this.popup.hide();
|
|
1673
1208
|
};
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1209
|
+
PopupHandler.prototype.on = function (event, handler) {
|
|
1210
|
+
if (!this.popup) {
|
|
1211
|
+
throw new Error("Popup is not initialized");
|
|
1212
|
+
}
|
|
1213
|
+
this.popup.on(event, handler);
|
|
1679
1214
|
};
|
|
1680
|
-
return
|
|
1215
|
+
return PopupHandler;
|
|
1681
1216
|
}());
|
|
1682
|
-
|
|
1683
|
-
var
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
this.api = new PasskeyApiClient({ baseUrl: baseUrl, tenantId: tenantId });
|
|
1217
|
+
function resizeIframe(event) {
|
|
1218
|
+
var iframeEl = document.querySelector("#".concat(IFRAME_ID));
|
|
1219
|
+
if (iframeEl && event.data.height) {
|
|
1220
|
+
iframeEl.style.height = event.data.height + "px";
|
|
1687
1221
|
}
|
|
1688
|
-
|
|
1689
|
-
var userName = _a.userName, token = _a.token;
|
|
1690
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1691
|
-
var optionsResponse, registrationResponse, addAuthenticatorResponse;
|
|
1692
|
-
return __generator(this, function (_b) {
|
|
1693
|
-
switch (_b.label) {
|
|
1694
|
-
case 0: return [4 /*yield*/, this.api.registrationOptions({ userName: userName, token: token })];
|
|
1695
|
-
case 1:
|
|
1696
|
-
optionsResponse = _b.sent();
|
|
1697
|
-
return [4 /*yield*/, startRegistration(optionsResponse.options)];
|
|
1698
|
-
case 2:
|
|
1699
|
-
registrationResponse = _b.sent();
|
|
1700
|
-
return [4 /*yield*/, this.api.addAuthenticator({
|
|
1701
|
-
challengeId: optionsResponse.challengeId,
|
|
1702
|
-
registrationCredential: registrationResponse,
|
|
1703
|
-
token: token
|
|
1704
|
-
})];
|
|
1705
|
-
case 3:
|
|
1706
|
-
addAuthenticatorResponse = _b.sent();
|
|
1707
|
-
return [2 /*return*/, addAuthenticatorResponse === null || addAuthenticatorResponse === void 0 ? void 0 : addAuthenticatorResponse.accessToken];
|
|
1708
|
-
}
|
|
1709
|
-
});
|
|
1710
|
-
});
|
|
1711
|
-
};
|
|
1712
|
-
Passkey.prototype.signIn = function (params) {
|
|
1713
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1714
|
-
var optionsResponse, authenticationResponse, verifyResponse;
|
|
1715
|
-
return __generator(this, function (_a) {
|
|
1716
|
-
switch (_a.label) {
|
|
1717
|
-
case 0:
|
|
1718
|
-
if ((params === null || params === void 0 ? void 0 : params.token) && params.autofill) {
|
|
1719
|
-
throw new Error("Autofill is not supported when providing a token");
|
|
1720
|
-
}
|
|
1721
|
-
return [4 /*yield*/, this.api.authenticationOptions({ token: params === null || params === void 0 ? void 0 : params.token })];
|
|
1722
|
-
case 1:
|
|
1723
|
-
optionsResponse = _a.sent();
|
|
1724
|
-
return [4 /*yield*/, startAuthentication(optionsResponse.options, params === null || params === void 0 ? void 0 : params.autofill)];
|
|
1725
|
-
case 2:
|
|
1726
|
-
authenticationResponse = _a.sent();
|
|
1727
|
-
return [4 /*yield*/, this.api.verify({
|
|
1728
|
-
challengeId: optionsResponse.challengeId,
|
|
1729
|
-
authenticationCredential: authenticationResponse,
|
|
1730
|
-
token: params === null || params === void 0 ? void 0 : params.token
|
|
1731
|
-
})];
|
|
1732
|
-
case 3:
|
|
1733
|
-
verifyResponse = _a.sent();
|
|
1734
|
-
return [2 /*return*/, verifyResponse === null || verifyResponse === void 0 ? void 0 : verifyResponse.accessToken];
|
|
1735
|
-
}
|
|
1736
|
-
});
|
|
1737
|
-
});
|
|
1738
|
-
};
|
|
1739
|
-
return Passkey;
|
|
1740
|
-
}());
|
|
1222
|
+
}
|
|
1741
1223
|
|
|
1742
1224
|
var DEFAULT_COOKIE_NAME = "__as_aid";
|
|
1225
|
+
var DEFAULT_PROFILING_COOKIE_NAME = "__as_pid";
|
|
1743
1226
|
var DEFAULT_BASE_URL = "https://api.authsignal.com/v1";
|
|
1227
|
+
var TMX_ORG_ID = "4a08uqve";
|
|
1744
1228
|
var Authsignal = /** @class */ (function () {
|
|
1745
1229
|
function Authsignal(_a) {
|
|
1746
1230
|
var cookieDomain = _a.cookieDomain, _b = _a.cookieName, cookieName = _b === void 0 ? DEFAULT_COOKIE_NAME : _b, _c = _a.baseUrl, baseUrl = _c === void 0 ? DEFAULT_BASE_URL : _c, tenantId = _a.tenantId;
|
|
1747
1231
|
this.anonymousId = "";
|
|
1232
|
+
this.profilingId = "";
|
|
1748
1233
|
this.cookieDomain = "";
|
|
1749
1234
|
this.anonymousIdCookieName = "";
|
|
1750
1235
|
this._token = undefined;
|
|
@@ -1780,6 +1265,40 @@ var Authsignal = /** @class */ (function () {
|
|
|
1780
1265
|
this.launchWithRedirect(url);
|
|
1781
1266
|
}
|
|
1782
1267
|
};
|
|
1268
|
+
Authsignal.prototype.initAdvancedProfiling = function (baseUrl) {
|
|
1269
|
+
var profilingId = v4();
|
|
1270
|
+
this.profilingId = profilingId;
|
|
1271
|
+
setCookie({
|
|
1272
|
+
name: DEFAULT_PROFILING_COOKIE_NAME,
|
|
1273
|
+
value: profilingId,
|
|
1274
|
+
expire: Infinity,
|
|
1275
|
+
domain: this.cookieDomain,
|
|
1276
|
+
secure: document.location.protocol !== "http:"
|
|
1277
|
+
});
|
|
1278
|
+
var tmxProfilingScruiptUrl = baseUrl
|
|
1279
|
+
? "".concat(baseUrl, "/fp/tags.js?org_id=").concat(TMX_ORG_ID, "&session_id=").concat(profilingId)
|
|
1280
|
+
: "https://h.online-metrix.net/fp/tags.js?org_id=".concat(TMX_ORG_ID, "&session_id=").concat(profilingId);
|
|
1281
|
+
var script = document.createElement("script");
|
|
1282
|
+
script.src = tmxProfilingScruiptUrl;
|
|
1283
|
+
script.async = false;
|
|
1284
|
+
script.id = "as_adv_profile";
|
|
1285
|
+
document.head.appendChild(script);
|
|
1286
|
+
var pixelContainer = document.createElement("noscript");
|
|
1287
|
+
pixelContainer.setAttribute("id", "as_adv_profile_pixel");
|
|
1288
|
+
pixelContainer.setAttribute("aria-hidden", "true");
|
|
1289
|
+
// Instantiate Pixel
|
|
1290
|
+
var iframe = document.createElement("iframe");
|
|
1291
|
+
var profilingPixelUrl = baseUrl
|
|
1292
|
+
? "".concat(baseUrl, "/fp/tags?org_id=").concat(TMX_ORG_ID, "&session_id=").concat(profilingId)
|
|
1293
|
+
: "https://h.online-metrix.net/fp/tags?org_id=".concat(TMX_ORG_ID, "&session_id=").concat(profilingId);
|
|
1294
|
+
iframe.setAttribute("id", "as_adv_profile_pixel");
|
|
1295
|
+
iframe.setAttribute("src", profilingPixelUrl);
|
|
1296
|
+
iframe.setAttribute("style", "width: 100px; height: 100px; border: 0; position: absolute; top: -5000px;");
|
|
1297
|
+
if (pixelContainer) {
|
|
1298
|
+
pixelContainer.appendChild(iframe);
|
|
1299
|
+
document.body.prepend(pixelContainer);
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1783
1302
|
Authsignal.prototype.launchWithRedirect = function (url) {
|
|
1784
1303
|
window.location.href = url;
|
|
1785
1304
|
};
|