diff --git a/oauth3.core.js b/oauth3.core.js
index e268388..c500461 100644
--- a/oauth3.core.js
+++ b/oauth3.core.js
@@ -1,4 +1,4 @@
-/* global Promise */
+/ * global Promise */
;(function (exports) {
'use strict';
@@ -294,34 +294,41 @@
}
}
, urls: {
- discover: function (providerUri, opts) {
+ , rpc: function (providerUri, opts) {
if (!providerUri) {
- throw new Error("cannot discover without providerUri");
+ throw new Error("cannot run rpc without providerUri");
}
if (!opts.client_id) {
- throw new Error("cannot discover without options.client_id");
+ throw new Error("cannot run rpc without options.client_id");
}
var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri);
providerUri = OAUTH3.url.normalize(providerUri);
var params = {
- action: 'directives'
- , state: opts.state || OAUTH3.utils.randomState()
+ state: opts.state || OAUTH3.utils.randomState()
, redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/')
, response_type: 'rpc'
, _method: 'GET'
- , _pathname: '.well-known/oauth3/directives.json'
+ , _scheme: opts._scheme
+ , _pathname: opts._pathname
, debug: opts.debug || undefined
};
- var result = {
+ var toRequest = {
url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.query.stringify(params)
, state: params.state
, method: 'GET'
, query: params
};
- return result;
+ return toRequest;
+ }
+ , discover: function (providerUri, opts) {
+ return OAUTH3.urls.directives(providerUri, opts);
+ }
+ , directives: function (providerUri, opts) {
+ opts._pathname = ".well-known/oauth3/scopes.json";
+ return OAUTH3.urls.rpc(providerUri, opts);
}
, implicitGrant: function (directive, opts) {
//
@@ -530,6 +537,14 @@
return OAUTH3.PromiseA.resolve(OAUTH3._hooks.directives.clear());
}
}
+ , scopes: {
+ get: function(providerUri) {
+ //TODO: retrieve cached scopes
+ }
+ , set: function(providerUri, scopes) {
+ //TODO: cache scopes
+ }
+ }
, session: {
refresh: function (oldSession, newSession) {
var providerUri = oldSession.provider_uri;
@@ -658,9 +673,29 @@
}
}
}
- , discover: function (providerUri, opts) {
+ , discoverScopes: function (providerUri, opts) {
+ return OAUTH.scopes(providerUri, opts);
+ }
+ , scopes: function (providerUri, opts) {
if (!providerUri) {
- throw new Error('oauth3.discover(providerUri, opts) received providerUri as ' + providerUri);
+ throw new Error('oauth3.discoverScopes(providerUri, opts) received providerUri as :', providerUri);
+ }
+
+ opts = opts || {};
+ opts._pathname = ".well-known/oauth3/scopes.json";
+
+ //TODO: add caching
+
+ return OAUTH3._rpcHelper(providerUri, opts).then(function(scopes) {
+ return scopes;
+ });
+ }
+ , discover: function (providerUri, opts) {
+ return OAUTH3.directives(providerUri, opts);
+ }
+ , directives: function (providerUri, opts) {
+ if (!providerUri) {
+ throw new Error('oauth3.discover(providerUri, opts) received providerUri as :', providerUri);
}
return OAUTH3.hooks.directives.get(providerUri).then(function (directives) {
@@ -668,7 +703,8 @@
return directives;
}
- return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) {
+ opts._pathname = ".well-known/oauth3/directives.json";
+ return OAUTH3._rpcHelper(providerUri, opts).then(function (directives) {
directives.azp = directives.azp || OAUTH3.url.normalize(providerUri);
directives.issuer = directives.issuer || OAUTH3.url.normalize(providerUri);
directives.api = OAUTH3.url.normalize((directives.api||':hostname').replace(/:hostname/, OAUTH3.uri.normalize(directives.issuer) || OAUTH3.uri.normalize(providerUri)));
@@ -677,8 +713,8 @@
});
});
}
- , _discoverHelper: function(providerUri, opts) {
- return OAUTH3._browser.discover(providerUri, opts);
+ , _rpcHelper: function(providerUri, opts) {
+ return OAUTH3._browser.rpc(providerUri, opts);
}
, request: function (preq, opts) {
function fetch() {
@@ -858,21 +894,28 @@
//
, _browser: {
window: 'undefined' !== typeof window ? window : null
- // TODO we don't need to include this if we're using jQuery or angular
- , discover: function(providerUri, opts) {
+ , rpc: function(providerUri, opts) {
opts = opts || {};
providerUri = OAUTH3.url.normalize(providerUri);
+ // TODO SECURITY should we whitelist our own self?
if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) {
- console.warn("It looks like you're a provider checking for your own directive,"
+ console.warn("It looks like you're a provider trying to run rpc on yourself,"
+ " so we we're just gonna use"
- + " OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })");
- return OAUTH3.request({
- method: 'GET'
- , url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/directives.json'
- }).then(function (resp) {
- return resp.data;
- });
+ + " OAUTH3.request({ method: 'GET', url: "
+ + "'" + opts._pathname + "' })");
+
+ if (/localstorage/i.test(opts._scheme)) {
+ return OAUTH3.PromiseA.resolve(localStorage.getItem(opts._pathname));
+ }
+ else {
+ return OAUTH3.request({
+ method: 'GET'
+ , url: OAUTH3.url.normalize(providerUri) + opts._pathname // '/.well-known/oauth3/' + discoverFile
+ }).then(function (resp) {
+ return resp.data;
+ });
+ }
}
if (!(opts.client_id || opts.client_uri).match(OAUTH3._browser.window.location.hostname)) {
@@ -881,17 +924,20 @@
console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname);
}
- var discReq = OAUTH3.urls.discover(
+ var discReq = OAUTH3.urls.rpc(
providerUri
, { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location))
, windowType: opts.broker && opts.windowType || 'background'
, broker: opts.broker
, state: opts._state || undefined
, debug: opts.debug
+ , _scheme: opts._scheme
+ , _pathname: opts._pathname
+ , _method: opts._method
}
);
opts._state = discReq.state;
- //var discReq = OAUTH3.urls.discover(providerUri, opts);
+ //var discReq = OAUTH3.urls.rpc(providerUri, opts);
// hmm... we're gonna need a broker for this since switching windows is distracting,
// popups are obnoxious, iframes are sometimes blocked, and most servers don't implement CORS
@@ -920,9 +966,9 @@
}
// TODO params should have response_type indicating json, binary, etc
- var directives = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives));
+ var result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.data || params.result || params.directives));
// caller will call OAUTH3.hooks.directives.set(providerUri, directives);
- return directives;
+ return result;
});
});
}
diff --git a/well-known/oauth3/index.html b/well-known/oauth3/index.html
index 9c415e5..a3d6c62 100644
--- a/well-known/oauth3/index.html
+++ b/well-known/oauth3/index.html
@@ -20,40 +20,20 @@
// TODO what about search within hash?
var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/]";
var params = OAUTH3.query.parse(window.location.hash || window.location.search);
- if (params.debug) {
- console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled.");
- }
+ var urlsafe64;
+ var redirect;
+ var err;
+ var oldRpc;
+ var sub = params.sub || params.subject;
+ var subData;
- console.log(prefix, 'hash||search:');
- console.log(window.location.hash || window.location.search);
+ function doRedirect(redirect) {
+ if (params.debug) {
+ console.log(prefix, 'params.redirect_uri:', params.redirect_uri);
+ console.log(prefix, 'redirect');
+ console.log(redirect);
+ }
- console.log(prefix, 'params:');
- console.log(params);
-
- OAUTH3.request({ url: 'directives.json' }).then(function (resp) {
- var urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0));
- var redirect;
-
- console.log(prefix, 'directives');
- console.log(resp);
-
- console.log(prefix, 'base64');
- console.log(urlsafe64);
-
- // TODO try postMessage back to redirect_uri domain right here
- // window.postMessage();
-
- // TODO make sure it's https NOT http
- // NOTE: this can be only up to 2,083 characters
- console.log(prefix, 'params.redirect_uri:', params.redirect_uri);
- redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
- state: params.state
- , directives: urlsafe64
- , debug: params.debug || undefined
- })
-
- console.log(prefix, 'redirect');
- console.log(redirect);
if (!params.debug) {
window.location = redirect;
} else {
@@ -63,6 +43,93 @@
+ ' to let you look at logs or whatever it is that you intended to do.'
+ '
Continue with redirect: ' + redirect + '' + 'a>';
}
+ }
+
+ function onError(err) {
+ var redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
+ state: params.state
+ , error: err.code
+ , error_description: err.message
+ , error_uri: err.uri
+ , debug: params.debug || undefined
+ });
+
+ doRedirect(redirect);
+ }
+
+ function onSuccess(urlsafe64, hasSub) {
+ if (params.debug) {
+ console.log(prefix, 'directives');
+ console.log(resp);
+
+ console.log(prefix, 'base64');
+ console.log(urlsafe64);
+ }
+
+ // TODO try postMessage back to redirect_uri domain right here
+ // window.postMessage();
+
+ // TODO SECURITY make sure it's https NOT http
+ // NOTE: this can be only up to 2,083 characters
+ redirect = params.redirect_uri + '?' + OAUTH3.query.stringify({
+ state: params.state
+ , directives: oldRpc ? urlsafe64 : undefined
+ , data: !oldRpc ? urlsafe64 : undefined
+ , sub: hasSub && sub || undefined
+ , debug: params.debug || undefined
+ });
+
+ doRedirect(redirect);
+ }
+
+ if (params.debug) {
+ console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled.");
+
+ console.log(prefix, 'hash||search:');
+ console.log(window.location.hash || window.location.search);
+
+ console.log(prefix, 'params:');
+ console.log(params);
+ }
+
+ if ('rpc' !== params.response_type) {
+ err = new Error("response_type '" + params.response_type + "' is not supported");
+ err.code = "E_RESPONSE_TYPE";
+ // TODO err.uri
+ onError(err);
+ return;
+ }
+
+ if (params.action) {
+ oldRpc = true;
+ }
+
+ if (/localstorage/i.test(params._scheme)) {
+ if (sub) {
+ subData = localStorage.getItem(sub + '@oauth3.org:issuer');
+ onSuccess(subData || localStorage.getItem('oauth3.org:issuer'), subData && true);
+ return;
+ }
+ onSuccess(localStorage.getItem('oauth3.org:issuer'));
+ return;
+ }
+
+ var fileWhiteList = [
+ '.well-known/oauth3/directives.json'
+ , '.well-known/oauth3/scopes.json'
+ ];
+
+ if (-1 === fileWhiteList.indexOf(params._pathname)) {
+ err = new Error("No access to requested file: " + params._pathname);
+ err.code = "E_ACCESS_DENIED"
+ // TODO err.uri
+ onError(err);
+ }
+
+ OAUTH3.request({ url: 'directives.json' }).then(function (resp) {
+ urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0));
+
+ onSuccess(urlsafe64);
});
}());
diff --git a/well-known/oauth3/scopes.json b/well-known/oauth3/scopes.json
new file mode 100644
index 0000000..268acf7
--- /dev/null
+++ b/well-known/oauth3/scopes.json
@@ -0,0 +1,26 @@
+{
+
+ "oauth3_authn": "Basic secure authentication"
+ , "auth@oauth3.org": "Basic secure authentication"
+ , "wallet": "Access to payments and subscriptions"
+ , "bucket": "Access to file storage"
+ , "db": "Access to app data"
+ , "domains": "Domain registration (and Glue and NS records)"
+ , "domains@oauth3.org": "Domain registration (and Glue and NS records)"
+ , "domains:glue": "Glue Record management (for vanity nameservers)"
+ , "domains:ns": "Name Server management"
+ , "dns": "DNS records (A/AAAA, TXT, SRV, MX, etc)"
+
+ , "hello@example.com": "Hello World Example Access"
+ , "authn@oauth3.org": "Basic secure authentication"
+ , "wallet@oauth3.org": "Access to payments and subscriptions"
+ , "bucket@oauth3.org": "Access to file storage"
+ , "db@oauth3.org": "Access to app data"
+ , "domains@oauth3.org": "Domain registration (and Glue and NS records)"
+ , "domains:glue@oauth3.org": "Glue Record management (for vanity nameservers)"
+ , "domains:ns@oauth3.org": "Name Server management"
+ , "dns@oauth3.org": "DNS records (A/AAAA, TXT, SRV, MX, etc)"
+ , "www@daplie.com": "Websites and webapps"
+
+ , "*": "FULL ACCOUNT ACCESS"
+ }