From d6e29cd0fa986703908fc5bca7c2eb406ad8e0e3 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Tue, 14 Feb 2017 10:37:00 -0700 Subject: [PATCH] WIP frameRequest refactor (iframe, window.open) --- oauth3.implicit.js | 136 ++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 77 deletions(-) diff --git a/oauth3.implicit.js b/oauth3.implicit.js index fbcbc89..4494500 100644 --- a/oauth3.implicit.js +++ b/oauth3.implicit.js @@ -251,7 +251,7 @@ ).then(function (params) { // discWin.child.close() // TODO params should have response_type indicating json, binary, etc - var directives = JSON.parse(OAUTH3.utils.atob(OAUTH3.utils.urlSafeBase64ToBase64(params.result || params.directives))); + var directives = JSON.parse(OAUTH3.utils.atob(OAUTH3.utils._urlSafeBase64ToBase64(params.result || params.directives))); return OAUTH3.hooks.directives.set(providerUri, directives); }); } @@ -310,7 +310,6 @@ xhr = new XMLHttpRequest(); } xhr.onreadystatechange = function () { - console.error('state change'); var data; if (xhr.readyState !== XMLHttpRequest.DONE) { // nothing to do here @@ -365,7 +364,10 @@ ); // TODO ability to reuse iframe instead of closing - return OAUTH3._browser._iframe.insert(discObj.url, discObj.state, opts).then(function (params) { + opts._windowType = opts.windowType; + opts.windowType = opts.windowType || 'background'; + return OAUTH3._browser.frameRequest(discObj.url, discObj.state, opts).then(function (params) { + opts.windowType = opts._windowType; OAUTH3._browser.closeFrame(discObj.state, { debug: opts.debug || params.debug }); if (params.error) { return OAUTH3.utils._formatError(providerUri, params.error); @@ -378,47 +380,67 @@ }); } , frameRequest: function (url, state, opts) { + opts = opts || {}; var previousFrame = OAUTH3._browser._frames[state]; - if (!opts.windowType) { - opts.windowType = 'popup'; + var windowType = opts.windowType; + if (!windowType) { + windowType = 'popup'; } - opts = opts || {}; + var timeout = opts.timeout; if (opts.debug) { - opts.timeout = opts.timeout || 15 * 60 * 1000; + timeout = timeout || 3 * 60 * 1000; + } + else { + timeout = timeout || ('background' === windowType ? 15 * 1000 : 3 * 60 * 1000); } return new OAUTH3.PromiseA(function (resolve, reject) { + // TODO periodically garbage collect expired handlers from window object var tok; function cleanup() { delete window['--oauth3-callback-' + state]; clearTimeout(tok); tok = null; + // the actual close is done later (by the caller) so that the window/frame + // can be reused or self-closes synchronously itself / by parent + // (probably won't ever happen, but that's a negotiable implementation detail) } + + console.log('[oauth3.implicit.js] callbackName', '--oauth3-callback-' + state); window['--oauth3-callback-' + state] = function (params) { resolve(params); cleanup(); }; tok = setTimeout(function () { - var err = new Error("the iframe request did not complete within 15 seconds"); + var err = new Error( + "the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s" + ); err.code = "E_TIMEOUT"; reject(err); cleanup(); - }, opts.timeout || 15 * 1000); + }, timeout); - if ('background' === opts.windowType) { + setTimeout(function () { + if (!OAUTH3._browser._frames[state]) { + reject(new Error("TODO: open the iframe first and discover oauth3 directives before popup")); + cleanup(); + } + }, 0); + + if ('background' === windowType) { if (previousFrame) { previousFrame.location = url; //promise = previousFrame.promise; } else { - OAUTH3._browser._iframe.insert(url, state, opts); + OAUTH3._browser._frames[state] = OAUTH3._browser.iframe(url, state, opts); } - } else if ('popup' === opts.windowType) { + } else if ('popup' === windowType) { if (previousFrame) { previousFrame.location = url; if (opts.debug) { @@ -426,9 +448,9 @@ } } else { - OAUTH3._browser.frame.open(url, state, opts); + OAUTH3._browser._frames[state] = OAUTH3._browser.frame(url, state, opts); } - } else if ('inline' === opts.windowType) { + } else if ('inline' === windowType) { // callback function will never execute and would need to redirect back to current page // rather than the callback.html url += '&original_url=' + OAUTH3._browser.window.location.href; @@ -478,72 +500,32 @@ } } , _frames: {} - , iframe: { - insert: function (url, state, opts) { - // TODO hidden / non-hidden (via directive even) - var framesrc = '