forked from coolaj86/walnut.js
		
	
		
			
	
	
		
			739 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			739 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								(function (exports) {
							 | 
						||
| 
								 | 
							
								  'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var oauth3 = {};
							 | 
						||
| 
								 | 
							
								  var logins = {};
							 | 
						||
| 
								 | 
							
								  oauth3.requests = logins;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ('undefined' !== typeof Promise) {
							 | 
						||
| 
								 | 
							
								    oauth3.PromiseA = Promise;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    console.warn("[oauth3.js] Remember to call oauth3.providePromise(Promise) with a proper Promise implementation");
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // TODO move to a test / lint suite?
							 | 
						||
| 
								 | 
							
								  oauth3._testPromise = function (PromiseA) {
							 | 
						||
| 
								 | 
							
								    var promise;
							 | 
						||
| 
								 | 
							
								    var x = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // tests that this promise has all of the necessary api
							 | 
						||
| 
								 | 
							
								    promise = new PromiseA(function (resolve, reject) {
							 | 
						||
| 
								 | 
							
								      if (x === 1) {
							 | 
						||
| 
								 | 
							
								        throw new Error("bad promise, create not asynchronous");
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      PromiseA.resolve().then(function () {
							 | 
						||
| 
								 | 
							
								        var promise2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (x === 1 || x === 2) {
							 | 
						||
| 
								 | 
							
								          throw new Error("bad promise, resolve not asynchronous");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        promise2 = PromiseA.reject().then(reject, function () {
							 | 
						||
| 
								 | 
							
								          if (x === 1 || x === 2 || x === 3) {
							 | 
						||
| 
								 | 
							
								            throw new Error("bad promise, reject not asynchronous");
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          if ('undefined' === typeof angular) {
							 | 
						||
| 
								 | 
							
								            throw new Error("[NOT AN ERROR] Dear angular users: ignore this error-handling test");
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            return PromiseA.reject(new Error("[NOT AN ERROR] ignore this error-handling test"));
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        x = 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return promise2;
							 | 
						||
| 
								 | 
							
								      }).catch(function (e) {
							 | 
						||
| 
								 | 
							
								        if (e.message.match('NOT AN ERROR')) {
							 | 
						||
| 
								 | 
							
								          resolve({ success: true });
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          reject(e);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      x = 3;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    x = 2;
							 | 
						||
| 
								 | 
							
								    return promise;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.providePromise = function (PromiseA) {
							 | 
						||
| 
								 | 
							
								    oauth3.PromiseA = PromiseA;
							 | 
						||
| 
								 | 
							
								    return oauth3._testPromise(PromiseA).then(function () {
							 | 
						||
| 
								 | 
							
								      oauth3.PromiseA = PromiseA;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.provideRequest = function (request, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    var Recase = exports.Recase || require('recase');
							 | 
						||
| 
								 | 
							
								    // TODO make insensitive to providing exceptions
							 | 
						||
| 
								 | 
							
								    var recase = Recase.create({ exceptions: {} });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (opts.rawCase) {
							 | 
						||
| 
								 | 
							
								      oauth3.request = request;
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Wrap oauth3 api calls in snake_case / camelCase conversion
							 | 
						||
| 
								 | 
							
								    oauth3.request = function (req, opts) {
							 | 
						||
| 
								 | 
							
								      //console.log('[D] [oauth3 req.url]', req.url);
							 | 
						||
| 
								 | 
							
								      opts = opts || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (opts.rawCase) {
							 | 
						||
| 
								 | 
							
								        return request(req);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // convert JavaScript camelCase to oauth3 snake_case
							 | 
						||
| 
								 | 
							
								      if (req.data && 'object' === typeof req.data) {
							 | 
						||
| 
								 | 
							
								        req.originalData = req.data;
							 | 
						||
| 
								 | 
							
								        req.data = recase.snakeCopy(req.data);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      //console.log('[F] [oauth3 req.url]', req.url);
							 | 
						||
| 
								 | 
							
								      return request(req).then(function (resp) {
							 | 
						||
| 
								 | 
							
								        // convert oauth3 snake_case to JavaScript camelCase
							 | 
						||
| 
								 | 
							
								        if (resp.data && 'object' === typeof resp.data) {
							 | 
						||
| 
								 | 
							
								          resp.originalData = resp.data;
							 | 
						||
| 
								 | 
							
								          resp.data = recase.camelCopy(resp.data);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return resp;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*
							 | 
						||
| 
								 | 
							
								    return oauth3._testRequest(request).then(function () {
							 | 
						||
| 
								 | 
							
								      oauth3.request = request;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  logins.authorizationRedirect = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    // TODO get own directives
							 | 
						||
| 
								 | 
							
								    return oauth3.authorizationRedirect(
							 | 
						||
| 
								 | 
							
								      providerUri
							 | 
						||
| 
								 | 
							
								    , opts.authorizationRedirect
							 | 
						||
| 
								 | 
							
								    , opts
							 | 
						||
| 
								 | 
							
								    ).then(function (prequest) {
							 | 
						||
| 
								 | 
							
								      if (!prequest.state) {
							 | 
						||
| 
								 | 
							
								        throw new Error("[Devolper Error] [authorization redirect] prequest.state is empty");
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return oauth3.frameRequest(prequest.url, prequest.state, opts);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  logins.implicitGrant = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    // TODO OAuth3 provider should use the redirect URI as the appId?
							 | 
						||
| 
								 | 
							
								    return oauth3.implicitGrant(
							 | 
						||
| 
								 | 
							
								      providerUri
							 | 
						||
| 
								 | 
							
								      // TODO OAuth3 provider should referer / origin as the appId?
							 | 
						||
| 
								 | 
							
								    , opts
							 | 
						||
| 
								 | 
							
								    ).then(function (prequest) {
							 | 
						||
| 
								 | 
							
								      // console.log('[debug] prequest', prequest);
							 | 
						||
| 
								 | 
							
								      if (!prequest.state) {
							 | 
						||
| 
								 | 
							
								        throw new Error("[Devolper Error] [implicit grant] prequest.state is empty");
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return oauth3.frameRequest(prequest.url, prequest.state, opts);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  logins.resourceOwnerPassword = function (providerUri, username, passphrase, opts) {
							 | 
						||
| 
								 | 
							
								    console.log('DEBUG logins.resourceOwnerPassword opts', opts);
							 | 
						||
| 
								 | 
							
								    //var scope = opts.scope;
							 | 
						||
| 
								 | 
							
								    //var appId = opts.appId;
							 | 
						||
| 
								 | 
							
								    return oauth3.resourceOwnerPassword(
							 | 
						||
| 
								 | 
							
								      providerUri
							 | 
						||
| 
								 | 
							
								    , username
							 | 
						||
| 
								 | 
							
								    , passphrase
							 | 
						||
| 
								 | 
							
								    , opts
							 | 
						||
| 
								 | 
							
								    //, scope
							 | 
						||
| 
								 | 
							
								    //, appId
							 | 
						||
| 
								 | 
							
								    ).then(function (request) {
							 | 
						||
| 
								 | 
							
								      console.log('DEBUG oauth3.resourceOwnerPassword', request);
							 | 
						||
| 
								 | 
							
								      return oauth3.request({
							 | 
						||
| 
								 | 
							
								        url: request.url
							 | 
						||
| 
								 | 
							
								      , method: request.method
							 | 
						||
| 
								 | 
							
								      , data: request.data
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.frameRequest = function (url, state, opts) {
							 | 
						||
| 
								 | 
							
								    var promise;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ('background' === opts.type) {
							 | 
						||
| 
								 | 
							
								      promise = oauth3.insertIframe(url, state, opts);
							 | 
						||
| 
								 | 
							
								    } else if ('popup' === opts.type) {
							 | 
						||
| 
								 | 
							
								      promise = oauth3.openWindow(url, state, opts);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      throw new Error("login framing method not specified or not type yet implemented");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return promise.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;
							 | 
						||
| 
								 | 
							
								        return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return params;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.login = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    console.log('##### DEBUG oauth3.login providerUri, opts');
							 | 
						||
| 
								 | 
							
								    console.log(providerUri);
							 | 
						||
| 
								 | 
							
								    console.log(opts);
							 | 
						||
| 
								 | 
							
								    // Four styles of login:
							 | 
						||
| 
								 | 
							
								    //   * background (hidden iframe)
							 | 
						||
| 
								 | 
							
								    //   * iframe (visible iframe, needs border color and width x height params)
							 | 
						||
| 
								 | 
							
								    //   * popup (needs width x height and positioning? params)
							 | 
						||
| 
								 | 
							
								    //   * window (params?)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Two strategies
							 | 
						||
| 
								 | 
							
								    //  * authorization_redirect (to server authorization code)
							 | 
						||
| 
								 | 
							
								    //  * implicit_grant (default, browser-only)
							 | 
						||
| 
								 | 
							
								    // If both are selected, implicit happens first and then the other happens in background
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var promise;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (opts.username || opts.password) {
							 | 
						||
| 
								 | 
							
								      /* jshint ignore:start */
							 | 
						||
| 
								 | 
							
								      // ingore "confusing use of !"
							 | 
						||
| 
								 | 
							
								      if (!opts.username !== !opts.password) {
							 | 
						||
| 
								 | 
							
								        throw new Error("you did not specify both username and password");
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      /* jshint ignore:end */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var username = opts.username;
							 | 
						||
| 
								 | 
							
								      var password = opts.password;
							 | 
						||
| 
								 | 
							
								      delete opts.username;
							 | 
						||
| 
								 | 
							
								      delete opts.password;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return logins.resourceOwnerPassword(providerUri, username, password, opts).then(function (resp) {
							 | 
						||
| 
								 | 
							
								        if (!resp || !resp.data) {
							 | 
						||
| 
								 | 
							
								          var err = new Error("bad response");
							 | 
						||
| 
								 | 
							
								          err.response = resp;
							 | 
						||
| 
								 | 
							
								          err.data = resp && resp.data || undefined;
							 | 
						||
| 
								 | 
							
								          return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return resp.data;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TODO support dual-strategy login
							 | 
						||
| 
								 | 
							
								    // by default, always get implicitGrant (for client)
							 | 
						||
| 
								 | 
							
								    // and optionally do authorizationCode (for server session)
							 | 
						||
| 
								 | 
							
								    if ('background' === opts.type || opts.background) {
							 | 
						||
| 
								 | 
							
								      opts.type = 'background';
							 | 
						||
| 
								 | 
							
								      opts.background = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      opts.type = 'popup';
							 | 
						||
| 
								 | 
							
								      opts.popup = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (opts.authorizationRedirect) {
							 | 
						||
| 
								 | 
							
								      promise = logins.authorizationRedirect(providerUri, opts);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      promise = logins.implicitGrant(providerUri, opts);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return promise;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.backgroundLogin = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    opts.type = 'background';
							 | 
						||
| 
								 | 
							
								    return oauth3.login(providerUri, opts);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.insertIframe = function (url, state, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    var promise = new oauth3.PromiseA(function (resolve, reject) {
							 | 
						||
| 
								 | 
							
								      var tok;
							 | 
						||
| 
								 | 
							
								      var $iframe;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      function cleanup() {
							 | 
						||
| 
								 | 
							
								        delete window['__oauth3_' + state];
							 | 
						||
| 
								 | 
							
								        $iframe.remove();
							 | 
						||
| 
								 | 
							
								        clearTimeout(tok);
							 | 
						||
| 
								 | 
							
								        tok = null;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      window['__oauth3_' + state] = function (params) {
							 | 
						||
| 
								 | 
							
								        //console.info('[iframe] complete', params);
							 | 
						||
| 
								 | 
							
								        resolve(params);
							 | 
						||
| 
								 | 
							
								        cleanup();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      tok = setTimeout(function () {
							 | 
						||
| 
								 | 
							
								        var err = new Error("the iframe request did not complete within 15 seconds");
							 | 
						||
| 
								 | 
							
								        err.code = "E_TIMEOUT";
							 | 
						||
| 
								 | 
							
								        reject(err);
							 | 
						||
| 
								 | 
							
								        cleanup();
							 | 
						||
| 
								 | 
							
								      }, opts.timeout || 15000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // TODO hidden / non-hidden (via directive even)
							 | 
						||
| 
								 | 
							
								      $iframe = $(
							 | 
						||
| 
								 | 
							
								        '<iframe src="' + url
							 | 
						||
| 
								 | 
							
								      //+ '" width="800px" height="800px" style="opacity: 0.8;" frameborder="1"></iframe>'
							 | 
						||
| 
								 | 
							
								      + '" width="1px" height="1px" frameborder="0"></iframe>'
							 | 
						||
| 
								 | 
							
								      );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      $('body').append($iframe);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TODO periodically garbage collect expired handlers from window object
							 | 
						||
| 
								 | 
							
								    return promise;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.openWindow = function (url, state, opts) {
							 | 
						||
| 
								 | 
							
								    var promise = new oauth3.PromiseA(function (resolve, reject) {
							 | 
						||
| 
								 | 
							
								      var winref;
							 | 
						||
| 
								 | 
							
								      var tok;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      function cleanup() {
							 | 
						||
| 
								 | 
							
								        delete window['__oauth3_' + state];
							 | 
						||
| 
								 | 
							
								        clearTimeout(tok);
							 | 
						||
| 
								 | 
							
								        tok = null;
							 | 
						||
| 
								 | 
							
								        // this is last in case the window self-closes synchronously
							 | 
						||
| 
								 | 
							
								        // (should never happen, but that's a negotiable implementation detail)
							 | 
						||
| 
								 | 
							
								        //winref.close();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      window['__oauth3_' + state] = function (params) {
							 | 
						||
| 
								 | 
							
								        //console.info('[popup] (or window) complete', params);
							 | 
						||
| 
								 | 
							
								        resolve(params);
							 | 
						||
| 
								 | 
							
								        cleanup();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      tok = setTimeout(function () {
							 | 
						||
| 
								 | 
							
								        var err = new Error("the windowed request did not complete within 3 minutes");
							 | 
						||
| 
								 | 
							
								        err.code = "E_TIMEOUT";
							 | 
						||
| 
								 | 
							
								        reject(err);
							 | 
						||
| 
								 | 
							
								        cleanup();
							 | 
						||
| 
								 | 
							
								      }, opts.timeout || 3 * 60 * 1000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // TODO allow size changes (via directive even)
							 | 
						||
| 
								 | 
							
								      winref = window.open(url, 'oauth3-login-' + state, 'height=720,width=620');
							 | 
						||
| 
								 | 
							
								      if (!winref) {
							 | 
						||
| 
								 | 
							
								        reject("TODO: open the iframe first and discover oauth3 directives before popup");
							 | 
						||
| 
								 | 
							
								        cleanup();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TODO periodically garbage collect expired handlers from window object
							 | 
						||
| 
								 | 
							
								    return promise;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.logout = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Oauth3.init({ logout: function () {} });
							 | 
						||
| 
								 | 
							
								    //return Oauth3.logout();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var state = parseInt(Math.random().toString().replace('0.', ''), 10).toString('36');
							 | 
						||
| 
								 | 
							
								    var url = providerUri.replace(/\/$/, '') + (opts.providerOauth3Html || '/oauth3.html');
							 | 
						||
| 
								 | 
							
								    var redirectUri = opts.redirectUri
							 | 
						||
| 
								 | 
							
								      || (window.location.protocol + '//' + (window.location.host + window.location.pathname) + 'oauth3.html')
							 | 
						||
| 
								 | 
							
								      ;
							 | 
						||
| 
								 | 
							
								    var params = {
							 | 
						||
| 
								 | 
							
								      // logout=true for all logins/accounts
							 | 
						||
| 
								 | 
							
								      // logout=app-scoped-login-id for a single login
							 | 
						||
| 
								 | 
							
								      action: 'logout'
							 | 
						||
| 
								 | 
							
								      // TODO specify specific accounts / logins to delete from session
							 | 
						||
| 
								 | 
							
								    , accounts: true
							 | 
						||
| 
								 | 
							
								    , logins: true
							 | 
						||
| 
								 | 
							
								    , redirect_uri: redirectUri
							 | 
						||
| 
								 | 
							
								    , state: state
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //console.log('DEBUG oauth3.logout NIX insertIframe');
							 | 
						||
| 
								 | 
							
								    //console.log(url, params.redirect_uri);
							 | 
						||
| 
								 | 
							
								    //console.log(state);
							 | 
						||
| 
								 | 
							
								    //console.log(params); // redirect_uri
							 | 
						||
| 
								 | 
							
								    //console.log(opts);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (url === params.redirect_uri) {
							 | 
						||
| 
								 | 
							
								      return oauth3.PromiseA.resolve();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    url += '#' + oauth3.querystringify(params);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return oauth3.insertIframe(url, state, opts);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.stringifyscope = function (scope) {
							 | 
						||
| 
								 | 
							
								    if (Array.isArray(scope)) {
							 | 
						||
| 
								 | 
							
								      scope = scope.join(' ');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return scope;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.querystringify = function (params) {
							 | 
						||
| 
								 | 
							
								    var qs = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Object.keys(params).forEach(function (key) {
							 | 
						||
| 
								 | 
							
								      if ('scope' === key) {
							 | 
						||
| 
								 | 
							
								        params[key] = oauth3.stringifyscope(params[key]);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return qs.join('&');
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.createState = function () {
							 | 
						||
| 
								 | 
							
								    // TODO mo' betta' random function
							 | 
						||
| 
								 | 
							
								    // maybe gather some entropy from mouse / keyboard events?
							 | 
						||
| 
								 | 
							
								    // (probably not, just use webCrypto or be sucky)
							 | 
						||
| 
								 | 
							
								    return parseInt(Math.random().toString().replace('0.', ''), 10).toString('36');
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.normalizeProviderUri = function (providerUri) {
							 | 
						||
| 
								 | 
							
								    // tested with
							 | 
						||
| 
								 | 
							
								    //   example.com
							 | 
						||
| 
								 | 
							
								    //   example.com/
							 | 
						||
| 
								 | 
							
								    //   http://example.com
							 | 
						||
| 
								 | 
							
								    //   https://example.com/
							 | 
						||
| 
								 | 
							
								    providerUri = providerUri
							 | 
						||
| 
								 | 
							
								      .replace(/^(https?:\/\/)?/, 'https://')
							 | 
						||
| 
								 | 
							
								      .replace(/\/?$/, '')
							 | 
						||
| 
								 | 
							
								      ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return providerUri;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3._discoverHelper = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    var state = oauth3.createState();
							 | 
						||
| 
								 | 
							
								    var params;
							 | 
						||
| 
								 | 
							
								    var url;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    params = {
							 | 
						||
| 
								 | 
							
								      action: 'directives'
							 | 
						||
| 
								 | 
							
								    , state: state
							 | 
						||
| 
								 | 
							
								      // TODO this should be configurable (i.e. I want a dev vs production oauth3.html)
							 | 
						||
| 
								 | 
							
								    , redirect_uri: window.location.protocol + '//' + window.location.host
							 | 
						||
| 
								 | 
							
								        + window.location.pathname + 'oauth3.html'
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    url = providerUri + '/oauth3.html#' + oauth3.querystringify(params);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return oauth3.insertIframe(url, state, opts).then(function (directives) {
							 | 
						||
| 
								 | 
							
								      return directives;
							 | 
						||
| 
								 | 
							
								    }, function (err) {
							 | 
						||
| 
								 | 
							
								      return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.discover = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    console.log('DEBUG oauth3.discover', providerUri);
							 | 
						||
| 
								 | 
							
								    console.log(opts);
							 | 
						||
| 
								 | 
							
								    if (opts.directives) {
							 | 
						||
| 
								 | 
							
								      return oauth3.PromiseA.resolve(opts.directives);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var promise;
							 | 
						||
| 
								 | 
							
								    var promise2;
							 | 
						||
| 
								 | 
							
								    var directives;
							 | 
						||
| 
								 | 
							
								    var updatedAt;
							 | 
						||
| 
								 | 
							
								    var fresh;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    providerUri = oauth3.normalizeProviderUri(providerUri);
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      directives = JSON.parse(localStorage.getItem('oauth3.' + providerUri + '.directives'));
							 | 
						||
| 
								 | 
							
								      console.log('DEBUG oauth3.discover cache', directives);
							 | 
						||
| 
								 | 
							
								      updatedAt = localStorage.getItem('oauth3.' + providerUri + '.directives.updated_at');
							 | 
						||
| 
								 | 
							
								      console.log('DEBUG oauth3.discover updatedAt', updatedAt);
							 | 
						||
| 
								 | 
							
								      updatedAt = new Date(updatedAt).valueOf();
							 | 
						||
| 
								 | 
							
								      console.log('DEBUG oauth3.discover updatedAt', updatedAt);
							 | 
						||
| 
								 | 
							
								    } catch(e) {
							 | 
						||
| 
								 | 
							
								      // ignore
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fresh = (Date.now() - updatedAt) < (24 * 60 * 60 * 1000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (directives) {
							 | 
						||
| 
								 | 
							
								      promise = oauth3.PromiseA.resolve(directives);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (fresh) {
							 | 
						||
| 
								 | 
							
								        //console.log('[local] [fresh directives]', directives);
							 | 
						||
| 
								 | 
							
								        return promise;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    promise2 = oauth3._discoverHelper(providerUri, opts).then(function (params) {
							 | 
						||
| 
								 | 
							
								      console.log('DEBUG oauth3._discoverHelper', params);
							 | 
						||
| 
								 | 
							
								      var err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (!params.directives) {
							 | 
						||
| 
								 | 
							
								        err = new Error(params.error_description || "Unknown error when discoving provider '" + providerUri + "'");
							 | 
						||
| 
								 | 
							
								        err.code = params.error || "E_UNKNOWN_ERROR";
							 | 
						||
| 
								 | 
							
								        return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      try {
							 | 
						||
| 
								 | 
							
								        directives = JSON.parse(atob(params.directives));
							 | 
						||
| 
								 | 
							
								        console.log('DEBUG oauth3._discoverHelper directives', directives);
							 | 
						||
| 
								 | 
							
								      } catch(e) {
							 | 
						||
| 
								 | 
							
								        err = new Error(params.error_description || "could not parse directives for provider '" + providerUri + "'");
							 | 
						||
| 
								 | 
							
								        err.code = params.error || "E_PARSE_DIRECTIVE";
							 | 
						||
| 
								 | 
							
								        return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (
							 | 
						||
| 
								 | 
							
								          (directives.authorization_dialog && directives.authorization_dialog.url)
							 | 
						||
| 
								 | 
							
								        || (directives.access_token && directives.access_token.url)
							 | 
						||
| 
								 | 
							
								      ) {
							 | 
						||
| 
								 | 
							
								        // TODO lint directives
							 | 
						||
| 
								 | 
							
								        localStorage.setItem('oauth3.' + providerUri + '.directives', JSON.stringify(directives));
							 | 
						||
| 
								 | 
							
								        localStorage.setItem('oauth3.' + providerUri + '.directives.updated_at', new Date().toISOString());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return oauth3.PromiseA.resolve(directives);
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        // ignore
							 | 
						||
| 
								 | 
							
								        console.error("the directives provided by '" + providerUri + "' were invalid.");
							 | 
						||
| 
								 | 
							
								        params.error = params.error || "E_INVALID_DIRECTIVE";
							 | 
						||
| 
								 | 
							
								        params.error_description = params.error_description
							 | 
						||
| 
								 | 
							
								          || "directives did not include authorization_dialog.url";
							 | 
						||
| 
								 | 
							
								        err = new Error(params.error_description || "Unknown error when discoving provider '" + providerUri + "'");
							 | 
						||
| 
								 | 
							
								        err.code = params.error;
							 | 
						||
| 
								 | 
							
								        return oauth3.PromiseA.reject(err);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return promise || promise2;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.authorizationRedirect = function (providerUri, authorizationRedirect, opts) {
							 | 
						||
| 
								 | 
							
								    //console.log('[authorizationRedirect]');
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Example Authorization Redirect - from Browser to Consumer API
							 | 
						||
| 
								 | 
							
								    // (for generating a session securely on your own server)
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // i.e. GET https://<<CONSUMER>>.com/api/org.oauth3.consumer/authorization_redirect/<<PROVIDER>>.com
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // GET https://myapp.com/api/org.oauth3.consumer/authorization_redirect/`encodeURIComponent('example.com')`
							 | 
						||
| 
								 | 
							
								    //  &scope=`encodeURIComponent('profile.login profile.email')`
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // (optional)
							 | 
						||
| 
								 | 
							
								    //  &state=`Math.random()`
							 | 
						||
| 
								 | 
							
								    //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // NOTE: This is not a request sent to the provider, but rather a request sent to the
							 | 
						||
| 
								 | 
							
								    // consumer (your own API) which then sets some state and redirects.
							 | 
						||
| 
								 | 
							
								    // This will initiate the `authorization_code` request on your server
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return oauth3.discover(providerUri, opts).then(function (directive) {
							 | 
						||
| 
								 | 
							
								      if (!directive) {
							 | 
						||
| 
								 | 
							
								        throw new Error("Developer Error: directive should exist when discovery is successful");
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var scope = opts.scope || directive.authn_scope;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var state = Math.random().toString().replace(/^0\./, '');
							 | 
						||
| 
								 | 
							
								      var params = {};
							 | 
						||
| 
								 | 
							
								      var slimProviderUri = encodeURIComponent(providerUri.replace(/^(https?|spdy):\/\//, ''));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      params.state = state;
							 | 
						||
| 
								 | 
							
								      if (scope) {
							 | 
						||
| 
								 | 
							
								        params.scope = scope;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (opts.redirectUri) {
							 | 
						||
| 
								 | 
							
								        // this is really only for debugging
							 | 
						||
| 
								 | 
							
								        params.redirect_uri = opts.redirectUri;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      // Note: the type check is necessary because we allow 'true'
							 | 
						||
| 
								 | 
							
								      // as an automatic mechanism when it isn't necessary to specify
							 | 
						||
| 
								 | 
							
								      if ('string' !== typeof authorizationRedirect) {
							 | 
						||
| 
								 | 
							
								        // TODO oauth3.json for self?
							 | 
						||
| 
								 | 
							
								        authorizationRedirect = 'https://' + window.location.host
							 | 
						||
| 
								 | 
							
								          + '/api/org.oauth3.consumer/authorization_redirect/:provider_uri';
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      authorizationRedirect = authorizationRedirect
							 | 
						||
| 
								 | 
							
								        .replace(/!(provider_uri)/, slimProviderUri)
							 | 
						||
| 
								 | 
							
								        .replace(/:provider_uri/, slimProviderUri)
							 | 
						||
| 
								 | 
							
								        .replace(/#{provider_uri}/, slimProviderUri)
							 | 
						||
| 
								 | 
							
								        .replace(/{{provider_uri}}/, slimProviderUri)
							 | 
						||
| 
								 | 
							
								        ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return oauth3.PromiseA.resolve({
							 | 
						||
| 
								 | 
							
								        url: authorizationRedirect + '?' + oauth3.querystringify(params)
							 | 
						||
| 
								 | 
							
								      , method: 'GET'
							 | 
						||
| 
								 | 
							
								      , state: state    // this becomes browser_state
							 | 
						||
| 
								 | 
							
								      , params: params  // includes scope, final redirect_uri?
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.authorizationCode = function (/*providerUri, scope, redirectUri, clientId*/) {
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Example Authorization Code Request
							 | 
						||
| 
								 | 
							
								    // (not for use in the browser)
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // GET https://example.com/api/org.oauth3.provider/authorization_dialog
							 | 
						||
| 
								 | 
							
								    //  ?response_type=code
							 | 
						||
| 
								 | 
							
								    //  &scope=`encodeURIComponent('profile.login profile.email')`
							 | 
						||
| 
								 | 
							
								    //  &state=`Math.random()`
							 | 
						||
| 
								 | 
							
								    //  &client_id=xxxxxxxxxxx
							 | 
						||
| 
								 | 
							
								    //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // NOTE: `redirect_uri` itself may also contain URI-encoded components
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // NOTE: This probably shouldn't be done in the browser because the server
							 | 
						||
| 
								 | 
							
								    //   needs to initiate the state. If it is done in a browser, the browser
							 | 
						||
| 
								 | 
							
								    //   should probably request 'state' from the server beforehand
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    throw new Error("not implemented");
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.implicitGrant = function (providerUri, opts) {
							 | 
						||
| 
								 | 
							
								    //console.log('[implicitGrant]');
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Example Implicit Grant Request
							 | 
						||
| 
								 | 
							
								    // (for generating a browser-only session, not a session on your server)
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // GET https://example.com/api/org.oauth3.provider/authorization_dialog
							 | 
						||
| 
								 | 
							
								    //  ?response_type=token
							 | 
						||
| 
								 | 
							
								    //  &scope=`encodeURIComponent('profile.login profile.email')`
							 | 
						||
| 
								 | 
							
								    //  &state=`Math.random()`
							 | 
						||
| 
								 | 
							
								    //  &client_id=xxxxxxxxxxx
							 | 
						||
| 
								 | 
							
								    //  &redirect_uri=`encodeURIComponent('https://myapp.com/oauth3.html')`
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // NOTE: `redirect_uri` itself may also contain URI-encoded components
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    var type = 'authorization_dialog';
							 | 
						||
| 
								 | 
							
								    var responseType = 'token';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return oauth3.discover(providerUri, opts).then(function (directive) {
							 | 
						||
| 
								 | 
							
								      var redirectUri = opts.redirectUri;
							 | 
						||
| 
								 | 
							
								      var scope = opts.scope || directive.authn_scope;
							 | 
						||
| 
								 | 
							
								      var clientId = opts.appId;
							 | 
						||
| 
								 | 
							
								      var args = directive[type];
							 | 
						||
| 
								 | 
							
								      var uri = args.url;
							 | 
						||
| 
								 | 
							
								      var state = Math.random().toString().replace(/^0\./, '');
							 | 
						||
| 
								 | 
							
								      var params = {};
							 | 
						||
| 
								 | 
							
								      var loc;
							 | 
						||
| 
								 | 
							
								      var result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      params.state = state;
							 | 
						||
| 
								 | 
							
								      params.response_type = responseType;
							 | 
						||
| 
								 | 
							
								      if (scope) {
							 | 
						||
| 
								 | 
							
								        if (Array.isArray(scope)) {
							 | 
						||
| 
								 | 
							
								          scope = scope.join(' ');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        params.scope = scope;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (clientId) {
							 | 
						||
| 
								 | 
							
								        // In OAuth3 client_id is optional for implicit grant
							 | 
						||
| 
								 | 
							
								        params.client_id = clientId;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (!redirectUri) {
							 | 
						||
| 
								 | 
							
								        loc = window.location;
							 | 
						||
| 
								 | 
							
								        redirectUri = loc.protocol + '//' + loc.host + loc.pathname;
							 | 
						||
| 
								 | 
							
								        if ('/' !== redirectUri[redirectUri.length - 1]) {
							 | 
						||
| 
								 | 
							
								          redirectUri += '/';
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        redirectUri += 'oauth3.html';
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      params.redirect_uri = redirectUri;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      uri += '?' + oauth3.querystringify(params);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      result = {
							 | 
						||
| 
								 | 
							
								        url: uri
							 | 
						||
| 
								 | 
							
								      , state: state
							 | 
						||
| 
								 | 
							
								      , method: args.method
							 | 
						||
| 
								 | 
							
								      , query: params
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								      return oauth3.PromiseA.resolve(result);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  oauth3.resourceOwnerPassword = function (providerUri, username, passphrase, opts) {
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Example Resource Owner Password Request
							 | 
						||
| 
								 | 
							
								    // (generally for 1st party and direct-partner mobile apps, and webapps)
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // POST https://example.com/api/org.oauth3.provider/access_token
							 | 
						||
| 
								 | 
							
								    //    { "grant_type": "password", "client_id": "<<id>>", "scope": "<<scope>>"
							 | 
						||
| 
								 | 
							
								    //    , "username": "<<username>>", "password": "password" }
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    opts = opts || {};
							 | 
						||
| 
								 | 
							
								    var type = 'access_token';
							 | 
						||
| 
								 | 
							
								    var grantType = 'password';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return oauth3.discover(providerUri, opts).then(function (directive) {
							 | 
						||
| 
								 | 
							
								      var scope = opts.scope || directive.authn_scope;
							 | 
						||
| 
								 | 
							
								      var clientId = opts.appId;
							 | 
						||
| 
								 | 
							
								      var clientAgreeTos = opts.clientAgreeTos;
							 | 
						||
| 
								 | 
							
								      var clientUri = opts.clientUri;
							 | 
						||
| 
								 | 
							
								      var args = directive[type];
							 | 
						||
| 
								 | 
							
								      var params = {
							 | 
						||
| 
								 | 
							
								        "grant_type": grantType
							 | 
						||
| 
								 | 
							
								      , "username": username
							 | 
						||
| 
								 | 
							
								      , "password": passphrase
							 | 
						||
| 
								 | 
							
								      //, "totp": opts.totp
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								      var uri = args.url;
							 | 
						||
| 
								 | 
							
								      var body;
							 | 
						||
| 
								 | 
							
								      if (opts.totp) {
							 | 
						||
| 
								 | 
							
								        params.totp = opts.totp;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (clientId) {
							 | 
						||
| 
								 | 
							
								        params.clientId = clientId;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (clientUri) {
							 | 
						||
| 
								 | 
							
								        params.clientUri = clientUri;
							 | 
						||
| 
								 | 
							
								        params.clientAgreeTos = clientAgreeTos;
							 | 
						||
| 
								 | 
							
								        if (!clientAgreeTos) {
							 | 
						||
| 
								 | 
							
								          throw new Error('Developer Error: missing clientAgreeTos uri');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (scope) {
							 | 
						||
| 
								 | 
							
								        if (Array.isArray(scope)) {
							 | 
						||
| 
								 | 
							
								          scope = scope.join(' ');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        params.scope = scope;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if ('GET' === args.method.toUpperCase()) {
							 | 
						||
| 
								 | 
							
								        uri += '?' + oauth3.querystringify(params);
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        body = params;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return {
							 | 
						||
| 
								 | 
							
								        url: uri
							 | 
						||
| 
								 | 
							
								      , method: args.method
							 | 
						||
| 
								 | 
							
								      , data: body
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exports.OAUTH3 = oauth3.oauth3 = oauth3.OAUTH3 = oauth3;
							 | 
						||
| 
								 | 
							
								  exports.oauth3 = exports.OAUTH3;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if ('undefined' !== typeof module) {
							 | 
						||
| 
								 | 
							
								    module.exports = oauth3;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}('undefined' !== typeof exports ? exports : window));
							 |