2017-02-13 22:22:06 +00:00
|
|
|
/* global Promise */
|
|
|
|
;(function (exports) {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var OAUTH3 = exports.OAUTH3 = {
|
|
|
|
utils: {
|
2017-02-14 00:53:54 +00:00
|
|
|
clientUri: function (location) {
|
|
|
|
return OAUTH3.utils.uri.normalize(location.host + location.pathname);
|
|
|
|
}
|
|
|
|
, atob: function (base64) {
|
2017-02-13 22:22:06 +00:00
|
|
|
return (exports.atob || require('atob'))(base64);
|
|
|
|
}
|
2017-02-14 00:53:54 +00:00
|
|
|
, _urlSafeBase64ToBase64: function (b64) {
|
2017-02-13 22:22:06 +00:00
|
|
|
// URL-safe Base64 to Base64
|
|
|
|
// https://en.wikipedia.org/wiki/Base64
|
|
|
|
// https://gist.github.com/catwell/3046205
|
|
|
|
var mod = b64.length % 4;
|
|
|
|
if (2 === mod) { b64 += '=='; }
|
|
|
|
if (3 === mod) { b64 += '='; }
|
|
|
|
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
|
|
|
return b64;
|
|
|
|
}
|
|
|
|
, uri: {
|
|
|
|
normalize: function (uri) {
|
|
|
|
// tested with
|
|
|
|
// example.com
|
|
|
|
// example.com/
|
|
|
|
// http://example.com
|
|
|
|
// https://example.com/
|
|
|
|
return uri
|
|
|
|
.replace(/^(https?:\/\/)?/i, '')
|
|
|
|
.replace(/\/?$/, '')
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, url: {
|
|
|
|
normalize: function (url) {
|
|
|
|
// tested with
|
|
|
|
// example.com
|
|
|
|
// example.com/
|
|
|
|
// http://example.com
|
|
|
|
// https://example.com/
|
|
|
|
return url
|
|
|
|
.replace(/^(https?:\/\/)?/i, 'https://')
|
|
|
|
.replace(/\/?$/, '')
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, query: {
|
|
|
|
stringify: function (params) {
|
|
|
|
var qs = [];
|
|
|
|
|
|
|
|
Object.keys(params).forEach(function (key) {
|
|
|
|
// TODO nullify instead?
|
|
|
|
if ('undefined' === typeof params[key]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('scope' === key) {
|
|
|
|
params[key] = OAUTH3.utils.scope.stringify(params[key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
|
|
|
|
});
|
|
|
|
|
|
|
|
return qs.join('&');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, scope: {
|
|
|
|
stringify: function (scope) {
|
|
|
|
if (Array.isArray(scope)) {
|
|
|
|
scope = scope.join(' ');
|
|
|
|
}
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, randomState: function () {
|
|
|
|
// TODO put in different file for browser vs node
|
|
|
|
try {
|
|
|
|
return Array.prototype.slice.call(
|
|
|
|
window.crypto.getRandomValues(new Uint8Array(16))
|
|
|
|
).map(function (ch) { return (ch).toString(16); }).join('');
|
|
|
|
} catch(e) {
|
|
|
|
return OAUTH3.utils._insecureRandomState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, _insecureRandomState: function () {
|
|
|
|
var i;
|
|
|
|
var ch;
|
|
|
|
var str;
|
|
|
|
// TODO use fisher-yates on 0..255 and select [0] 16 times
|
|
|
|
// [security] https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.5qx0bf95a
|
|
|
|
// https://github.com/v8/v8/blob/b0e4dce6091a8777bda80d962df76525dc6c5ea9/src/js/math.js#L135-L144
|
|
|
|
// Note: newer versions of v8 do not have this bug, but other engines may still
|
|
|
|
console.warn('[security] crypto.getRandomValues() failed, falling back to Math.random()');
|
|
|
|
str = '';
|
|
|
|
for (i = 0; i < 32; i += 1) {
|
|
|
|
ch = Math.round(Math.random() * 255).toString(16);
|
|
|
|
if (ch.length < 2) { ch = '0' + ch; }
|
|
|
|
str += ch;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, urls: {
|
|
|
|
discover: function (providerUri, opts) {
|
|
|
|
if (!providerUri) {
|
|
|
|
throw new Error("cannot discover without providerUri");
|
|
|
|
}
|
|
|
|
if (!opts.client_id) {
|
|
|
|
throw new Error("cannot discover without options.client_id");
|
|
|
|
}
|
|
|
|
var clientId = OAUTH3.utils.url.normalize(opts.client_id || opts.client_uri);
|
|
|
|
providerUri = OAUTH3.utils.url.normalize(providerUri);
|
|
|
|
|
|
|
|
var params = {
|
|
|
|
action: 'directives'
|
|
|
|
, state: OAUTH3.utils.randomState()
|
|
|
|
, redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/')
|
|
|
|
, response_type: 'rpc'
|
|
|
|
, _method: 'GET'
|
|
|
|
, _pathname: '.well-known/oauth3/directives.json'
|
|
|
|
, debug: opts.debug || undefined
|
|
|
|
};
|
|
|
|
|
|
|
|
var result = {
|
|
|
|
url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.utils.query.stringify(params)
|
|
|
|
, state: params.state
|
|
|
|
, method: 'GET'
|
|
|
|
, query: params
|
|
|
|
};
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, hooks: {
|
|
|
|
directives: {
|
|
|
|
get: function (providerUri) {
|
|
|
|
providerUri = OAUTH3.utils.uri.normalize(providerUri);
|
|
|
|
console.warn('[Warn] You should implement: OAUTH3.hooks.directives.get = function (providerUri) { return directives; }');
|
|
|
|
if (!OAUTH3.hooks.directives._cache) { OAUTH3.hooks.directives._cache = {}; }
|
|
|
|
return JSON.parse(window.localStorage.getItem('directives-' + providerUri) || '{}');
|
|
|
|
}
|
|
|
|
, set: function (providerUri, directives) {
|
|
|
|
providerUri = OAUTH3.utils.uri.normalize(providerUri);
|
|
|
|
console.warn('[Warn] You should implement: OAUTH3.hooks.directives.set = function (providerUri, directives) { return directives; }');
|
|
|
|
console.warn(directives);
|
|
|
|
if (!OAUTH3.hooks.directives._cache) { OAUTH3.hooks.directives._cache = {}; }
|
|
|
|
window.localStorage.setItem('directives-' + providerUri, JSON.stringify(directives));
|
|
|
|
OAUTH3.hooks.directives._cache[providerUri] = directives;
|
|
|
|
return directives;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, discover: function (providerUri, opts) {
|
|
|
|
if (!providerUri) {
|
|
|
|
throw new Error('oauth3.discover(providerUri, opts) received providerUri as ' + providerUri);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OAUTH3.PromiseA.resolve(OAUTH3.hooks.directives.get(providerUri)).then(function (directives) {
|
|
|
|
if (directives && directives.issuer) {
|
2017-02-14 00:53:54 +00:00
|
|
|
return directives;
|
2017-02-13 22:22:06 +00:00
|
|
|
}
|
|
|
|
return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) {
|
|
|
|
directives.issuer = directives.issuer || OAUTH3.utils.url.normalize(providerUri);
|
|
|
|
// OAUTH3.PromiseA.resolve() is taken care of because this is wrapped
|
|
|
|
return OAUTH3.hooks.directives.set(providerUri, directives);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// this is the browser version
|
|
|
|
, _discoverHelper: function (providerUri, opts) {
|
|
|
|
return OAUTH3._browser.discover(providerUri, opts);
|
|
|
|
}
|
2017-02-14 00:53:54 +00:00
|
|
|
, request: function (preq) {
|
|
|
|
return OAUTH3._browser.request(preq);
|
|
|
|
}
|
|
|
|
, implicitGrant: function(providerUri, opts) {
|
|
|
|
var promise;
|
|
|
|
|
|
|
|
if (opts.broker) {
|
|
|
|
promise = OAUTH3._discoverThenImplicitGrant(providerUri, opts);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
promise = OAUTH3._implicitGrant(providerUri, opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
return promise.then(function (tokens) {
|
|
|
|
return OAUTH3.hooks.refreshSession(
|
|
|
|
opts.session || {
|
|
|
|
provider_uri: providerUri
|
|
|
|
, client_id: opts.client_id
|
|
|
|
, client_uri: opts.client_uri || opts.clientUri
|
|
|
|
}
|
|
|
|
, tokens
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, _discoverThenImplicitGrant: function(providerUri, opts) {
|
|
|
|
opts.windowType = opts.windowType || 'popup';
|
|
|
|
return OAUTH3._discover(providerUri, opts).then(function (directives) {
|
|
|
|
return OAUTH3._implicitGrant(directives, opts).then(function (tokens) {
|
|
|
|
OAUTH3._browser.closeFrame(tokens.state || opts._state);
|
|
|
|
opts._state = undefined;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, _discover: function(providerUri, opts) {
|
|
|
|
providerUri = OAUTH3.utils.url.normalize(providerUri);
|
|
|
|
|
|
|
|
if (providerUri.match(OAUTH3._browser.window.location.hostname)) {
|
|
|
|
console.warn("It looks like you're a provider checking for your own directive,"
|
|
|
|
+ " so we we're just gonna use"
|
|
|
|
+ " OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })");
|
|
|
|
return OAUTH3.request({
|
|
|
|
method: 'GET'
|
|
|
|
, url: OAUTH3.utils.url.normalize(providerUri) + '/.well-known/oauth3/directives.json'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(opts.client_id || opts.client_uri).match(OAUTH3._browser.window.location.hostname)) {
|
|
|
|
console.warn("It looks like your client_id doesn't match your current window..."
|
|
|
|
+ " this probably won't end well");
|
|
|
|
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
var discReq = OAUTH3.urls.discover(
|
|
|
|
providerUri
|
|
|
|
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
|
|
|
|
, windowType: opts.broker && opts.windowType || 'background'
|
|
|
|
, broker: opts.broker
|
|
|
|
, debug: opts.debug
|
|
|
|
}
|
|
|
|
);
|
|
|
|
opts._state = discReq.state;
|
|
|
|
//var discReq = OAUTH3.urls.discover(providerUri, opts);
|
|
|
|
|
|
|
|
// hmm... we're gonna need a broker for this since switching windows is distracting,
|
|
|
|
// popups are obnoxious, iframes are sometimes blocked, and most servers don't implement CORS
|
|
|
|
// eventually it should be the browser (and postMessage may be a viable option now), but whatever...
|
|
|
|
|
|
|
|
// TODO allow postMessage from providerUri in addition to callback
|
|
|
|
// TODO allow node to open a desktop browser window
|
|
|
|
return OAUTH3._browser.frameRequest(
|
|
|
|
discReq.url
|
|
|
|
, discReq.state
|
|
|
|
, { windowType: opts.windowType
|
|
|
|
, reuseWindow: opts.broker && '-broker'
|
|
|
|
, debug: opts.debug
|
|
|
|
}
|
|
|
|
).then(function (params) {
|
|
|
|
// discWin.child.close()
|
|
|
|
// TODO params should have response_type indicating json, binary, etc
|
2017-02-14 17:37:00 +00:00
|
|
|
var directives = JSON.parse(OAUTH3.utils.atob(OAUTH3.utils._urlSafeBase64ToBase64(params.result || params.directives)));
|
2017-02-14 00:53:54 +00:00
|
|
|
return OAUTH3.hooks.directives.set(providerUri, directives);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, _implicitGrant: function(providerUri, opts) {
|
|
|
|
// TODO this may need to be synchronous for browser security policy
|
|
|
|
return OAUTH3.PromiseA.resolve(OAUTH3.hooks.directives.get(providerUri)).then(function (directives) {
|
|
|
|
// Do some stuff
|
|
|
|
var authReq = OAUTH3.urls.implicitGrant(
|
|
|
|
directives
|
|
|
|
, { redirect_uri: opts.redirect_uri
|
|
|
|
, client_id: opts.client_id || opts.client_uri
|
|
|
|
, client_uri: opts.client_uri || opts.client_id
|
|
|
|
, state: opts._state
|
|
|
|
, debug: opts.debug
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
if (opts.debug) {
|
|
|
|
window.alert("DEBUG MODE: Pausing so you can look at logs and whatnot :) Fire at will!");
|
|
|
|
}
|
|
|
|
|
|
|
|
return new OAUTH3.PromiseA(function (resolve, reject) {
|
|
|
|
return OAUTH3._browser.frameRequest(
|
|
|
|
authReq.url
|
|
|
|
, authReq.state // state should recycle params
|
|
|
|
, { windowType: opts.windowType
|
|
|
|
, reuseWindow: opts.broker && '-broker'
|
|
|
|
, debug: opts.debug
|
|
|
|
}
|
|
|
|
).then(function (tokens) {
|
|
|
|
if (tokens.error) {
|
|
|
|
return reject(OAUTH3.utils._formatError(tokens.error));
|
|
|
|
}
|
|
|
|
|
|
|
|
OAUTH3._browser.closeFrame(authReq.state, { debug: opts.debug || tokens.debug });
|
|
|
|
|
|
|
|
return tokens;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Let the Code Waste begin!!
|
|
|
|
//
|
2017-02-13 22:22:06 +00:00
|
|
|
, _browser: {
|
2017-02-14 00:53:54 +00:00
|
|
|
window: window
|
|
|
|
// TODO we don't need to include this if we're using jQuery or angular
|
|
|
|
, request: function (preq, _sys) {
|
|
|
|
return new OAUTH3.PromiseA(function (resolve, reject) {
|
|
|
|
var xhr;
|
|
|
|
try {
|
|
|
|
xhr = new XMLHttpRequest(_sys);
|
|
|
|
} catch(e) {
|
|
|
|
xhr = new XMLHttpRequest();
|
|
|
|
}
|
|
|
|
xhr.onreadystatechange = function () {
|
|
|
|
var data;
|
|
|
|
if (xhr.readyState !== XMLHttpRequest.DONE) {
|
|
|
|
// nothing to do here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xhr.status !== 200) {
|
|
|
|
reject(new Error('bad status code: ' + xhr.status));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
data = JSON.parse(xhr.responseText);
|
|
|
|
} catch(e) {
|
|
|
|
data = xhr.responseText;
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve({
|
|
|
|
request: xhr
|
|
|
|
, data: data
|
|
|
|
, status: xhr.status
|
|
|
|
});
|
|
|
|
};
|
|
|
|
xhr.open(preq.method, preq.url, true);
|
|
|
|
var headers = preq.headers || {};
|
|
|
|
Object.keys(headers).forEach(function (key) {
|
|
|
|
xhr.setRequestHeader(key, headers[key]);
|
|
|
|
});
|
|
|
|
xhr.send();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, discover: function (providerUri, opts) {
|
2017-02-13 22:22:06 +00:00
|
|
|
opts = opts || {};
|
|
|
|
//opts.debug = true;
|
|
|
|
providerUri = OAUTH3.utils.url.normalize(providerUri);
|
2017-02-14 00:53:54 +00:00
|
|
|
if (providerUri.match(OAUTH3._browser.window.location.hostname)) {
|
2017-02-13 22:22:06 +00:00
|
|
|
console.warn("It looks like you're a provider checking for your own directive,"
|
|
|
|
+ " so we we're just gonna use OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })");
|
|
|
|
return OAUTH3.request({
|
|
|
|
method: 'GET'
|
|
|
|
, url: OAUTH3.utils.url.normalize(providerUri) + '/.well-known/oauth3/directives.json'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-02-14 00:53:54 +00:00
|
|
|
if (!(opts.client_id || opts.client_uri).match(OAUTH3._browser.window.location.hostname)) {
|
2017-02-13 22:22:06 +00:00
|
|
|
console.warn("It looks like your client_id doesn't match your current window... this probably won't end well");
|
2017-02-14 00:53:54 +00:00
|
|
|
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
|
2017-02-13 22:22:06 +00:00
|
|
|
}
|
|
|
|
var discObj = OAUTH3.urls.discover(
|
|
|
|
providerUri
|
2017-02-14 00:53:54 +00:00
|
|
|
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location)), debug: opts.debug }
|
2017-02-13 22:22:06 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// TODO ability to reuse iframe instead of closing
|
2017-02-14 17:37:00 +00:00
|
|
|
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;
|
2017-02-14 00:53:54 +00:00
|
|
|
OAUTH3._browser.closeFrame(discObj.state, { debug: opts.debug || params.debug });
|
2017-02-13 22:22:06 +00:00
|
|
|
if (params.error) {
|
|
|
|
return OAUTH3.utils._formatError(providerUri, params.error);
|
|
|
|
}
|
2017-02-14 00:53:54 +00:00
|
|
|
var directives = JSON.parse(OAUTH3.utils.atob(OAUTH3.utils._urlSafeBase64ToBase64(params.result || params.directives)));
|
2017-02-13 22:22:06 +00:00
|
|
|
return directives;
|
|
|
|
}, function (err) {
|
2017-02-14 00:53:54 +00:00
|
|
|
OAUTH3._browser.closeFrame(discObj.state, { debug: opts.debug || err.debug });
|
2017-02-13 22:22:06 +00:00
|
|
|
return OAUTH3.PromiseA.reject(err);
|
|
|
|
});
|
|
|
|
}
|
2017-02-14 00:53:54 +00:00
|
|
|
, frameRequest: function (url, state, opts) {
|
2017-02-14 17:37:00 +00:00
|
|
|
opts = opts || {};
|
2017-02-14 00:53:54 +00:00
|
|
|
var previousFrame = OAUTH3._browser._frames[state];
|
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
var windowType = opts.windowType;
|
|
|
|
if (!windowType) {
|
|
|
|
windowType = 'popup';
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
var timeout = opts.timeout;
|
2017-02-14 00:53:54 +00:00
|
|
|
if (opts.debug) {
|
2017-02-14 17:37:00 +00:00
|
|
|
timeout = timeout || 3 * 60 * 1000;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
timeout = timeout || ('background' === windowType ? 15 * 1000 : 3 * 60 * 1000);
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new OAUTH3.PromiseA(function (resolve, reject) {
|
2017-02-14 17:37:00 +00:00
|
|
|
// TODO periodically garbage collect expired handlers from window object
|
2017-02-14 00:53:54 +00:00
|
|
|
var tok;
|
|
|
|
|
|
|
|
function cleanup() {
|
|
|
|
delete window['--oauth3-callback-' + state];
|
|
|
|
clearTimeout(tok);
|
|
|
|
tok = null;
|
2017-02-14 17:37:00 +00:00
|
|
|
// 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)
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
|
|
|
|
console.log('[oauth3.implicit.js] callbackName', '--oauth3-callback-' + state);
|
2017-02-14 00:53:54 +00:00
|
|
|
window['--oauth3-callback-' + state] = function (params) {
|
|
|
|
resolve(params);
|
|
|
|
cleanup();
|
|
|
|
};
|
|
|
|
|
|
|
|
tok = setTimeout(function () {
|
2017-02-14 17:37:00 +00:00
|
|
|
var err = new Error(
|
|
|
|
"the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s"
|
|
|
|
);
|
2017-02-14 00:53:54 +00:00
|
|
|
err.code = "E_TIMEOUT";
|
|
|
|
reject(err);
|
|
|
|
cleanup();
|
2017-02-14 17:37:00 +00:00
|
|
|
}, timeout);
|
2017-02-14 00:53:54 +00:00
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
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) {
|
2017-02-14 00:53:54 +00:00
|
|
|
if (previousFrame) {
|
|
|
|
previousFrame.location = url;
|
|
|
|
//promise = previousFrame.promise;
|
|
|
|
}
|
|
|
|
else {
|
2017-02-14 17:37:00 +00:00
|
|
|
OAUTH3._browser._frames[state] = OAUTH3._browser.iframe(url, state, opts);
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
2017-02-14 17:37:00 +00:00
|
|
|
} else if ('popup' === windowType) {
|
2017-02-14 00:53:54 +00:00
|
|
|
if (previousFrame) {
|
|
|
|
previousFrame.location = url;
|
|
|
|
if (opts.debug) {
|
|
|
|
previousFrame.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2017-02-14 17:37:00 +00:00
|
|
|
OAUTH3._browser._frames[state] = OAUTH3._browser.frame(url, state, opts);
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
2017-02-14 17:37:00 +00:00
|
|
|
} else if ('inline' === windowType) {
|
2017-02-14 00:53:54 +00:00
|
|
|
// 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;
|
|
|
|
OAUTH3._browser.window.location = url;
|
|
|
|
//promise = OAUTH3.PromiseA.resolve({ url: url });
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
throw new Error("login framing method options.windowType="
|
|
|
|
+ opts.windowType + " not type yet implemented");
|
|
|
|
}
|
|
|
|
|
|
|
|
}).then(function (params) {
|
|
|
|
var err;
|
|
|
|
|
|
|
|
if (params.error || params.error_description) {
|
|
|
|
err = new Error(params.error_description || "Unknown response error");
|
|
|
|
err.code = params.error || "E_UKNOWN_ERROR";
|
|
|
|
err.params = params;
|
|
|
|
//_formatError
|
|
|
|
return OAUTH3.PromiseA.reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return params;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, closeFrame: function (state, opts) {
|
|
|
|
function close() {
|
|
|
|
try {
|
|
|
|
OAUTH3._browser._frames[state].close();
|
|
|
|
} catch(e) {
|
|
|
|
try {
|
|
|
|
OAUTH3._browser._frames[state].remove();
|
|
|
|
} catch(e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete OAUTH3._browser._frames[state];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.debug) {
|
|
|
|
if (window.confirm("DEBUG MODE: okay to close oauth3 window?")) {
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
, _frames: {}
|
2017-02-14 17:37:00 +00:00
|
|
|
, iframe: function (url, state, opts) {
|
|
|
|
var framesrc = '<iframe class="js-oauth3-iframe" src="' + url + '" ';
|
|
|
|
if (opts.debug) {
|
|
|
|
framesrc += ' width="' + (opts.height || 600) + 'px"'
|
|
|
|
+ ' height="' + (opts.width || 720) + 'px"'
|
|
|
|
+ ' style="opacity: 0.8;" frameborder="1"';
|
2017-02-14 00:53:54 +00:00
|
|
|
}
|
2017-02-14 17:37:00 +00:00
|
|
|
else {
|
|
|
|
framesrc += ' width="1px" height="1px" frameborder="0"';
|
|
|
|
}
|
|
|
|
framesrc += '></iframe>';
|
2017-02-13 22:22:06 +00:00
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
var frame = OAUTH3._browser.window.document.createElement('div');
|
|
|
|
frame.innerHTML = framesrc;
|
|
|
|
OAUTH3._browser.window.document.body.appendChild(frame);
|
2017-02-13 22:22:06 +00:00
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
return frame;
|
|
|
|
}
|
|
|
|
, frame: function (url, state, opts) {
|
2017-02-13 22:22:06 +00:00
|
|
|
|
2017-02-14 17:37:00 +00:00
|
|
|
// TODO allow size changes (via directive even)
|
|
|
|
return window.open(
|
|
|
|
url
|
|
|
|
, 'oauth3-login-' + (opts.reuseWindow || state)
|
|
|
|
, 'height=' + (opts.height || 720) + ',width=' + (opts.width || 620)
|
|
|
|
);
|
2017-02-13 22:22:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if ('undefined' !== typeof Promise) {
|
|
|
|
OAUTH3.PromiseA = Promise;
|
|
|
|
}
|
|
|
|
|
|
|
|
}('undefined' !== typeof exports ? exports : window));
|