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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/js/Duo-Web-v2.js +300 -88
  3. data/js/Duo-Web-v2.min.js +1 -1
  4. metadata +18 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7c058b1950046167876439b51f1704b6352f255e
4
- data.tar.gz: cb1a60d911a9874e70eefcadb16a4273e339d8f9
3
+ metadata.gz: 0eb13447a3aed9e9be7a8073b18a54781e174f06
4
+ data.tar.gz: 952d88272d0e26fe20d254f4f025ba792015c6d2
5
5
  SHA512:
6
- metadata.gz: c57215b09fc5cc0135347425b65016e8b086962302677faaa12ca09d0c2481f9208228e8a96959ec1fff010dd79e980800dd30ed8223b830bc547603a3ba0d82
7
- data.tar.gz: c2733a950b847ab7e66e330d8207d0d64d1676b76cc5a5add8fe4bb0893d98f6a6c2b75e4ed6fe8f6a3a6cd8e18f0f13ac34c778869017cab31cf60452ef157b
6
+ metadata.gz: d19b8967b13c7a248157d398f57bf428aa2dc01c4159fc07750a99a2ba84f34fa06f8f1bd725518db1ce99b5e5bca3c5328fcac2b7be09a5ecbab443a97bbd79
7
+ data.tar.gz: b27b8828147e8f8ee78b9dddb22ee5ca80757f53afea04d4ae22a970e15fd795132bd46160e40449907291107b3691f90214b6c391df438993c03a5231a5ce03
@@ -1,14 +1,41 @@
1
1
  /**
2
2
  * Duo Web SDK v2
3
- * Copyright 2015, Duo Security
3
+ * Copyright 2019, Duo Security
4
4
  */
5
- window.Duo = (function(document, window) {
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 iframeId = 'duo_iframe',
10
- postAction = '',
11
- postArgument = 'sig_response',
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 throwError(message, url) {
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.iframe The iframe, or id of an iframe to set up
190
- * @param {String} options.host Hostname
191
- * @param {String} options.sig_request Request token
192
- * @param {String} [options.post_action=''] URL to POST back to after successful auth
193
- * @param {String} [options.post_argument='sig_response'] Parameter name to use for response token
194
- * @param {Function} [options.submit_callback] If provided, duo will not submit the form instead execute
195
- * the callback function with reference to the "duo_form" form object
196
- * submit_callback can be used to prevent the webpage from reloading.
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
- // if we were given an iframe, no need to wait for the rest of the DOM
230
- if (iframe) {
231
- ready();
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
- // try to find the iframe in the DOM
234
- iframe = document.getElementById(iframeId);
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
- // the event came from duo, do the post back
260
- doPostBack(event.data);
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
- // always clean up after yourself!
263
- offMessage(onReceivedMessage);
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(iframe, 'host');
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(iframe, 'sigRequest'));
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(iframe, 'postAction') || postAction;
499
+ postAction = getDataAttribute(promptElement, 'postAction') || postAction;
301
500
  }
302
501
 
303
502
  if (postArgument === 'sig_response') {
304
- postArgument = getDataAttribute(iframe, 'postArgument') || postArgument;
503
+ postArgument = getDataAttribute(promptElement, 'postArgument') || postArgument;
305
504
  }
306
505
 
307
- // point the iframe at Duo
308
- iframe.src = [
309
- 'https://', host, '/frame/web/v1/auth?tx=', duoSig,
310
- '&parent=', document.location.href,
311
- '&v=2.2'
312
- ].join('');
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
- }(document, window));
578
+ }));
@@ -1 +1 @@
1
- window.Duo=function(e,t){var i=/^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;var o=/^ERR\|[\w\s\.\(\)]+$/;var n="duo_iframe",a="",s="sig_response",r,f,u,d,m,c;function h(e,t){throw new Error("Duo Web SDK error: "+e+(t?"\n"+"See "+t+" for more information":""))}function g(e){return e.replace(/([a-z])([A-Z])/,"$1-$2").toLowerCase()}function l(e,t){if("dataset"in e){return e.dataset[t]}else{return e.getAttribute("data-"+g(t))}}function p(e,i,o,n){if("addEventListener"in t){e.addEventListener(i,n,false)}else{e.attachEvent(o,n)}}function w(e,i,o,n){if("removeEventListener"in t){e.removeEventListener(i,n,false)}else{e.detachEvent(o,n)}}function v(t){p(e,"DOMContentLoaded","onreadystatechange",t)}function b(t){w(e,"DOMContentLoaded","onreadystatechange",t)}function E(e){p(t,"message","onmessage",e)}function _(e){w(t,"message","onmessage",e)}function y(e){if(!e){return}if(e.indexOf("ERR|")===0){h(e.split("|")[1])}if(e.indexOf(":")===-1||e.split(":").length!==2){h("Duo was given a bad token. This might indicate a configuration "+"problem with one of Duo's client libraries.","https://www.duosecurity.com/docs/duoweb#first-steps")}var t=e.split(":");f=e;u=t[0];d=t[1];return{sigRequest:e,duoSig:t[0],appSig:t[1]}}function D(){m=e.getElementById(n);if(!m){throw new Error("This page does not contain an iframe for Duo to use."+'Add an element like <iframe id="duo_iframe"></iframe> '+"to this page. "+"See https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe "+"for more information.")}B();b(D)}function A(e){return Boolean(e.origin==="https://"+r&&typeof e.data==="string"&&(e.data.match(i)||e.data.match(o)))}function L(t){if(t){if(t.host){r=t.host}if(t.sig_request){y(t.sig_request)}if(t.post_action){a=t.post_action}if(t.post_argument){s=t.post_argument}if(t.iframe){if("tagName"in t.iframe){m=t.iframe}else if(typeof t.iframe==="string"){n=t.iframe}}if(typeof t.submit_callback==="function"){c=t.submit_callback}}if(m){B()}else{m=e.getElementById(n);if(m){B()}else{v(D)}}b(L)}function q(e){if(A(e)){R(e.data);_(q)}}function B(){if(!r){r=l(m,"host");if(!r){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.","https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe")}}if(!u||!d){y(l(m,"sigRequest"));if(!u||!d){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.","https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe")}}if(a===""){a=l(m,"postAction")||a}if(s==="sig_response"){s=l(m,"postArgument")||s}m.src=["https://",r,"/frame/web/v1/auth?tx=",u,"&parent=",e.location.href,"&v=2.2"].join("");E(q)}function R(t){var i=e.createElement("input");i.type="hidden";i.name=s;i.value=t+":"+d;var o=e.getElementById("duo_form");if(!o){o=e.createElement("form");m.parentElement.insertBefore(o,m.nextSibling)}o.method="POST";o.action=a;o.appendChild(i);if(typeof c==="function"){c.call(null,o)}else{o.submit()}}v(L);return{init:L,_parseSigRequest:y,_isDuoMessage:A,_doPostBack:R}}(document,window);
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.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: 2016-06-10 00:00:00.000000000 Z
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: '0'
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.1
84
+ rubygems_version: 2.5.2.3
71
85
  signing_key:
72
86
  specification_version: 4
73
87
  summary: Duo Web Ruby