duo_web 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/js/Duo-Web-v2.js +300 -88
- data/js/Duo-Web-v2.min.js +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0eb13447a3aed9e9be7a8073b18a54781e174f06
|
4
|
+
data.tar.gz: 952d88272d0e26fe20d254f4f025ba792015c6d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d19b8967b13c7a248157d398f57bf428aa2dc01c4159fc07750a99a2ba84f34fa06f8f1bd725518db1ce99b5e5bca3c5328fcac2b7be09a5ecbab443a97bbd79
|
7
|
+
data.tar.gz: b27b8828147e8f8ee78b9dddb22ee5ca80757f53afea04d4ae22a970e15fd795132bd46160e40449907291107b3691f90214b6c391df438993c03a5231a5ce03
|
data/js/Duo-Web-v2.js
CHANGED
@@ -1,14 +1,41 @@
|
|
1
1
|
/**
|
2
2
|
* Duo Web SDK v2
|
3
|
-
* Copyright
|
3
|
+
* Copyright 2019, Duo Security
|
4
4
|
*/
|
5
|
-
|
5
|
+
|
6
|
+
(function (root, factory) {
|
7
|
+
/*eslint-disable */
|
8
|
+
if (typeof define === 'function' && define.amd) {
|
9
|
+
// AMD. Register as an anonymous module.
|
10
|
+
define([], factory);
|
11
|
+
/*eslint-enable */
|
12
|
+
} else if (typeof module === 'object' && module.exports) {
|
13
|
+
// Node. Does not work with strict CommonJS, but
|
14
|
+
// only CommonJS-like environments that support module.exports,
|
15
|
+
// like Node.
|
16
|
+
module.exports = factory();
|
17
|
+
} else {
|
18
|
+
// Browser globals (root is window)
|
19
|
+
var Duo = factory();
|
20
|
+
// If the Javascript was loaded via a script tag, attempt to autoload
|
21
|
+
// the frame.
|
22
|
+
Duo._onReady(Duo.init);
|
23
|
+
|
24
|
+
// Attach Duo to the `window` object
|
25
|
+
root.Duo = Duo;
|
26
|
+
}
|
27
|
+
}(this, function() {
|
6
28
|
var DUO_MESSAGE_FORMAT = /^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;
|
7
29
|
var DUO_ERROR_FORMAT = /^ERR\|[\w\s\.\(\)]+$/;
|
8
|
-
|
9
|
-
var
|
10
|
-
|
11
|
-
|
30
|
+
var DUO_OPEN_WINDOW_FORMAT = /^DUO_OPEN_WINDOW\|/;
|
31
|
+
var VALID_OPEN_WINDOW_DOMAINS = [
|
32
|
+
'duo.com',
|
33
|
+
'duosecurity.com',
|
34
|
+
'duomobile.s3-us-west-1.amazonaws.com'
|
35
|
+
];
|
36
|
+
|
37
|
+
var postAction,
|
38
|
+
postArgument,
|
12
39
|
host,
|
13
40
|
sigRequest,
|
14
41
|
duoSig,
|
@@ -16,7 +43,30 @@ window.Duo = (function(document, window) {
|
|
16
43
|
iframe,
|
17
44
|
submitCallback;
|
18
45
|
|
19
|
-
function
|
46
|
+
// We use this function instead of setting initial values in the var
|
47
|
+
// declarations to make sure the initial values and subsequent
|
48
|
+
// re-initializations are always the same.
|
49
|
+
initializeStatefulVariables();
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Set local variables to whatever they should be before you call init().
|
53
|
+
*/
|
54
|
+
function initializeStatefulVariables() {
|
55
|
+
postAction = '';
|
56
|
+
postArgument = 'sig_response';
|
57
|
+
host = undefined;
|
58
|
+
sigRequest = undefined;
|
59
|
+
duoSig = undefined;
|
60
|
+
appSig = undefined;
|
61
|
+
iframe = undefined;
|
62
|
+
submitCallback = undefined;
|
63
|
+
}
|
64
|
+
|
65
|
+
function throwError(message, givenUrl) {
|
66
|
+
var url = (
|
67
|
+
givenUrl ||
|
68
|
+
'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
|
69
|
+
);
|
20
70
|
throw new Error(
|
21
71
|
'Duo Web SDK error: ' + message +
|
22
72
|
(url ? ('\n' + 'See ' + url + ' for more information') : '')
|
@@ -90,8 +140,7 @@ window.Duo = (function(document, window) {
|
|
90
140
|
if (sig.indexOf(':') === -1 || sig.split(':').length !== 2) {
|
91
141
|
throwError(
|
92
142
|
'Duo was given a bad token. This might indicate a configuration ' +
|
93
|
-
'problem with one of Duo\'s client libraries.'
|
94
|
-
'https://www.duosecurity.com/docs/duoweb#first-steps'
|
143
|
+
'problem with one of Duo\'s client libraries.'
|
95
144
|
);
|
96
145
|
}
|
97
146
|
|
@@ -109,30 +158,6 @@ window.Duo = (function(document, window) {
|
|
109
158
|
};
|
110
159
|
}
|
111
160
|
|
112
|
-
/**
|
113
|
-
* This function is set up to run when the DOM is ready, if the iframe was
|
114
|
-
* not available during `init`.
|
115
|
-
*/
|
116
|
-
function onDOMReady() {
|
117
|
-
iframe = document.getElementById(iframeId);
|
118
|
-
|
119
|
-
if (!iframe) {
|
120
|
-
throw new Error(
|
121
|
-
'This page does not contain an iframe for Duo to use.' +
|
122
|
-
'Add an element like <iframe id="duo_iframe"></iframe> ' +
|
123
|
-
'to this page. ' +
|
124
|
-
'See https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe ' +
|
125
|
-
'for more information.'
|
126
|
-
);
|
127
|
-
}
|
128
|
-
|
129
|
-
// we've got an iframe, away we go!
|
130
|
-
ready();
|
131
|
-
|
132
|
-
// always clean up after yourself
|
133
|
-
offReady(onDOMReady);
|
134
|
-
}
|
135
|
-
|
136
161
|
/**
|
137
162
|
* Validate that a MessageEvent came from the Duo service, and that it
|
138
163
|
* is a properly formatted payload.
|
@@ -149,7 +174,8 @@ window.Duo = (function(document, window) {
|
|
149
174
|
typeof event.data === 'string' &&
|
150
175
|
(
|
151
176
|
event.data.match(DUO_MESSAGE_FORMAT) ||
|
152
|
-
event.data.match(DUO_ERROR_FORMAT)
|
177
|
+
event.data.match(DUO_ERROR_FORMAT) ||
|
178
|
+
event.data.match(DUO_OPEN_WINDOW_FORMAT)
|
153
179
|
)
|
154
180
|
);
|
155
181
|
}
|
@@ -175,7 +201,7 @@ window.Duo = (function(document, window) {
|
|
175
201
|
* ```
|
176
202
|
*
|
177
203
|
* Example using `data-` attributes:
|
178
|
-
* ```
|
204
|
+
* ```html
|
179
205
|
* <iframe id="duo_iframe"
|
180
206
|
* data-host="api-main.duo.test"
|
181
207
|
* data-sig-request="..."
|
@@ -185,17 +211,56 @@ window.Duo = (function(document, window) {
|
|
185
211
|
* </iframe>
|
186
212
|
* ```
|
187
213
|
*
|
214
|
+
* Some browsers (especially embedded browsers) don't like it when the Duo
|
215
|
+
* Web SDK changes the `src` attribute on the iframe. To prevent this, there
|
216
|
+
* is an alternative way to use the Duo Web SDK:
|
217
|
+
*
|
218
|
+
* Add a div (or any other container element) instead of an iframe to the
|
219
|
+
* DOM with an id of "duo_iframe", or pass that element to the
|
220
|
+
* `iframeContainer` parameter of `Duo.init`. An iframe will be created and
|
221
|
+
* inserted into that container element, preventing `src` change related
|
222
|
+
* bugs. WARNING: All other elements in the container will be deleted.
|
223
|
+
*
|
224
|
+
* The `iframeAttributes` parameter of `Duo.init` is available to set any
|
225
|
+
* attributes on the inserted iframe if the Duo Web SDK is inserting the
|
226
|
+
* iframe. For details, see the parameter documentation below.
|
227
|
+
*
|
188
228
|
* @param {Object} options
|
189
|
-
* @param {String} options.
|
190
|
-
* @param {String} options.
|
191
|
-
* @param {String} options.
|
192
|
-
*
|
193
|
-
*
|
194
|
-
*
|
195
|
-
*
|
196
|
-
*
|
229
|
+
* @param {String} options.host - Hostname for the Duo Prompt.
|
230
|
+
* @param {String} options.sig_request - Request token.
|
231
|
+
* @param {String|HTMLElement} [options.iframe] - The iframe, or id of an
|
232
|
+
* iframe that will be used for the Duo Prompt. If you don't provide
|
233
|
+
* this or the `iframeContainer` parameter the Duo Web SDK will default
|
234
|
+
* to using whatever element has an id of "duo_iframe".
|
235
|
+
* @param {String|HTMLElement} [options.iframeContainer] - The element you
|
236
|
+
* want the Duo Prompt inserted into, or the id of that element.
|
237
|
+
* Anything inside this element will be deleted and replaced with an
|
238
|
+
* iframe hosting the Duo prompt. If you don't provide this or the
|
239
|
+
* `iframe` parameter the Duo Web SDK will default to using whatever
|
240
|
+
* element has an id of "duo_iframe".
|
241
|
+
* @param {Object} [options.iframeAttributes] - Object with names and
|
242
|
+
* values coresponding to attributes you want added to the Duo Prompt
|
243
|
+
* iframe, like `title`, `width` and `allow`. WARNING: this parameter
|
244
|
+
* only works if you use the `iframeContainer` parameter or add an id
|
245
|
+
* of "duo_iframe" to an element that isn't an iframe. If you have
|
246
|
+
* added an iframe to the DOM yourself, you should set those attributes
|
247
|
+
* directly on the iframe.
|
248
|
+
* @param {String} [options.post_action=''] - URL to POST back to after a
|
249
|
+
* successful auth.
|
250
|
+
* @param {String} [options.post_argument='sig_response'] - Parameter name
|
251
|
+
* to use for response token.
|
252
|
+
* @param {Function} [options.submit_callback] - If provided, the Duo Web
|
253
|
+
* SDK will not submit the form. Instead it will execute this callback
|
254
|
+
* function passing in a reference to the "duo_form" form object.
|
255
|
+
* `submit_callback`` can be used to prevent the webpage from reloading.
|
197
256
|
*/
|
198
257
|
function init(options) {
|
258
|
+
// If init() is called more than once we have to reset all the local
|
259
|
+
// variables to ensure init() will work the same way every time. This
|
260
|
+
// helps people making single page applications. SPAs may periodically
|
261
|
+
// remove the iframe and add a new one that has to be initialized.
|
262
|
+
initializeStatefulVariables();
|
263
|
+
|
199
264
|
if (options) {
|
200
265
|
if (options.host) {
|
201
266
|
host = options.host;
|
@@ -213,39 +278,114 @@ window.Duo = (function(document, window) {
|
|
213
278
|
postArgument = options.post_argument;
|
214
279
|
}
|
215
280
|
|
216
|
-
if (options.iframe) {
|
217
|
-
if ('tagName' in options.iframe) {
|
218
|
-
iframe = options.iframe;
|
219
|
-
} else if (typeof options.iframe === 'string') {
|
220
|
-
iframeId = options.iframe;
|
221
|
-
}
|
222
|
-
}
|
223
|
-
|
224
281
|
if (typeof options.submit_callback === 'function') {
|
225
282
|
submitCallback = options.submit_callback;
|
226
283
|
}
|
227
284
|
}
|
228
285
|
|
229
|
-
|
230
|
-
if (
|
231
|
-
|
286
|
+
var promptElement = getPromptElement(options);
|
287
|
+
if (promptElement) {
|
288
|
+
// If we can get the element that will host the prompt, set it.
|
289
|
+
ready(promptElement, options.iframeAttributes || {});
|
232
290
|
} else {
|
233
|
-
//
|
234
|
-
|
235
|
-
|
236
|
-
// iframe is in the DOM, away we go!
|
237
|
-
if (iframe) {
|
238
|
-
ready();
|
239
|
-
} else {
|
240
|
-
// wait until the DOM is ready, then try again
|
241
|
-
onReady(onDOMReady);
|
242
|
-
}
|
291
|
+
// If the element that will host the prompt isn't available yet, set
|
292
|
+
// it up after the DOM finishes loading.
|
293
|
+
asyncReady(options);
|
243
294
|
}
|
244
295
|
|
245
296
|
// always clean up after yourself!
|
246
297
|
offReady(init);
|
247
298
|
}
|
248
299
|
|
300
|
+
/**
|
301
|
+
* Given the options from init(), get the iframe or iframe container that
|
302
|
+
* should be used for the Duo Prompt. Returns `null` if nothing was found.
|
303
|
+
*/
|
304
|
+
function getPromptElement(options) {
|
305
|
+
var result;
|
306
|
+
|
307
|
+
if (options.iframe && options.iframeContainer) {
|
308
|
+
throwError(
|
309
|
+
'Passing both `iframe` and `iframeContainer` arguments at the' +
|
310
|
+
' same time is not allowed.'
|
311
|
+
);
|
312
|
+
} else if (options.iframe) {
|
313
|
+
// If we are getting an iframe, try to get it and raise if the
|
314
|
+
// element we find is NOT an iframe.
|
315
|
+
result = getUserDefinedElement(options.iframe);
|
316
|
+
validateIframe(result);
|
317
|
+
} else if (options.iframeContainer) {
|
318
|
+
result = getUserDefinedElement(options.iframeContainer);
|
319
|
+
validateIframeContainer(result);
|
320
|
+
} else {
|
321
|
+
result = document.getElementById('duo_iframe');
|
322
|
+
}
|
323
|
+
|
324
|
+
return result;
|
325
|
+
}
|
326
|
+
|
327
|
+
/**
|
328
|
+
* When given an HTMLElement, return it. When given a string, get an element
|
329
|
+
* with that id, else return null.
|
330
|
+
*/
|
331
|
+
function getUserDefinedElement(object) {
|
332
|
+
if (object.tagName) {
|
333
|
+
return object;
|
334
|
+
} else if (typeof object == 'string') {
|
335
|
+
return document.getElementById(object);
|
336
|
+
}
|
337
|
+
return null;
|
338
|
+
}
|
339
|
+
|
340
|
+
/**
|
341
|
+
* Check if the given thing is an iframe.
|
342
|
+
*/
|
343
|
+
function isIframe(element) {
|
344
|
+
return (
|
345
|
+
element &&
|
346
|
+
element.tagName &&
|
347
|
+
element.tagName.toLowerCase() === 'iframe'
|
348
|
+
);
|
349
|
+
}
|
350
|
+
|
351
|
+
/**
|
352
|
+
* Throw an error if we are given an element that is NOT an iframe.
|
353
|
+
*/
|
354
|
+
function validateIframe(element) {
|
355
|
+
if (element && !isIframe(element)) {
|
356
|
+
throwError(
|
357
|
+
'`iframe` only accepts an iframe element or the id of an' +
|
358
|
+
' iframe. To use a non-iframe element, use the' +
|
359
|
+
' `iframeContainer` argument.'
|
360
|
+
);
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
/**
|
365
|
+
* Throw an error if we are given an element that IS an iframe instead of an
|
366
|
+
* element that we can insert an iframe into.
|
367
|
+
*/
|
368
|
+
function validateIframeContainer(element) {
|
369
|
+
if (element && isIframe(element)) {
|
370
|
+
throwError(
|
371
|
+
'`iframeContainer` only accepts a non-iframe element or the' +
|
372
|
+
' id of a non-iframe. To use a non-iframe element, use the' +
|
373
|
+
' `iframeContainer` argument on Duo.init().'
|
374
|
+
);
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
/**
|
379
|
+
* Generate the URL that goes to the Duo Prompt.
|
380
|
+
*/
|
381
|
+
function generateIframeSrc() {
|
382
|
+
return [
|
383
|
+
'https://', host, '/frame/web/v1/auth?tx=', duoSig,
|
384
|
+
'&parent=', encodeURIComponent(document.location.href),
|
385
|
+
'&v=2.8'
|
386
|
+
].join('');
|
387
|
+
}
|
388
|
+
|
249
389
|
/**
|
250
390
|
* This function is called when a message was received from another domain
|
251
391
|
* using the `postMessage` API. Check that the event came from the Duo
|
@@ -256,40 +396,99 @@ window.Duo = (function(document, window) {
|
|
256
396
|
*/
|
257
397
|
function onReceivedMessage(event) {
|
258
398
|
if (isDuoMessage(event)) {
|
259
|
-
|
260
|
-
|
399
|
+
if (event.data.match(DUO_OPEN_WINDOW_FORMAT)) {
|
400
|
+
var url = event.data.substring("DUO_OPEN_WINDOW|".length);
|
401
|
+
if (isValidUrlToOpen(url)) {
|
402
|
+
// Open the URL that comes after the DUO_WINDOW_OPEN token.
|
403
|
+
window.open(url, "_self");
|
404
|
+
}
|
405
|
+
}
|
406
|
+
else {
|
407
|
+
// the event came from duo, do the post back
|
408
|
+
doPostBack(event.data);
|
261
409
|
|
262
|
-
|
263
|
-
|
410
|
+
// always clean up after yourself!
|
411
|
+
offMessage(onReceivedMessage);
|
412
|
+
}
|
264
413
|
}
|
265
414
|
}
|
266
415
|
|
416
|
+
/**
|
417
|
+
* Validate that this passed in URL is one that we will actually allow to
|
418
|
+
* be opened.
|
419
|
+
* @param url String URL that the message poster wants to open
|
420
|
+
* @returns {boolean} true if we allow this url to be opened in the window
|
421
|
+
*/
|
422
|
+
function isValidUrlToOpen(url) {
|
423
|
+
if (!url) {
|
424
|
+
return false;
|
425
|
+
}
|
426
|
+
|
427
|
+
var parser = document.createElement('a');
|
428
|
+
parser.href = url;
|
429
|
+
|
430
|
+
if (parser.protocol === "duotrustedendpoints:") {
|
431
|
+
return true;
|
432
|
+
} else if (parser.protocol !== "https:") {
|
433
|
+
return false;
|
434
|
+
}
|
435
|
+
|
436
|
+
for (var i = 0; i < VALID_OPEN_WINDOW_DOMAINS.length; i++) {
|
437
|
+
if (parser.hostname.endsWith("." + VALID_OPEN_WINDOW_DOMAINS[i]) ||
|
438
|
+
parser.hostname === VALID_OPEN_WINDOW_DOMAINS[i]) {
|
439
|
+
return true;
|
440
|
+
}
|
441
|
+
}
|
442
|
+
return false;
|
443
|
+
}
|
444
|
+
|
445
|
+
/**
|
446
|
+
* Register a callback to call ready() after the DOM has loaded.
|
447
|
+
*/
|
448
|
+
function asyncReady(options) {
|
449
|
+
var callback = function() {
|
450
|
+
var promptElement = getPromptElement(options);
|
451
|
+
if (!promptElement) {
|
452
|
+
throwError(
|
453
|
+
'This page does not contain an iframe for Duo to use.' +
|
454
|
+
' Add an element like' +
|
455
|
+
' <iframe id="duo_iframe"></iframe> to this page.'
|
456
|
+
);
|
457
|
+
}
|
458
|
+
|
459
|
+
ready(promptElement, options.iframeAttributes || {});
|
460
|
+
|
461
|
+
// Always clean up after yourself.
|
462
|
+
offReady(callback)
|
463
|
+
};
|
464
|
+
|
465
|
+
onReady(callback);
|
466
|
+
}
|
467
|
+
|
267
468
|
/**
|
268
469
|
* Point the iframe at Duo, then wait for it to postMessage back to us.
|
269
470
|
*/
|
270
|
-
function ready() {
|
471
|
+
function ready(promptElement, iframeAttributes) {
|
271
472
|
if (!host) {
|
272
|
-
host = getDataAttribute(
|
473
|
+
host = getDataAttribute(promptElement, 'host');
|
273
474
|
|
274
475
|
if (!host) {
|
275
476
|
throwError(
|
276
477
|
'No API hostname is given for Duo to use. Be sure to pass ' +
|
277
478
|
'a `host` parameter to Duo.init, or through the `data-host` ' +
|
278
|
-
'attribute on the iframe element.'
|
279
|
-
'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
|
479
|
+
'attribute on the iframe element.'
|
280
480
|
);
|
281
481
|
}
|
282
482
|
}
|
283
483
|
|
284
484
|
if (!duoSig || !appSig) {
|
285
|
-
parseSigRequest(getDataAttribute(
|
485
|
+
parseSigRequest(getDataAttribute(promptElement, 'sigRequest'));
|
286
486
|
|
287
487
|
if (!duoSig || !appSig) {
|
288
488
|
throwError(
|
289
489
|
'No valid signed request is given. Be sure to give the ' +
|
290
490
|
'`sig_request` parameter to Duo.init, or use the ' +
|
291
|
-
'`data-sig-request` attribute on the iframe element.'
|
292
|
-
'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
|
491
|
+
'`data-sig-request` attribute on the iframe element.'
|
293
492
|
);
|
294
493
|
}
|
295
494
|
}
|
@@ -297,19 +496,35 @@ window.Duo = (function(document, window) {
|
|
297
496
|
// if postAction/Argument are defaults, see if they are specified
|
298
497
|
// as data attributes on the iframe
|
299
498
|
if (postAction === '') {
|
300
|
-
postAction = getDataAttribute(
|
499
|
+
postAction = getDataAttribute(promptElement, 'postAction') || postAction;
|
301
500
|
}
|
302
501
|
|
303
502
|
if (postArgument === 'sig_response') {
|
304
|
-
postArgument = getDataAttribute(
|
503
|
+
postArgument = getDataAttribute(promptElement, 'postArgument') || postArgument;
|
305
504
|
}
|
306
505
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
506
|
+
if (isIframe(promptElement)) {
|
507
|
+
iframe = promptElement;
|
508
|
+
iframe.src = generateIframeSrc();
|
509
|
+
} else {
|
510
|
+
// If given a container to put an iframe in, clean out any children
|
511
|
+
// child elements in case `init()` was called more than once.
|
512
|
+
while (promptElement.firstChild) {
|
513
|
+
// We call `removeChild()` instead of doing `innerHTML = ""`
|
514
|
+
// to make sure we unbind any events.
|
515
|
+
promptElement.removeChild(promptElement.firstChild)
|
516
|
+
}
|
517
|
+
|
518
|
+
iframe = document.createElement('iframe');
|
519
|
+
|
520
|
+
// Set the src and all other attributes on the new iframe.
|
521
|
+
iframeAttributes['src'] = generateIframeSrc();
|
522
|
+
for (var name in iframeAttributes) {
|
523
|
+
iframe.setAttribute(name, iframeAttributes[name]);
|
524
|
+
}
|
525
|
+
|
526
|
+
promptElement.appendChild(iframe);
|
527
|
+
}
|
313
528
|
|
314
529
|
// listen for the 'message' event
|
315
530
|
onMessage(onReceivedMessage);
|
@@ -353,14 +568,11 @@ window.Duo = (function(document, window) {
|
|
353
568
|
}
|
354
569
|
}
|
355
570
|
|
356
|
-
// when the DOM is ready, initialize
|
357
|
-
// note that this will get cleaned up if the user calls init directly!
|
358
|
-
onReady(init);
|
359
|
-
|
360
571
|
return {
|
361
572
|
init: init,
|
573
|
+
_onReady: onReady,
|
362
574
|
_parseSigRequest: parseSigRequest,
|
363
575
|
_isDuoMessage: isDuoMessage,
|
364
576
|
_doPostBack: doPostBack
|
365
577
|
};
|
366
|
-
}
|
578
|
+
}));
|
data/js/Duo-Web-v2.min.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
!function(e,t){if("function"==typeof define&&define.amd)define([],t);else if("object"==typeof module&&module.exports)module.exports=t();else{var n=t();n._onReady(n.init),e.Duo=n}}(this,function(){var i,a,r,s,u,f,m,t=/^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/,n=/^ERR\|[\w\s\.\(\)]+$/,d=/^DUO_OPEN_WINDOW\|/,c=["duo.com","duosecurity.com","duomobile.s3-us-west-1.amazonaws.com"];function l(){i="",a="sig_response",r=undefined,undefined,s=undefined,u=undefined,f=undefined,m=undefined}function h(e,t){var n=t||"https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe";throw new Error("Duo Web SDK error: "+e+(n?"\nSee "+n+" for more information":""))}function g(e,t){return"dataset"in e?e.dataset[t]:e.getAttribute("data-"+function n(e){return e.replace(/([a-z])([A-Z])/,"$1-$2").toLowerCase()}(t))}function p(e,t,n,o){"addEventListener"in window?e.addEventListener(t,o,!1):e.attachEvent(n,o)}function v(e,t,n,o){"removeEventListener"in window?e.removeEventListener(t,o,!1):e.detachEvent(n,o)}function w(e){p(document,"DOMContentLoaded","onreadystatechange",e)}function _(e){v(document,"DOMContentLoaded","onreadystatechange",e)}function b(e){if(e){0===e.indexOf("ERR|")&&h(e.split("|")[1]),-1!==e.indexOf(":")&&2===e.split(":").length||h("Duo was given a bad token. This might indicate a configuration problem with one of Duo's client libraries.");var t=e.split(":");return e,s=t[0],u=t[1],{sigRequest:e,duoSig:t[0],appSig:t[1]}}}function E(e){return Boolean(e.origin==="https://"+r&&"string"==typeof e.data&&(e.data.match(t)||e.data.match(n)||e.data.match(d)))}function y(e){var t;return e.iframe&&e.iframeContainer?h("Passing both `iframe` and `iframeContainer` arguments at the same time is not allowed."):e.iframe?function n(e){e&&!D(e)&&h("`iframe` only accepts an iframe element or the id of an iframe. To use a non-iframe element, use the `iframeContainer` argument.")}(t=C(e.iframe)):e.iframeContainer?function o(e){e&&D(e)&&h("`iframeContainer` only accepts a non-iframe element or the id of a non-iframe. To use a non-iframe element, use the `iframeContainer` argument on Duo.init().")}(t=C(e.iframeContainer)):t=document.getElementById("duo_iframe"),t}function C(e){return e.tagName?e:"string"==typeof e?document.getElementById(e):null}function D(e){return e&&e.tagName&&"iframe"===e.tagName.toLowerCase()}function A(){return["https://",r,"/frame/web/v1/auth?tx=",s,"&parent=",encodeURIComponent(document.location.href),"&v=2.8"].join("")}function O(e){if(E(e))if(e.data.match(d)){var t=e.data.substring("DUO_OPEN_WINDOW|".length);(function o(e){if(!e)return!1;var t=document.createElement("a");{if(t.href=e,"duotrustedendpoints:"===t.protocol)return!0;if("https:"!==t.protocol)return!1}for(var n=0;n<c.length;n++)if(t.hostname.endsWith("."+c[n])||t.hostname===c[n])return!0;return!1})(t)&&window.open(t,"_self")}else L(e.data),function n(e){v(window,"message","onmessage",e)}(O)}function R(e,t){if(r||(r=g(e,"host"))||h("No API hostname is given for Duo to use. Be sure to pass a `host` parameter to Duo.init, or through the `data-host` attribute on the iframe element."),s&&u||(b(g(e,"sigRequest")),s&&u||h("No valid signed request is given. Be sure to give the `sig_request` parameter to Duo.init, or use the `data-sig-request` attribute on the iframe element.")),""===i&&(i=g(e,"postAction")||i),"sig_response"===a&&(a=g(e,"postArgument")||a),D(e))(f=e).src=A();else{for(;e.firstChild;)e.removeChild(e.firstChild);for(var n in f=document.createElement("iframe"),t.src=A(),t)f.setAttribute(n,t[n]);e.appendChild(f)}!function o(e){p(window,"message","onmessage",e)}(O)}function L(e){var t=document.createElement("input");t.type="hidden",t.name=a,t.value=e+":"+u;var n=document.getElementById("duo_form");n||(n=document.createElement("form"),f.parentElement.insertBefore(n,f.nextSibling)),n.method="POST",n.action=i,n.appendChild(t),"function"==typeof m?m.call(null,n):n.submit()}return l(),{init:function N(e){l(),e&&(e.host&&(r=e.host),e.sig_request&&b(e.sig_request),e.post_action&&(i=e.post_action),e.post_argument&&(a=e.post_argument),"function"==typeof e.submit_callback&&(m=e.submit_callback));var t=y(e);t?R(t,e.iframeAttributes||{}):function o(t){var n=function(){var e=y(t);e||h('This page does not contain an iframe for Duo to use. Add an element like <iframe id="duo_iframe"></iframe> to this page.'),R(e,t.iframeAttributes||{}),_(n)};w(n)}(e),_(N)},_onReady:w,_parseSigRequest:b,_isDuoMessage:E,_doPostBack:L}});
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duo_web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Duo Security
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -30,12 +30,26 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.49.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.49.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
55
|
description: A Ruby implementation of the Duo Web SDK.
|
@@ -67,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
81
|
version: '0'
|
68
82
|
requirements: []
|
69
83
|
rubyforge_project:
|
70
|
-
rubygems_version: 2.5.
|
84
|
+
rubygems_version: 2.5.2.3
|
71
85
|
signing_key:
|
72
86
|
specification_version: 4
|
73
87
|
summary: Duo Web Ruby
|