clean up, clean up, everybody everywhere
This commit is contained in:
		
							parent
							
								
									bb6bcd826e
								
							
						
					
					
						commit
						c2b6a91716
					
				@ -3,22 +3,22 @@
 | 
				
			|||||||
  'use strict';
 | 
					  'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var OAUTH3 = exports.OAUTH3 = {
 | 
					  var OAUTH3 = exports.OAUTH3 = {
 | 
				
			||||||
    utils: {
 | 
					    clientUri: function (location) {
 | 
				
			||||||
      clientUri: function (location) {
 | 
					      return OAUTH3.utils.uri.normalize(location.host + location.pathname);
 | 
				
			||||||
        return OAUTH3.utils.uri.normalize(location.host + location.pathname);
 | 
					    }
 | 
				
			||||||
 | 
					  , error: {
 | 
				
			||||||
 | 
					      parse: function (providerUri, params) {
 | 
				
			||||||
 | 
					        var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'");
 | 
				
			||||||
 | 
					        err.uri = params.error_uri || params.error.uri;
 | 
				
			||||||
 | 
					        err.code = params.error.code || params.error;
 | 
				
			||||||
 | 
					        return err;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , _error: {
 | 
					    }
 | 
				
			||||||
        parse: function (providerUri, params) {
 | 
					  , _base64: {
 | 
				
			||||||
          var err = new Error(params.error_description || params.error.message || "Unknown error with provider '" + providerUri + "'");
 | 
					      atob: function (base64) {
 | 
				
			||||||
          err.uri = params.error_uri || params.error.uri;
 | 
					 | 
				
			||||||
          err.code = params.error.code || params.error;
 | 
					 | 
				
			||||||
          return err;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    , atob: function (base64) {
 | 
					 | 
				
			||||||
        return (exports.atob || require('atob'))(base64);
 | 
					        return (exports.atob || require('atob'))(base64);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , _urlSafeBase64ToBase64: function (b64) {
 | 
					    , decodeUrlSafe: function (b64) {
 | 
				
			||||||
        // URL-safe Base64 to Base64
 | 
					        // URL-safe Base64 to Base64
 | 
				
			||||||
        // https://en.wikipedia.org/wiki/Base64
 | 
					        // https://en.wikipedia.org/wiki/Base64
 | 
				
			||||||
        // https://gist.github.com/catwell/3046205
 | 
					        // https://gist.github.com/catwell/3046205
 | 
				
			||||||
@ -26,105 +26,105 @@
 | 
				
			|||||||
        if (2 === mod) { b64 += '=='; }
 | 
					        if (2 === mod) { b64 += '=='; }
 | 
				
			||||||
        if (3 === mod) { b64 += '='; }
 | 
					        if (3 === mod) { b64 += '='; }
 | 
				
			||||||
        b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
 | 
					        b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
 | 
				
			||||||
        return b64;
 | 
					        return OAUTH3._base64.atob(b64);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , uri: {
 | 
					    }
 | 
				
			||||||
        normalize: function (uri) {
 | 
					  , uri: {
 | 
				
			||||||
          if ('string' !== typeof uri) {
 | 
					      normalize: function (uri) {
 | 
				
			||||||
            console.error((new Error('stack')).stack);
 | 
					        if ('string' !== typeof uri) {
 | 
				
			||||||
          }
 | 
					          console.error((new Error('stack')).stack);
 | 
				
			||||||
          // tested with
 | 
					 | 
				
			||||||
          //   example.com
 | 
					 | 
				
			||||||
          //   example.com/
 | 
					 | 
				
			||||||
          //   http://example.com
 | 
					 | 
				
			||||||
          //   https://example.com/
 | 
					 | 
				
			||||||
          return uri
 | 
					 | 
				
			||||||
            .replace(/^(https?:\/\/)?/i, '')
 | 
					 | 
				
			||||||
            .replace(/\/?$/, '')
 | 
					 | 
				
			||||||
            ;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        // tested with
 | 
				
			||||||
 | 
					        //   example.com
 | 
				
			||||||
 | 
					        //   example.com/
 | 
				
			||||||
 | 
					        //   http://example.com
 | 
				
			||||||
 | 
					        //   https://example.com/
 | 
				
			||||||
 | 
					        return uri
 | 
				
			||||||
 | 
					          .replace(/^(https?:\/\/)?/i, '')
 | 
				
			||||||
 | 
					          .replace(/\/?$/, '')
 | 
				
			||||||
 | 
					          ;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , url: {
 | 
					    }
 | 
				
			||||||
        normalize: function (url) {
 | 
					  , url: {
 | 
				
			||||||
          if ('string' !== typeof url) {
 | 
					      normalize: function (url) {
 | 
				
			||||||
            console.error((new Error('stack')).stack);
 | 
					        if ('string' !== typeof url) {
 | 
				
			||||||
          }
 | 
					          console.error((new Error('stack')).stack);
 | 
				
			||||||
          // tested with
 | 
					 | 
				
			||||||
          //   example.com
 | 
					 | 
				
			||||||
          //   example.com/
 | 
					 | 
				
			||||||
          //   http://example.com
 | 
					 | 
				
			||||||
          //   https://example.com/
 | 
					 | 
				
			||||||
          return url
 | 
					 | 
				
			||||||
            .replace(/^(https?:\/\/)?/i, 'https://')
 | 
					 | 
				
			||||||
            .replace(/\/?$/, '')
 | 
					 | 
				
			||||||
            ;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      , resolve: function (base, next) {
 | 
					 | 
				
			||||||
          if (/^https:\/\//i.test(next)) {
 | 
					 | 
				
			||||||
            return next;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          return this.normalize(base) + '/' + this._normalizePath(next);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      , _normalizePath: function (path) {
 | 
					 | 
				
			||||||
          return path.replace(/^\//, '').replace(/\/$/, '');
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        // tested with
 | 
				
			||||||
 | 
					        //   example.com
 | 
				
			||||||
 | 
					        //   example.com/
 | 
				
			||||||
 | 
					        //   http://example.com
 | 
				
			||||||
 | 
					        //   https://example.com/
 | 
				
			||||||
 | 
					        return url
 | 
				
			||||||
 | 
					          .replace(/^(https?:\/\/)?/i, 'https://')
 | 
				
			||||||
 | 
					          .replace(/\/?$/, '')
 | 
				
			||||||
 | 
					          ;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , query: {
 | 
					    , resolve: function (base, next) {
 | 
				
			||||||
        stringify: function (params) {
 | 
					        if (/^https:\/\//i.test(next)) {
 | 
				
			||||||
          var qs = [];
 | 
					          return next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this.normalize(base) + '/' + this._normalizePath(next);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    , _normalizePath: function (path) {
 | 
				
			||||||
 | 
					        return path.replace(/^\//, '').replace(/\/$/, '');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , query: {
 | 
				
			||||||
 | 
					      stringify: function (params) {
 | 
				
			||||||
 | 
					        var qs = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          Object.keys(params).forEach(function (key) {
 | 
					        Object.keys(params).forEach(function (key) {
 | 
				
			||||||
            // TODO nullify instead?
 | 
					          // TODO nullify instead?
 | 
				
			||||||
            if ('undefined' === typeof params[key]) {
 | 
					          if ('undefined' === typeof params[key]) {
 | 
				
			||||||
              return;
 | 
					            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;
 | 
					
 | 
				
			||||||
        }
 | 
					          if ('scope' === key) {
 | 
				
			||||||
 | 
					            params[key] = OAUTH3.utils.scope.stringify(params[key]);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          qs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return qs.join('&');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , randomState: function () {
 | 
					    }
 | 
				
			||||||
        // TODO put in different file for browser vs node
 | 
					  , scope: {
 | 
				
			||||||
        try {
 | 
					      stringify: function (scope) {
 | 
				
			||||||
          return Array.prototype.slice.call(
 | 
					        if (Array.isArray(scope)) {
 | 
				
			||||||
            window.crypto.getRandomValues(new Uint8Array(16))
 | 
					          scope = scope.join(' ');
 | 
				
			||||||
          ).map(function (ch) { return (ch).toString(16); }).join('');
 | 
					 | 
				
			||||||
        } catch(e) {
 | 
					 | 
				
			||||||
          return OAUTH3.utils._insecureRandomState();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return scope;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    , _insecureRandomState: function () {
 | 
					    }
 | 
				
			||||||
        var i;
 | 
					  , randomState: function () {
 | 
				
			||||||
        var ch;
 | 
					      // TODO put in different file for browser vs node
 | 
				
			||||||
        var str;
 | 
					      try {
 | 
				
			||||||
        // TODO use fisher-yates on 0..255 and select [0] 16 times
 | 
					        return Array.prototype.slice.call(
 | 
				
			||||||
        // [security] https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.5qx0bf95a
 | 
					          window.crypto.getRandomValues(new Uint8Array(16))
 | 
				
			||||||
        // https://github.com/v8/v8/blob/b0e4dce6091a8777bda80d962df76525dc6c5ea9/src/js/math.js#L135-L144
 | 
					        ).map(function (ch) { return (ch).toString(16); }).join('');
 | 
				
			||||||
        // Note: newer versions of v8 do not have this bug, but other engines may still
 | 
					      } catch(e) {
 | 
				
			||||||
        console.warn('[security] crypto.getRandomValues() failed, falling back to Math.random()');
 | 
					        return OAUTH3.utils._insecureRandomState();
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  , _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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  , jwt: {
 | 
					  , jwt: {
 | 
				
			||||||
      // decode only (no verification)
 | 
					      // decode only (no verification)
 | 
				
			||||||
      decode: function (str) {
 | 
					      decode: function (str) {
 | 
				
			||||||
@ -135,9 +135,8 @@
 | 
				
			|||||||
        // { header: {}, payload: {}, signature: '' }
 | 
					        // { header: {}, payload: {}, signature: '' }
 | 
				
			||||||
        var parts = str.split(/\./g);
 | 
					        var parts = str.split(/\./g);
 | 
				
			||||||
        var jsons = parts.slice(0, 2).map(function (urlsafe64) {
 | 
					        var jsons = parts.slice(0, 2).map(function (urlsafe64) {
 | 
				
			||||||
          var atob = exports.atob || require('atob');
 | 
					          var b64 = OAUTH3._base64.decodeUrlSafe(urlsafe64);
 | 
				
			||||||
          var b64 = OAUTH3.utils._urlSafeBase64ToBase64(urlsafe64);
 | 
					          return b64;
 | 
				
			||||||
          return atob(b64);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
@ -161,22 +160,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return 'stale';
 | 
					        return 'stale';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
      // encode-only (no signature)
 | 
					 | 
				
			||||||
    , encode: function (parts) {
 | 
					 | 
				
			||||||
        parts.header = parts.header || { alg: 'none', typ: 'jwt' };
 | 
					 | 
				
			||||||
        parts.signature = parts.signature || '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var btoa = exports.btoa || require('btoa');
 | 
					 | 
				
			||||||
        var result = [
 | 
					 | 
				
			||||||
          core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null)))
 | 
					 | 
				
			||||||
        , core.utils.base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null)))
 | 
					 | 
				
			||||||
        , parts.signature // should already be url-safe base64
 | 
					 | 
				
			||||||
        ].join('.');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  , urls: {
 | 
					  , urls: {
 | 
				
			||||||
      discover: function (providerUri, opts) {
 | 
					      discover: function (providerUri, opts) {
 | 
				
			||||||
@ -727,7 +710,7 @@
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // TODO params should have response_type indicating json, binary, etc
 | 
					          // 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._base64.decodeUrlSafe(params.result || params.directives));
 | 
				
			||||||
          // caller will call OAUTH3.hooks.directives._set(providerUri, directives);
 | 
					          // caller will call OAUTH3.hooks.directives._set(providerUri, directives);
 | 
				
			||||||
          return directives;
 | 
					          return directives;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -917,10 +900,24 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  OAUTH3.utils._formatError = OAUTH3.utils._error.parse;
 | 
					  OAUTH3.login = OAUTH3.implicitGrant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // TODO get rid of these
 | 
				
			||||||
 | 
					  OAUTH3.utils = {
 | 
				
			||||||
 | 
					    clientUri: OAUTH3.clientUri
 | 
				
			||||||
 | 
					  , query: OAUTH3.query
 | 
				
			||||||
 | 
					  , scope: OAUTH3.scope
 | 
				
			||||||
 | 
					  , uri: OAUTH3.uri
 | 
				
			||||||
 | 
					  , url: OAUTH3.url
 | 
				
			||||||
 | 
					  , _error: OAUTH3.error
 | 
				
			||||||
 | 
					  , _formatError: OAUTH3.error
 | 
				
			||||||
 | 
					  , _urlSafeBase64ToBase64: OAUTH3._urlSafeBase64ToBase64
 | 
				
			||||||
 | 
					  , randomState: OAUTH3.randomState
 | 
				
			||||||
 | 
					  , _insecureRandomState: OAUTH3._insecureRandomState
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ('undefined' !== typeof Promise) {
 | 
					  if ('undefined' !== typeof Promise) {
 | 
				
			||||||
    OAUTH3.PromiseA = Promise;
 | 
					    OAUTH3.PromiseA = Promise;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}('undefined' !== typeof exports ? exports : window));
 | 
					}('undefined' !== typeof exports ? exports : window));
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,9 @@
 | 
				
			|||||||
/* global Promise */
 | 
					 | 
				
			||||||
;(function (exports) {
 | 
					;(function (exports) {
 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OAUTH3.utils.query.parse = function (search) {
 | 
					var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.implicit.js').OAUTH3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OAUTH3.query.parse = function (search) {
 | 
				
			||||||
  // parse a query or a hash
 | 
					  // parse a query or a hash
 | 
				
			||||||
  if (-1 !== ['#', '?'].indexOf(search[0])) {
 | 
					  if (-1 !== ['#', '?'].indexOf(search[0])) {
 | 
				
			||||||
    search = search.substring(1);
 | 
					    search = search.substring(1);
 | 
				
			||||||
@ -32,19 +33,19 @@ OAUTH3.utils.query.parse = function (search) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  return argsParsed;
 | 
					  return argsParsed;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
OAUTH3.utils.scope.parse = function (scope) {
 | 
					OAUTH3.scope.parse = function (scope) {
 | 
				
			||||||
  return (scope||'').split(/[, ]/g);
 | 
					  return (scope||'').split(/[, ]/g);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
OAUTH3.utils.url.parse = function (url) {
 | 
					OAUTH3.url.parse = function (url) {
 | 
				
			||||||
  // TODO browser
 | 
					  // TODO browser
 | 
				
			||||||
  // Node should replace this
 | 
					  // Node should replace this
 | 
				
			||||||
  var parser = document.createElement('a');
 | 
					  var parser = document.createElement('a');
 | 
				
			||||||
  parser.href = url;
 | 
					  parser.href = url;
 | 
				
			||||||
  return parser;
 | 
					  return parser;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
OAUTH3.utils.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
 | 
					OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
 | 
				
			||||||
  var src = OAUTH3.utils.url.parse(referrerUrl);
 | 
					  var src = OAUTH3.url.parse(referrerUrl);
 | 
				
			||||||
  var dst = OAUTH3.utils.url.parse(redirectUrl);
 | 
					  var dst = OAUTH3.url.parse(redirectUrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO how should we handle subdomains?
 | 
					  // TODO how should we handle subdomains?
 | 
				
			||||||
  // It should be safe for api.example.com to redirect to example.com
 | 
					  // It should be safe for api.example.com to redirect to example.com
 | 
				
			||||||
@ -55,11 +56,11 @@ OAUTH3.utils.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) {
 | 
				
			|||||||
  // api.example.com.evil.com SHOULD NOT match example.com
 | 
					  // api.example.com.evil.com SHOULD NOT match example.com
 | 
				
			||||||
  return dst.hostname === src.hostname;
 | 
					  return dst.hostname === src.hostname;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
OAUTH3.utils.url.checkRedirect = function (client, query) {
 | 
					OAUTH3.url.checkRedirect = function (client, query) {
 | 
				
			||||||
  console.warn("[security] URL path checking not yet implemented");
 | 
					  console.warn("[security] URL path checking not yet implemented");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var clientUrl = OAUTH3.utils.url.normalize(client.url);
 | 
					  var clientUrl = OAUTH3.url.normalize(client.url);
 | 
				
			||||||
  var redirectUrl = OAUTH3.utils.url.normalize(query.redirect_uri);
 | 
					  var redirectUrl = OAUTH3.url.normalize(query.redirect_uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // General rule:
 | 
					  // General rule:
 | 
				
			||||||
  // I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
 | 
					  // I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
 | 
				
			||||||
@ -67,13 +68,13 @@ OAUTH3.utils.url.checkRedirect = function (client, query) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // We can callback to an explicitly listed domain (TODO and path)
 | 
					  // We can callback to an explicitly listed domain (TODO and path)
 | 
				
			||||||
  if (OAUTH3.utils.url._isRedirectHostSafe(clientUrl, redirectUrl)) {
 | 
					  if (OAUTH3.url._isRedirectHostSafe(clientUrl, redirectUrl)) {
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
OAUTH3.utils.url.redirect = function (clientParams, grants, tokenOrError) {
 | 
					OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) {
 | 
				
			||||||
  // TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
 | 
					  // TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
 | 
				
			||||||
  // TODO check redirect safeness right here with grants.client.urls
 | 
					  // TODO check redirect safeness right here with grants.client.urls
 | 
				
			||||||
  // TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
 | 
					  // TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
 | 
				
			||||||
@ -93,13 +94,13 @@ OAUTH3.utils.url.redirect = function (clientParams, grants, tokenOrError) {
 | 
				
			|||||||
    authz.error_description = tokenOrError.error.message || tokenOrError.error_description;
 | 
					    authz.error_description = tokenOrError.error.message || tokenOrError.error_description;
 | 
				
			||||||
    authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri;
 | 
					    authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.utils.query.stringify(authz);
 | 
					  var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.query.stringify(authz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (clientParams.debug) {
 | 
					  if (clientParams.debug) {
 | 
				
			||||||
    console.info('final redirect_uri:', redirect);
 | 
					    console.info('final redirect_uri:', redirect);
 | 
				
			||||||
    window.alert("You're in debug mode so we've taken a pause. Hit OK to continue");
 | 
					    window.alert("You're in debug mode so we've taken a pause. Hit OK to continue");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
  window.location = redirect;
 | 
					  window.location = redirect;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -164,11 +165,11 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (scope) {
 | 
					  if (scope) {
 | 
				
			||||||
    params.scope = OAUTH3.utils.scope.stringify(scope);
 | 
					    params.scope = OAUTH3.scope.stringify(scope);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ('GET' === args.method.toUpperCase()) {
 | 
					  if ('GET' === args.method.toUpperCase()) {
 | 
				
			||||||
    uri += '?' + OAUTH3.utils.query.stringify(params);
 | 
					    uri += '?' + OAUTH3.query.stringify(params);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    body = params;
 | 
					    body = params;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -207,8 +208,8 @@ OAUTH3.urls.grants = function (directive, opts) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var url = OAUTH3.utils.url.resolve(directive.issuer, directive.grants.url)
 | 
					  var url = OAUTH3.url.resolve(directive.issuer, directive.grants.url)
 | 
				
			||||||
    .replace(/(:azp|:client_id)/g, OAUTH3.utils.uri.normalize(opts.client_id || opts.client_uri))
 | 
					    .replace(/(:azp|:client_id)/g, OAUTH3.uri.normalize(opts.client_id || opts.client_uri))
 | 
				
			||||||
    .replace(/(:sub|:account_id)/g, opts.session.token.sub)
 | 
					    .replace(/(:sub|:account_id)/g, opts.session.token.sub)
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
  var data = {
 | 
					  var data = {
 | 
				
			||||||
@ -222,7 +223,7 @@ OAUTH3.urls.grants = function (directive, opts) {
 | 
				
			|||||||
  var body;
 | 
					  var body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ('GET' === opts.method) {
 | 
					  if ('GET' === opts.method) {
 | 
				
			||||||
    url += '?' + OAUTH3.utils.query.stringify(data);
 | 
					    url += '?' + OAUTH3.query.stringify(data);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    body = data;
 | 
					    body = data;
 | 
				
			||||||
@ -237,9 +238,7 @@ OAUTH3.urls.grants = function (directive, opts) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OAUTH3.authn = {};
 | 
					OAUTH3.authn = {};
 | 
				
			||||||
 | 
					OAUTH3.authn.loginMeta = OAUTH3.authz.loginMeta = function (directive, opts) {
 | 
				
			||||||
OAUTH3.authz = {};
 | 
					 | 
				
			||||||
OAUTH3.authz.loginMeta = function (directive, opts) {
 | 
					 | 
				
			||||||
  if (opts.mock) {
 | 
					  if (opts.mock) {
 | 
				
			||||||
    if (opts.mockError) {
 | 
					    if (opts.mockError) {
 | 
				
			||||||
      return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
 | 
					      return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
 | 
				
			||||||
@ -250,23 +249,22 @@ OAUTH3.authz.loginMeta = function (directive, opts) {
 | 
				
			|||||||
  return OAUTH3.request({
 | 
					  return OAUTH3.request({
 | 
				
			||||||
    method: directive.credential_meta.method || 'GET'
 | 
					    method: directive.credential_meta.method || 'GET'
 | 
				
			||||||
    // TODO lint urls
 | 
					    // TODO lint urls
 | 
				
			||||||
  , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_meta.url)
 | 
					  , url: OAUTH3.url.resolve(directive.issuer, directive.credential_meta.url)
 | 
				
			||||||
      .replace(':type', 'email')
 | 
					      .replace(':type', 'email')
 | 
				
			||||||
      .replace(':id', opts.email)
 | 
					      .replace(':id', opts.email)
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					OAUTH3.authn.otp = OAUTH3.authz.otp = function (directive, opts) {
 | 
				
			||||||
OAUTH3.authz.otp = function (directive, opts) {
 | 
					 | 
				
			||||||
  if (opts.mock) {
 | 
					  if (opts.mock) {
 | 
				
			||||||
    if (opts.mockError) {
 | 
					    if (opts.mockError) {
 | 
				
			||||||
      return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
 | 
					      return OAUTH3.PromiseA.resolve({data: {error: {message: "Yikes!", code: 'E'}}});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return OAUTH3.PromiseA.resolve({data: {uuid: "uuidblah"}});
 | 
					    return OAUTH3.PromiseA.resolve({data: {uuid: "uuidblah"}});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
  return OAUTH3.request({
 | 
					  return OAUTH3.request({
 | 
				
			||||||
    method: directive.credential_otp.url.method || 'POST'
 | 
					    method: directive.credential_otp.url.method || 'POST'
 | 
				
			||||||
  , url: OAUTH3.utils.url.resolve(directive.issuer, directive.credential_otp.url)
 | 
					  , url: OAUTH3.url.resolve(directive.issuer, directive.credential_otp.url)
 | 
				
			||||||
  , data: {
 | 
					  , data: {
 | 
				
			||||||
      // TODO replace with signed hosted file
 | 
					      // TODO replace with signed hosted file
 | 
				
			||||||
      client_agree_tos: 'oauth3.org/tos/draft'
 | 
					      client_agree_tos: 'oauth3.org/tos/draft'
 | 
				
			||||||
@ -277,8 +275,7 @@ OAUTH3.authz.otp = function (directive, opts) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					OAUTH3.authn.resourceOwnerPassword = OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
 | 
				
			||||||
OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
 | 
					 | 
				
			||||||
  console.log('ginger bread man');
 | 
					  console.log('ginger bread man');
 | 
				
			||||||
  var providerUri = directive.issuer;
 | 
					  var providerUri = directive.issuer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -291,7 +288,7 @@ OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
 | 
				
			|||||||
      var data = req.data;
 | 
					      var data = req.data;
 | 
				
			||||||
      data.provider_uri = providerUri;
 | 
					      data.provider_uri = providerUri;
 | 
				
			||||||
      if (data.error) {
 | 
					      if (data.error) {
 | 
				
			||||||
        return oauth3.PromiseA.reject(OAUTH3.utils._error.parse(providerUri, data.error));
 | 
					        return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, data.error));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return OAUTH3.hooks.refreshSession(
 | 
					      return OAUTH3.hooks.refreshSession(
 | 
				
			||||||
        opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
 | 
					        opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri }
 | 
				
			||||||
@ -300,6 +297,8 @@ OAUTH3.authz.resourceOwnerPassword = function (directive, opts) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OAUTH3.authz = {};
 | 
				
			||||||
OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
 | 
					OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
 | 
				
			||||||
  if (clientParams.mock) {
 | 
					  if (clientParams.mock) {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
@ -312,7 +311,7 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // OAuth3.requests.grants(providerUri, {});         // return list of grants
 | 
					  // OAuth3.requests.grants(providerUri, {});         // return list of grants
 | 
				
			||||||
  // OAuth3.checkGrants(providerUri, {});             //
 | 
					  // OAuth3.checkGrants(providerUri, {});             //
 | 
				
			||||||
  var clientUri = OAUTH3.utils.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer);
 | 
					  var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer);
 | 
				
			||||||
  var scope = clientParams.scope || '';
 | 
					  var scope = clientParams.scope || '';
 | 
				
			||||||
  var clientObj = clientParams;
 | 
					  var clientObj = clientParams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -348,14 +347,14 @@ OAUTH3.authz.scopes = function (providerUri, session, clientParams) {
 | 
				
			|||||||
    // it doesn't matter who the referrer is as long as the destination
 | 
					    // it doesn't matter who the referrer is as long as the destination
 | 
				
			||||||
    // is an authorized destination for the client in question
 | 
					    // is an authorized destination for the client in question
 | 
				
			||||||
    // (though it may not hurt to pass the referrer's info on to the client)
 | 
					    // (though it may not hurt to pass the referrer's info on to the client)
 | 
				
			||||||
    if (!OAUTH3.utils.url.checkRedirect(grantResults.client, clientObj)) {
 | 
					    if (!OAUTH3.url.checkRedirect(grantResults.client, clientObj)) {
 | 
				
			||||||
      callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK'
 | 
					      callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK'
 | 
				
			||||||
        + '?redirect_uri=' + clientObj.redirect_uri
 | 
					        + '?redirect_uri=' + clientObj.redirect_uri
 | 
				
			||||||
        + '&allowed_urls=' + grantResults.client.url
 | 
					        + '&allowed_urls=' + grantResults.client.url
 | 
				
			||||||
        + '&client_id=' + clientUri
 | 
					        + '&client_id=' + clientUri
 | 
				
			||||||
        + '&referrer_uri=' + OAUTH3.utils.uri.normalize(window.document.referrer)
 | 
					        + '&referrer_uri=' + OAUTH3.uri.normalize(window.document.referrer)
 | 
				
			||||||
        ;
 | 
					        ;
 | 
				
			||||||
      if (opts.debug) {
 | 
					      if (clientParams.debug) {
 | 
				
			||||||
        console.log('grantResults Redirect Attack');
 | 
					        console.log('grantResults Redirect Attack');
 | 
				
			||||||
        console.log(grantResults);
 | 
					        console.log(grantResults);
 | 
				
			||||||
        console.log(clientObj);
 | 
					        console.log(clientObj);
 | 
				
			||||||
@ -424,21 +423,21 @@ OAUTH3.authz.grants = function (providerUri, opts) {
 | 
				
			|||||||
      var grants = grantsResult.originalData || grantsResult.data;
 | 
					      var grants = grantsResult.originalData || grantsResult.data;
 | 
				
			||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
      if (grants.error) {
 | 
					      if (grants.error) {
 | 
				
			||||||
        return oauth3.PromiseA.reject(oauth3.utils._formatError(grants.error));
 | 
					        return OAUTH3.PromiseA.reject(OAUTH3.error.parse(grants.error));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      console.warn('requests.grants', grants);
 | 
					      console.warn('requests.grants', grants);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      oauth3.hooks.setGrants(opts.client_id + '-client', grants.client);
 | 
					      OAUTH3.hooks.grants.set(opts.client_id + '-client', grants.client);
 | 
				
			||||||
      grants.grants.forEach(function (grant) {
 | 
					      grants.grants.forEach(function (grant) {
 | 
				
			||||||
        var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId;
 | 
					        var clientId = grant.client_id || grant.oauth_client_id || grant.oauthClientId;
 | 
				
			||||||
        // TODO should save as an array
 | 
					        // TODO should save as an array
 | 
				
			||||||
        oauth3.hooks.setGrants(clientId, [ grant ]);
 | 
					        OAUTH3.hooks.grants.set(clientId, [ grant ]);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        client: oauth3.hooks.getGrants(opts.client_id + '-client')
 | 
					        client: OAUTH3.hooks.grants.get(opts.client_id + '-client')
 | 
				
			||||||
      , grants: oauth3.hooks.getGrants(opts.client_id) || []
 | 
					      , grants: OAUTH3.hooks.grants.get(opts.client_id) || []
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@ -464,7 +463,7 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s
 | 
				
			|||||||
      console.info('generate token results');
 | 
					      console.info('generate token results');
 | 
				
			||||||
      console.info(results);
 | 
					      console.info(results);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      OAUTH3.utils.url.redirect(clientParams, scopes, results);
 | 
					      OAUTH3.url.redirect(clientParams, scopes, results);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else if ('code' === clientParams.response_type) {
 | 
					  else if ('code' === clientParams.response_type) {
 | 
				
			||||||
@ -548,4 +547,4 @@ OAUTH3._browser.isIframe = function isIframe () {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}('undefined' !== typeof exports ? exports : window));
 | 
					}('undefined' !== typeof exports ? exports : window));
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +1,23 @@
 | 
				
			|||||||
/* global Promise */
 | 
					 | 
				
			||||||
;(function (exports) {
 | 
					;(function (exports) {
 | 
				
			||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  OAUTH3.utils._base64ToUrlSafeBase64 = function (b64) {
 | 
					  var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.implicit.js').OAUTH3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OAUTH3._base64.btoa = exports.btoa || require('btoa');
 | 
				
			||||||
 | 
					  OAUTH3._base64.encodeUrlSafe = function (b64) {
 | 
				
			||||||
    // Base64 to URL-safe Base64
 | 
					    // Base64 to URL-safe Base64
 | 
				
			||||||
    b64 = b64.replace(/\+/g, '-').replace(/\//g, '_');
 | 
					    b64 = b64.replace(/\+/g, '-').replace(/\//g, '_');
 | 
				
			||||||
    b64 = b64.replace(/=+/g, '');
 | 
					    b64 = b64.replace(/=+/g, '');
 | 
				
			||||||
    return b64;
 | 
					    return OAUTH3._base64.btoa(b64);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  OAUTH3.jwt.encode = function (parts) {
 | 
					  OAUTH3.jwt.encode = function (parts) {
 | 
				
			||||||
    parts.header = parts.header || { alg: 'none', typ: 'jwt' };
 | 
					    parts.header = parts.header || { alg: 'none', typ: 'jwt' };
 | 
				
			||||||
    parts.signature = parts.signature || '';
 | 
					    parts.signature = parts.signature || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var btoa = exports.btoa || require('btoa');
 | 
					 | 
				
			||||||
    var result = [
 | 
					    var result = [
 | 
				
			||||||
      OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.header, null)))
 | 
					      OAUTH3._base64.encodeUrlSafe(JSON.stringify(parts.header, null))
 | 
				
			||||||
    , OAUTH3.utils._base64ToUrlSafeBase64(btoa(JSON.stringify(parts.payload, null)))
 | 
					    , OAUTH3._base64.encodeUrlSafe(JSON.stringify(parts.payload, null))
 | 
				
			||||||
    , parts.signature // should already be url-safe base64
 | 
					    , parts.signature // should already be url-safe base64
 | 
				
			||||||
    ].join('.');
 | 
					    ].join('.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,7 +64,7 @@
 | 
				
			|||||||
    , payload: { exp: Math.round(Date.now() / 1000) + 900, sub: 'fakeUserId', scp: opts.scope }
 | 
					    , payload: { exp: Math.round(Date.now() / 1000) + 900, sub: 'fakeUserId', scp: opts.scope }
 | 
				
			||||||
    , signature: "fakeSig"
 | 
					    , signature: "fakeSig"
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
    return OAUTH3.hooks.session.refresh(
 | 
					    return OAUTH3.hooks.session.refresh(
 | 
				
			||||||
      opts.session || {
 | 
					      opts.session || {
 | 
				
			||||||
        provider_uri: providerUri
 | 
					        provider_uri: providerUri
 | 
				
			||||||
@ -78,4 +79,4 @@
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}('undefined' !== typeof exports ? exports : window));
 | 
					}('undefined' !== typeof exports ? exports : window));
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user