duo_web 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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