diff --git a/README.md b/README.md index 3aad46d..435fd54 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ If you have no idea what you're doing 1. Create a folder for your project named after your app, such as `example.com/` 2. Inside of the folder `example.com/` a folder called `assets/` 3. Inside of the folder `example.com/assets` a folder called `org.oauth3/` -4. Download [oauth.js-v1.zip](https://git.daplie.com/Daplie/oauth3.js/repository/archive.zip?ref=v1) +4. Download [oauth3.js-v1.zip](https://git.daplie.com/OAuth3/oauth3.js/repository/archive.zip?ref=v1) 5. Double-click to unzip the folder. 6. Copy the file `oauth3.core.js` into the folder `example.com/assets/org.oauth3/` 7. Copy the folder `well-known` into the folder `example.com/` @@ -61,7 +61,7 @@ var auth = OAUTH3.create(window.location); // use window.location to set Client // function onChangeProvider(_providerUri) { // example https://oauth3.org - return auth.setProvider(providerUri); + return oauth3.setIdentityProvider(providerUri); } @@ -69,7 +69,7 @@ function onChangeProvider(_providerUri) { // function onClickLogin() { - return auth.authenticate().then(function (session) { + return oauth3.authenticate().then(function (session) { console.info('Authentication was Successful:'); console.log(session); @@ -80,7 +80,7 @@ function onClickLogin() { // console.info('Secure PPID (aka subject):', session.token.sub); - return auth.request({ + return oauth3.request({ url: 'https://oauth3.org/api/org.oauth3.provider/inspect' , session: session }).then(function (resp) { @@ -102,7 +102,7 @@ function onClickLogin() { // function onClickLogout() { - return auth.logout().then(function () { + return oauth3.logout().then(function () { localStorage.clear(); console.info('Logout was Successful'); @@ -167,7 +167,7 @@ pushd /path/to/your/web/app # clone the project as assets/org.oauth3 mkdir -p assets -git clone git@git.daplie.com:Daplie/oauth3.js.git assets/org.oauth3 +git clone git@git.daplie.com:OAuth3/oauth3.js.git assets/org.oauth3 pushd assets/org.oauth3 git checkout v1 popd @@ -284,29 +284,33 @@ We include a small wrapper function of just a few lines in the bottom of `oauth3 which exposes a `create` method to make using the underlying library require typing fewer keystrokes. ``` -auth = OAUTH3.create(location); // takes a location object, such as window.location - // to create the Client URI (your app's id) - // and save it to an internal state +oauth3 = OAUTH3.create(location); // takes a location object, such as window.location + // to create the Client URI (your app's id) + // and save it to an internal state -promise = auth.init(location); // set and fetch your own site/app's configuration details +promise = oauth3.init(location); // set and fetch your own site/app's configuration details // promises your site's config -promise = auth.setProvider(url); // changes the Provider URI (the site you're logging into), -// promises the provider's config // gets the config for that site (from their .well-known/oauth3), - // and caches it in internal state as the default +promise = oauth3.setIdentityProvider(url); // changes the Identity Provider URI (the site you're logging into), +// promises the provider's config // gets the config for that site (from their .well-known/oauth3), + // and caches it in internal state as the default -promise = auth.authenticate(); // opens login window for the provider and returns a session - // (must be called after the setProvider promise has completed) +promise = oauth3.setResourceProvider(url); // changes the Resource Provider URI (the site you're getting stuff from) -promise = auth.authorize(permissions); // authenticates (if not authenticated) and opens a window to - // authorize a particular scope (contacts, photos, whatever) +promise = oauth3.setProvider(url); // changes the both Identity and Resource Provider URI together -promise = auth.request({ url, method, data }); // make an (authorized) request to a provider's resource - // (contacts, photos, whatever) +promise = oauth3.authenticate(); // opens login window for the provider and returns a session + // (must be called after the setIdentityProvider promise has completed) -promise = auth.logout(); // opens logout window for the provider +promise = oauth3.authorize(permissions); // authenticates (if not authenticated) and opens a window to + // authorize a particular scope (contacts, photos, whatever) -auth.session(); // returns the current session, if any +promise = oauth3.request({ url, method, data }); // make an (authorized) request to a provider's resource + // (contacts, photos, whatever) + +promise = oauth3.logout(); // opens logout window for the provider + +oauth3.session(); // returns the current session, if any ``` @@ -437,7 +441,7 @@ Since we do not require the `protocol` to be specified, it is a URI However, we do have a problem of disambiguation since a URI may look like a `path`: 1. https://example.com/api/org.oauth3.provider -2. example.com/api/org.oauth.provider/ (not unique) +2. example.com/api/org.oauth3.provider/ (not unique) 3. /api/org.oauth3.provider 4. api/org.oauth3.provider (not unique) diff --git a/oauth3.account.js b/oauth3.account.js index 030d65d..5e73122 100644 --- a/oauth3.account.js +++ b/oauth3.account.js @@ -70,4 +70,17 @@ OAUTH3.api['account.addAddress'] = function (providerUri, opts) { }); }; +OAUTH3.api['account.removeAddress'] = function (providerUri, opts) { + var session = opts.session; + + return OAUTH3.request({ + method: 'DELETE' + , url: OAUTH3.url.normalize(providerUri) + + '/api/com.daplie.me/accounts/' + session.token.sub + '/addresses/' + opts.addressId + , session: session + }).then(function (res) { + return res; + }); +}; + }('undefined' !== typeof exports ? exports : window)); diff --git a/oauth3.core.js b/oauth3.core.js index 7f11c4c..39f79e1 100644 --- a/oauth3.core.js +++ b/oauth3.core.js @@ -603,7 +603,7 @@ console.warn('[Warn] Please implement OAUTH3._hooks.sessions.get = function (providerUri[, id]) { return PromiseA; }'); return JSON.parse(window.sessionStorage.getItem('session-' + providerUri + (id || '')) || 'null'); } - return OAUTH3._hooks.directives.get(providerUri, id); + return OAUTH3._hooks.sessions.get(providerUri, id); } , _set: function (providerUri, newSession, id) { if (!OAUTH3._hooks || !OAUTH3._hooks.sessions || !OAUTH3._hooks.sessions.set) { @@ -612,7 +612,7 @@ window.sessionStorage.setItem('session-' + providerUri + (id || newSession.id || newSession.token.id || ''), JSON.stringify(newSession)); return newSession; } - return OAUTH3._hooks.directives.set(providerUri, newSession, id); + return OAUTH3._hooks.sessions.set(providerUri, newSession, id); } } } @@ -1087,7 +1087,11 @@ var result = { _clientUri: OAUTH3.clientUri(location) - , _providerUri: null + , _identityProviderUri: null + , _resourceProviderUri: null + , _identityProviderDirectives: null + , _resourceProviderDirectives: null + //, _resourceProviderMap: null // map between xyz.com and org.oauth3.domains , _init: function (location, opts) { var me = this; if (location) { @@ -1095,13 +1099,20 @@ } if (opts) { if (opts.providerUri) { - me._providerUri = opts.providerUri; + me._identityProviderUri = opts.providerUri; + me._resourceProviderUri = opts.providerUri; + } + if (opts.identityProviderUri) { + me._identityProviderUri = opts.identityProviderUri; + } + if (opts.resourceProviderUri) { + me._resourceProviderUri = opts.resourceProviderUri; } if (opts.session) { - if (!me._providerUri) { + if (!me._identityProviderUri) { throw new Error("'providerUri' was not supplied"); } - opts.session.provider_uri = me._providerUri; + opts.session.provider_uri = me._identityProviderUri; opts.session.client_uri = me._clientUri; me.session(opts.session, opts.sessionId); } @@ -1109,35 +1120,62 @@ } , init: function (location/*, opts*/) { var me = this; - var p = OAUTH3.PromiseA.resolve(); + var p1 = OAUTH3.PromiseA.resolve(); + var p2 = OAUTH3.PromiseA.resolve(); me._init(location, opts); - if (me._providerUri) { + if (me._identityProviderUri) { // returns directives - p = OAUTH3.discover(me._providerUri, { client_id: this._clientUri }); + p1 = OAUTH3.discover(me._identityProviderUri, { client_id: this._clientUri }); + } + if (me._resourceProviderUri) { + // returns directives + p2 = OAUTH3.discover(me._resourceProviderUri, { client_id: this._clientUri }); } - return p.then(function () { - return OAUTH3.discover(me._clientUri, { client_id: me._clientUri }).then(function (clientDirectives) { - me._clientDirectives = clientDirectives; - return clientDirectives; + return p1.then(function () { + return p2.then(function () { + return OAUTH3.discover(me._clientUri, { client_id: me._clientUri }).then(function (clientDirectives) { + me._clientDirectives = clientDirectives; + return clientDirectives; + }); }); }); } , setProvider: function (providerUri) { var me = this; - me._providerUri = providerUri; + return me.init().then(function () { + return me.setIdentityProvider(providerUri).then(function () { + // TODO how to say "Use xyz.com for org.oauth3.domains, but abc.com for org.oauth3.dns"? + return me.setResourceProvider(providerUri); + }); + }); + } + , setIdentityProvider: function (providerUri) { + var me = this; + me._identityProviderUri = providerUri; return me.init().then(function () { // this should be synchronous the second time around - return OAUTH3.discover(me._providerUri, { client_id: me._clientUri }).then(function (directives) { - me._providerDirectives = directives; + return OAUTH3.discover(me._identityProviderUri, { client_id: me._clientUri }).then(function (directives) { + me._identityProviderDirectives = directives; + return directives; + }); + }); + } + , setResourceProvider: function (providerUri) { + var me = this; + me._resourceProviderUri = providerUri; + return me.init().then(function () { + // this should be synchronous the second time around + return OAUTH3.discover(me._resourceProviderUri, { client_id: me._clientUri }).then(function (directives) { + me._resourceProviderDirectives = directives; return directives; }); }); } , checkSession: function () { - return OAUTH3.hooks.session.get(this._providerUri); + return OAUTH3.hooks.session.get(this._identityProviderUri); } , login: function (opts) { var me = this; @@ -1149,16 +1187,16 @@ opts = opts || {}; opts.client_uri = me._clientUri; - return OAUTH3.implicitGrant(me._providerDirectives, opts).then(function (session) { + return OAUTH3.implicitGrant(me._identityProviderDirectives, opts).then(function (session) { me._session = true; return session; }); } , session: function (session, id) { if (!session) { - return JSON.parse(JSON.stringify(OAUTH3.hooks.session._getCached(this._providerUri) || null)); + return JSON.parse(JSON.stringify(OAUTH3.hooks.session._getCached(this._identityProviderUri) || null)); } - return OAUTH3.hooks.session.set(this._providerUri, session, id); + return OAUTH3.hooks.session.set(this._identityProviderUri, session, id); } , request: function (preq, opts) { opts = opts || {}; @@ -1166,10 +1204,10 @@ preq.client_id = this._clientUri; preq.method = preq.method || 'GET'; if (this._session) { - preq.session = preq.session || this.session(); // OAUTH3.hooks.session._getCached(this._providerUri); + preq.session = preq.session || this.session(); // OAUTH3.hooks.session._getCached(this._identityProviderUri); } // TODO maybe use a baseUrl from the directives file? - preq.url = OAUTH3.url.resolve(this._providerUri, preq.url); + preq.url = OAUTH3.url.resolve(this._resourceProviderUri, preq.url); return OAUTH3.request(preq, opts); } @@ -1178,16 +1216,16 @@ opts = opts || {}; opts.client_uri = this._clientUri; opts.client_id = this._clientUri; - opts.session = OAUTH3.hooks.session._getCached(this._providerUri); + opts.session = OAUTH3.hooks.session._getCached(this._identityProviderUri); - return OAUTH3.logout(this._providerUri, opts); + return OAUTH3.logout(this._identityProviderUri, opts); } , api: function (api, opts) { opts = opts || {}; opts.api = api; - opts.session = OAUTH3.hooks.session._getCached(this._providerUri); + opts.session = OAUTH3.hooks.session._getCached(this._identityProviderUri); - return OAUTH3.api(this._providerDirectives.api, opts); + return OAUTH3.api(this._resourceProviderDirectives.api, opts); } }; result.authenticate = result.login; diff --git a/oauth3.crypto.js b/oauth3.crypto.js index a6559ab..67c27ff 100644 --- a/oauth3.crypto.js +++ b/oauth3.crypto.js @@ -188,7 +188,9 @@ return OAUTH3.PromiseA.reject(new Error('JWK of type '+jwk.kty+' missing fields ' + missing)); } - var jwkStr = '{' + keys.map(function (name) { return name+':'+jwk[name]; }).join(',') + '}'; + // I'm not actually 100% sure this behavior is guaranteed, but when we use an array as the + // replacer argument the keys are always in the order they appeared in the array. + var jwkStr = JSON.stringify(jwk, keys); return OAUTH3.crypto.core.sha256(OAUTH3._binStr.binStrToBuffer(jwkStr)) .then(OAUTH3._base64.bufferToUrlSafe); }; diff --git a/oauth3.domains.js b/oauth3.domains.js index 2b5b0b0..191f13c 100644 --- a/oauth3.domains.js +++ b/oauth3.domains.js @@ -45,6 +45,22 @@ OAUTH3.api['domains.list'] = function (providerUri, opts) { }); }; +// TODO: Manual Renew Function +OAUTH3.api['domains.extend'] = function (providerUri, opts) { + var session = opts.session; + + return OAUTH3.request({ + method: 'POST' + , url: OAUTH3.url.normalize(providerUri) + + '/api/com.daplie.domains/accounts/' + session.token.sub + '/registrations/' + opts.data.tld + '/' + opts.data.sld + '/extend' + , session: session + , data: opts.data + }).then(function (res) { + return res; + }); +}; + + OAUTH3.api['ns.list'] = function (providerUri, opts) { var session = opts.session; var domain = opts.domain; @@ -77,7 +93,7 @@ OAUTH3.api['ns.list'] = function (providerUri, opts) { }; OAUTH3.api['ns.add'] = function (providerUri, opts) { - var session = opts.session + var session = opts.session; var server = opts.server; var tld = opts.tld; var sld = opts.sld; diff --git a/oauth3.node.storage.js b/oauth3.node.storage.js index 22ee06b..370c678 100644 --- a/oauth3.node.storage.js +++ b/oauth3.node.storage.js @@ -9,6 +9,11 @@ var sessionsdir = path.join(oauth3dir, 'sessions'); var directivesdir = path.join(oauth3dir, 'directives'); var metadir = path.join(oauth3dir, 'meta'); +// We can reasonably assume the existence of the home directory, but we can't assume +// that there will already be a `.oauth3` directory or anything inside of it. +if (!fs.existsSync(path.join(oauth3dir, '..'))) { + fs.mkdirSync(path.join(oauth3dir, '..')); +} if (!fs.existsSync(oauth3dir)) { fs.mkdirSync(oauth3dir); }