Compare commits
	
		
			No commits in common. "master" and "remember-device" have entirely different histories.
		
	
	
		
			master
			...
			remember-d
		
	
		
| @ -1 +1 @@ | |||||||
| _apis | well-known | ||||||
							
								
								
									
										64
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								README.md
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ oauth3.js | |||||||
| | [issuer.html](https://git.oauth3.org/OAuth3/issuer.html) | | [issuer.html](https://git.oauth3.org/OAuth3/issuer.html) | ||||||
| | [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js) | | [issuer.rest.walnut.js](https://git.oauth3.org/OAuth3/issuer.rest.walnut.js) | ||||||
| | [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv) | | [issuer.srv](https://git.oauth3.org/OAuth3/issuer.srv) | ||||||
| | Sponsored by [ppl](https://ppl.family) | | Sponsored by [Daplie](https://daplie.com) | ||||||
| 
 | 
 | ||||||
| The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation | The world's smallest, fastest, and most secure OAuth3 (and OAuth2) JavaScript implementation | ||||||
| (Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!) | (Yes! works in browsers and node.js with no extra dependencies or bloat and no hacks!) | ||||||
| @ -29,7 +29,8 @@ If you have no idea what you're doing | |||||||
| 4. Download [oauth3.js-v1.zip](https://git.oauth3.org/OAuth3/oauth3.js/repository/archive.zip?ref=v1) | 4. Download [oauth3.js-v1.zip](https://git.oauth3.org/OAuth3/oauth3.js/repository/archive.zip?ref=v1) | ||||||
| 5. Double-click to unzip the folder. | 5. Double-click to unzip the folder. | ||||||
| 6. Copy the file `oauth3.core.js` into the folder `example.com/assets/oauth3.org/` | 6. Copy the file `oauth3.core.js` into the folder `example.com/assets/oauth3.org/` | ||||||
| 7. Copy the folder `_apis` into the folder `example.com/` | 7. Copy the folder `well-known` into the folder `example.com/` | ||||||
|  | 8. Rename the folder `well-known` to `.well-known` (when you do this, it become invisible, that's okay) | ||||||
| 9. Add `<script src="assets/oauth3.org/oauth3.core.js"></script>` to your `index.html` | 9. Add `<script src="assets/oauth3.org/oauth3.core.js"></script>` to your `index.html` | ||||||
| 9. Add `<script src="app.js"></script>` to your `index.html` | 9. Add `<script src="app.js"></script>` to your `index.html` | ||||||
| 10. Create files in `example.com` called `app.js` and `index.html` and put this in it: | 10. Create files in `example.com` called `app.js` and `index.html` and put this in it: | ||||||
| @ -58,13 +59,13 @@ If you have no idea what you're doing | |||||||
| `app.js`: | `app.js`: | ||||||
| ```js | ```js | ||||||
| var OAUTH3 = window.OAUTH3; | var OAUTH3 = window.OAUTH3; | ||||||
| var oauth3 = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id) | var auth = OAUTH3.create(window.location); // use window.location to set Client URI (your app's id) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // this is any OAuth3-compatible provider, such as oauth3.org | // this is any OAuth3-compatible provider, such as oauth3.org | ||||||
| // in v1.1.0 we'll add backwards compatibility for facebook.com, google.com, etc | // in v1.1.0 we'll add backwards compatibility for facebook.com, google.com, etc | ||||||
| // | // | ||||||
| function onChangeProvider(providerUri) { | function onChangeProvider(_providerUri) { | ||||||
|   // example https://oauth3.org |   // example https://oauth3.org | ||||||
|   return oauth3.setIdentityProvider(providerUri); |   return oauth3.setIdentityProvider(providerUri); | ||||||
| } | } | ||||||
| @ -86,13 +87,11 @@ function onClickLogin() { | |||||||
|     console.info('Secure PPID (aka subject):', session.token.sub); |     console.info('Secure PPID (aka subject):', session.token.sub); | ||||||
| 
 | 
 | ||||||
|     return oauth3.request({ |     return oauth3.request({ | ||||||
|       url: 'https://api.oauth3.org/api/issuer@oauth3.org/jwks/:sub/:kid' |       url: 'https://oauth3.org/api/issuer@oauth3.org/inspect' | ||||||
|         .replace(/:sub/g, session.token.sub) |  | ||||||
|         .replace(/:kid/g, session.token.kid || session.token.iss) |  | ||||||
|     , session: session |     , session: session | ||||||
|     }).then(function (resp) { |     }).then(function (resp) { | ||||||
| 
 | 
 | ||||||
|       console.info("Signing Public Key JWK:"); |       console.info("Inspect Token:"); | ||||||
|       console.log(resp.data); |       console.log(resp.data); | ||||||
| 
 | 
 | ||||||
|     }); |     }); | ||||||
| @ -145,13 +144,13 @@ it might look like this: | |||||||
| example.com | example.com | ||||||
| │ | │ | ||||||
| │ | │ | ||||||
| ├── _apis | ├── .well-known (hidden) | ||||||
| │   └── oauth3.org | │   └── oauth3 | ||||||
| │       ├── callback.html | │       ├── callback.html | ||||||
| │       ├── directives.json | │       ├── directives.json | ||||||
| │       └── index.html | │       └── index.html | ||||||
| ├── assets | ├── assets | ||||||
| │   └── oauth3.org | │   └── org.oauth3 | ||||||
| │       └── oauth3.core.js | │       └── oauth3.core.js | ||||||
| │ | │ | ||||||
| │ | │ | ||||||
| @ -172,17 +171,17 @@ Installation (if you know what you're doing) | |||||||
| pushd /path/to/your/web/app | pushd /path/to/your/web/app | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # clone the project as assets/oauth3.org | # clone the project as assets/org.oauth3 | ||||||
| mkdir -p assets | mkdir -p assets | ||||||
| git clone git@git.oauth3.org:OAuth3/oauth3.js.git assets/oauth3.org | git clone git@git.daplie.com:OAuth3/oauth3.js.git assets/org.oauth3 | ||||||
| pushd assets/oauth3.org | pushd assets/org.oauth3 | ||||||
| git checkout v1 | git checkout v1 | ||||||
| popd | popd | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # symlink `_apis/oauth3.org` to `assets/oauth3.org/_apis/oauth3.org` | # symlink `.well-known/oauth3` to `assets/org.oauth3/.well-known/oauth3` | ||||||
| mkdir -p _apis | mkdir -p .well-known | ||||||
| ln -sf  ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org | ln -sf  ../assets/org.oauth3/.well-known/oauth3 .well-known/oauth3 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| **Advanced Installation with `bower`** | **Advanced Installation with `bower`** | ||||||
| @ -192,17 +191,17 @@ ln -sf  ../assets/oauth3.org/_apis/oauth3 _apis/oauth3.org | |||||||
| bower install oauth3 | bower install oauth3 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # create a `_apis` folder and an `assets` folder | # create a `.well-known` folder and an `assets` folder | ||||||
| mkdir -p _apis assets | mkdir -p .well-known assets | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # symlink `_apis/oauth3.org` to `bower_components/oauth3.org/_apis/oauth3.org` | # symlink `.well-known/oauth3` to `bower_components/oauth3/.well-known/oauth3` | ||||||
| ln -sf  ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org | ln -sf  ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # symlink `assets/oauth3.org` to `bower_components/oauth3.org` | # symlink `assets/org.oauth3` to `bower_components/oauth3` | ||||||
| ln -sf  ../bower_components/oauth3.org/_apis/oauth3.org _apis/oauth3.org | ln -sf  ../bower_components/oauth3/.well-known/oauth3 .well-known/oauth3 | ||||||
| ln -sf  ../bower_components/oauth3.org assets/oauth3.org | ln -sf  ../bower_components/oauth3 assets/org.oauth3 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Usage | Usage | ||||||
| @ -211,7 +210,7 @@ Usage | |||||||
| Update your HTML to include the the following script tag: | Update your HTML to include the the following script tag: | ||||||
| 
 | 
 | ||||||
| ```html | ```html | ||||||
| <script src="assets/oauth3.org/oauth3.core.js"></script> | <script src="assets/org.oauth3/oauth3.core.js"></script> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| You can create a very simple demo application like this: | You can create a very simple demo application like this: | ||||||
| @ -290,7 +289,7 @@ You're all set. Nothing else is needed. | |||||||
| We've created an `Oauth3` service just for you: | We've created an `Oauth3` service just for you: | ||||||
| 
 | 
 | ||||||
| ```html | ```html | ||||||
| <script src="assets/oauth3.org/oauth3.ng.js"></script> | <script src="assets/org.oauth3/oauth3.ng.js"></script> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| @ -323,7 +322,7 @@ promise = oauth3.init(opts);                        // set and fetch your own si | |||||||
| // promises your site's config                      // opts = { location, session, issuer, audience } | // promises your site's config                      // opts = { location, session, issuer, audience } | ||||||
| 
 | 
 | ||||||
| promise = oauth3.setIdentityProvider(url);          // changes the Identity Provider URI (the site you're logging into), | 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 _apis/oauth3.org), | // 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 |                                                     // and caches it in internal state as the default | ||||||
| 
 | 
 | ||||||
| promise = oauth3.setResourceProvider(url);          // changes the Resource Provider URI (the site you're getting stuff from) | promise = oauth3.setResourceProvider(url);          // changes the Resource Provider URI (the site you're getting stuff from) | ||||||
| @ -340,11 +339,12 @@ promise = oauth3.request({ url, method, data });    // make an (authorized) arbi | |||||||
|                                                     // (contacts, photos, whatever) |                                                     // (contacts, photos, whatever) | ||||||
| 
 | 
 | ||||||
| promise = oauth3.api(apiname, opts);                // make an (authorized) well-known api call to an audience | promise = oauth3.api(apiname, opts);                // make an (authorized) well-known api call to an audience | ||||||
|                                                     // Ex: oauth3.api('dns.list', { sld: 'example', tld: 'com' }); |                                                     // See https://labs.daplie.com/docs/ for API schemas | ||||||
|  |                                                     // Ex: oauth3.api('dns.list', { sld: 'daplie', tld: 'com' }); | ||||||
| 
 | 
 | ||||||
| // TODO | // TODO | ||||||
| api = await oauth3.package(audience, schemaname);   // make an (authorized) well-known api call to an audience | api = await oauth3.package(audience, schemaname);   // make an (authorized) well-known api call to an audience | ||||||
|                                                     // Ex: api = await oauth3.package('domains.example.com', 'dns@oauth3.org'); |                                                     // Ex: api = await oauth3.package('domains.daplie.com', 'dns@oauth3.org'); | ||||||
|                                                     //     api.list({ sld: 'mydomain', tld: 'com' }); |                                                     //     api.list({ sld: 'mydomain', tld: 'com' }); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -353,10 +353,6 @@ promise = oauth3.logout();                          // opens logout window for t | |||||||
| oauth3.session();                                   // returns the current session, if any | oauth3.session();                                   // returns the current session, if any | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| <!-- TODO |  | ||||||
| Track down the old https://labs.daplie.com/docs/ for API schemas |  | ||||||
| -- |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| Real API | Real API | ||||||
| ---------- | ---------- | ||||||
| @ -498,5 +494,5 @@ can be very ugly and confusing and we definitely need to allow relative paths. | |||||||
| 
 | 
 | ||||||
| A potential work-around would be to assume all paths are relative (eliminate #4 instead) | A potential work-around would be to assume all paths are relative (eliminate #4 instead) | ||||||
| and have the path always key off of the base URL - if oauth3 directives are to be found at | and have the path always key off of the base URL - if oauth3 directives are to be found at | ||||||
| https://example.com/username/_apis/oauth3.org/index.json then /api/whatever would refer | https://example.com/username/.well-known/oauth3/directives.json then /api/whatever would refer | ||||||
| to https://example.com/username/api/whatever. | to https://example.com/username/api/whatever. | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 43 B | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 43 B | 
| @ -1,140 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html> |  | ||||||
|   <head> |  | ||||||
|     <style> |  | ||||||
|       body { |  | ||||||
|         background-color: #ffcccc; |  | ||||||
|       } |  | ||||||
|     </style> |  | ||||||
|   </head> |  | ||||||
|   <body> |  | ||||||
|   OAuth3 RPC |  | ||||||
| 
 |  | ||||||
|   <script src="../../assets/oauth3.org/oauth3.core.js"></script> |  | ||||||
|   <script> |  | ||||||
|     ;(function () { |  | ||||||
|     'use strict'; |  | ||||||
| 
 |  | ||||||
|     // Taken from oauth3.core.js |  | ||||||
| 
 |  | ||||||
|     // 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); |  | ||||||
|     var urlsafe64; |  | ||||||
|     var redirect; |  | ||||||
|     var err; |  | ||||||
|     var oldRpc; |  | ||||||
|     var sub = params.sub || params.subject; |  | ||||||
|     var subData; |  | ||||||
| 
 |  | ||||||
|     function doRedirect(redirect) { |  | ||||||
|       if (params.debug) { |  | ||||||
|         console.log(prefix, 'params.redirect_uri:', params.redirect_uri); |  | ||||||
|         console.log(prefix, 'redirect'); |  | ||||||
|         console.log(redirect); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       if (!params.debug) { |  | ||||||
|         window.location = redirect; |  | ||||||
|       } else { |  | ||||||
|         // yes, we're violating the security lint with purpose |  | ||||||
|         document.body.innerHTML += window.location.host + window.location.pathname |  | ||||||
|           + '<br/><br/>You\'ve passed the \'debug\' parameter so we\'re pausing' |  | ||||||
|           + ' to let you look at logs or whatever it is that you intended to do.' |  | ||||||
|           + '<br/><br/>Continue with redirect: <a href="' + 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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var loco = window.location.href.replace(/\/\.well-known.*/, ''); |  | ||||||
|     //var loco = 'sso.hellabit.com'; |  | ||||||
|     var resp; |  | ||||||
|     if (/localstorage/i.test(params._scheme)) { |  | ||||||
|       if (sub) { |  | ||||||
|         subData = localStorage.getItem(sub + '@oauth3.org:issuer'); |  | ||||||
|       } |  | ||||||
|       resp = subData || localStorage.getItem('oauth3.org:issuer') || loco; |  | ||||||
|       onSuccess(resp, subData && true); |  | ||||||
|       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: params._pathname.replace(/^\.well-known\/oauth3\//, '') }).then(function (resp) { |  | ||||||
|       urlsafe64 = OAUTH3._base64.encodeUrlSafe(JSON.stringify(resp.data, null, 0)); |  | ||||||
| 
 |  | ||||||
|       onSuccess(urlsafe64); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     }()); |  | ||||||
|   </script> |  | ||||||
|   </body> |  | ||||||
| </html> |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| { |  | ||||||
| 
 |  | ||||||
|       "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" |  | ||||||
|     } |  | ||||||
| @ -1,96 +0,0 @@ | |||||||
| (function () { |  | ||||||
| 'use strict'; |  | ||||||
| 
 |  | ||||||
| function create(myOpts) { |  | ||||||
|   return { |  | ||||||
|     requestScope: function (opts) { |  | ||||||
|       // TODO pre-generate URL
 |  | ||||||
| 
 |  | ||||||
|       // deliver existing session if it exists
 |  | ||||||
|       var scope = opts && opts.scope || []; |  | ||||||
|       if (myOpts.session) { |  | ||||||
|         if (!scope.length || scope.every(function (scp) { |  | ||||||
|           return -1 !== opts.myOpts.session.scope.indexOf(scp); |  | ||||||
|         })) { |  | ||||||
|           return OAUTH3.PromiseA.resolve(myOpts.session); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       // request a new session otherwise
 |  | ||||||
|       return OAUTH3.implicitGrant(myOpts.directives, { |  | ||||||
|         client_id: myOpts.conf.client_uri |  | ||||||
|       , client_uri: myOpts.conf.client_uri |  | ||||||
|         // maybe use inline instead?
 |  | ||||||
|       , windowType: 'popup' |  | ||||||
|       , scope: scope |  | ||||||
|       }).then(function (session) { |  | ||||||
|         return session; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   , session: function () { |  | ||||||
|       return myOpts.session; |  | ||||||
|     } |  | ||||||
|   , refresh: function (session) { |  | ||||||
|       return OAUTH3.implicitGrant(myOpts.directives, { |  | ||||||
|         client_id: myOpts.conf.client_uri |  | ||||||
|       , client_uri: myOpts.conf.client_uri |  | ||||||
|       , windowType: 'background' |  | ||||||
|       }).then(function (_session) { |  | ||||||
|         session = _session; |  | ||||||
|         return session; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   , logout: function () { |  | ||||||
|       return OAUTH3.logout(myOpts.directives, { |  | ||||||
|         client_id: myOpts.conf.client_uri |  | ||||||
|       , client_uri: myOpts.conf.client_uri |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   , switchUser: function () { |  | ||||||
|       // should open dialog with user selection dialog
 |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| window.navigator.auth = { |  | ||||||
|   getUserAuthenticator: function (opts) { |  | ||||||
|     var conf = {}; |  | ||||||
|     var directives; |  | ||||||
|     var session; |  | ||||||
| 
 |  | ||||||
|     opts = opts || {}; |  | ||||||
|     conf.client_uri = opts.client_uri || OAUTH3.clientUri(opts.location || window.location); |  | ||||||
| 
 |  | ||||||
|     return OAUTH3.issuer({ broker: opts.issuer_uri || 'https://new.oauth3.org' }).then(function (issuer) { |  | ||||||
|       conf.issuer_uri = issuer; |  | ||||||
|       conf.provider_uri = issuer; |  | ||||||
| 
 |  | ||||||
|       return OAUTH3.directives(conf.provider_uri, { |  | ||||||
|         client_id: conf.client_uri |  | ||||||
|       , client_uri: conf.client_uri |  | ||||||
|       }).then(function (_directives) { |  | ||||||
|         directives = _directives; |  | ||||||
|         var myOpts = { |  | ||||||
|           directives: directives |  | ||||||
|         , conf: conf |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         return OAUTH3.implicitGrant(directives, { |  | ||||||
|           client_id: conf.client_uri |  | ||||||
|         , client_uri: conf.client_uri |  | ||||||
|         , windowType: 'background' |  | ||||||
|         }).then(function (_session) { |  | ||||||
|           session = _session; |  | ||||||
|           myOpts.session = session; |  | ||||||
|           return create(myOpts); |  | ||||||
|         }, function (err) { |  | ||||||
|           console.error('[DEBUG] implicitGrant err:'); |  | ||||||
|           console.error(err); |  | ||||||
|           return create(myOpts); |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| }()); |  | ||||||
							
								
								
									
										268
									
								
								oauth3.core.js
									
									
									
									
									
								
							
							
						
						
									
										268
									
								
								oauth3.core.js
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| / * global Promise */ | /* global Promise */ | ||||||
| ;(function (exports) { | ;(function (exports) { | ||||||
|   'use strict'; |   'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -169,7 +169,7 @@ | |||||||
|     } |     } | ||||||
|   , scope: { |   , scope: { | ||||||
|       parse: function (scope) { |       parse: function (scope) { | ||||||
|         return (scope||'').toString().split(/[+, ]+/g); |         return (scope||'').split(/[+, ]+/g); | ||||||
|       } |       } | ||||||
|     , stringify: function (scope) { |     , stringify: function (scope) { | ||||||
|         if (Array.isArray(scope)) { |         if (Array.isArray(scope)) { | ||||||
| @ -294,46 +294,34 @@ | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   , urls: { |   , urls: { | ||||||
|       rpc: function (providerUri, opts) { |       discover: function (providerUri, opts) { | ||||||
|         if (!providerUri) { |         if (!providerUri) { | ||||||
|           throw new Error("cannot run rpc without providerUri"); |           throw new Error("cannot discover without providerUri"); | ||||||
|         } |         } | ||||||
|         if (!opts.client_id) { |         if (!opts.client_id) { | ||||||
|           throw new Error("cannot run rpc without options.client_id"); |           throw new Error("cannot discover without options.client_id"); | ||||||
|         } |         } | ||||||
|         var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri); |         var clientId = OAUTH3.url.normalize(opts.client_id || opts.client_uri); | ||||||
|         providerUri = OAUTH3.url.normalize(providerUri); |         providerUri = OAUTH3.url.normalize(providerUri); | ||||||
| 
 | 
 | ||||||
|         var params = { |         var params = { | ||||||
|           state: opts.state || OAUTH3.utils.randomState() |           action: 'directives' | ||||||
|  |         , state: opts.state || OAUTH3.utils.randomState() | ||||||
|         , redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/') |         , redirect_uri: clientId + (opts.client_callback_path || '/.well-known/oauth3/callback.html#/') | ||||||
|         , response_type: 'rpc' |         , response_type: 'rpc' | ||||||
|         , _method: 'GET' |         , _method: 'GET' | ||||||
|         , _scheme: opts._scheme |         , _pathname: '.well-known/oauth3/directives.json' | ||||||
|         , _pathname: opts._pathname |  | ||||||
|         , debug: opts.debug || undefined |         , debug: opts.debug || undefined | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         var toRequest = { |         var result = { | ||||||
|           url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.query.stringify(params) |           url: providerUri + '/.well-known/oauth3/#/?' + OAUTH3.query.stringify(params) | ||||||
|         , state: params.state |         , state: params.state | ||||||
|         , method: 'GET' |         , method: 'GET' | ||||||
|         , query: params |         , query: params | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         return toRequest; |         return result; | ||||||
|       } |  | ||||||
|     , broker: function (providerUri, opts) { |  | ||||||
|         opts._scheme = "localstorage:"; |  | ||||||
|         opts._pathname = "issuer"; |  | ||||||
|         return OAUTH3.urls.rpc(providerUri, opts); |  | ||||||
|       } |  | ||||||
|     , 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) { |     , implicitGrant: function (directive, opts) { | ||||||
|         //
 |         //
 | ||||||
| @ -542,14 +530,6 @@ | |||||||
|           return OAUTH3.PromiseA.resolve(OAUTH3._hooks.directives.clear()); |           return OAUTH3.PromiseA.resolve(OAUTH3._hooks.directives.clear()); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     , scopes: { |  | ||||||
|         get: function(providerUri) { |  | ||||||
|           //TODO: retrieve cached scopes
 |  | ||||||
|         } |  | ||||||
|       , set: function(providerUri, scopes) { |  | ||||||
|           //TODO: cache scopes
 |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     , session: { |     , session: { | ||||||
|         refresh: function (oldSession, newSession) { |         refresh: function (oldSession, newSession) { | ||||||
|           var providerUri = oldSession.provider_uri; |           var providerUri = oldSession.provider_uri; | ||||||
| @ -678,29 +658,9 @@ | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   , discoverScopes: function (providerUri, opts) { |  | ||||||
|       return OAUTH.scopes(providerUri, opts); |  | ||||||
|     } |  | ||||||
|   , scopes: function (providerUri, opts) { |  | ||||||
|       if (!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) { |   , discover: function (providerUri, opts) { | ||||||
|       return OAUTH3.directives(providerUri, opts); |  | ||||||
|     } |  | ||||||
|   , directives: function (providerUri, opts) { |  | ||||||
|       if (!providerUri) { |       if (!providerUri) { | ||||||
|         throw new Error('oauth3.discover(providerUri, opts) received providerUri as :', providerUri); |         throw new Error('oauth3.discover(providerUri, opts) received providerUri as ' + providerUri); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       return OAUTH3.hooks.directives.get(providerUri).then(function (directives) { |       return OAUTH3.hooks.directives.get(providerUri).then(function (directives) { | ||||||
| @ -708,8 +668,7 @@ | |||||||
|           return directives; |           return directives; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         opts._pathname = ".well-known/oauth3/directives.json"; |         return OAUTH3._discoverHelper(providerUri, opts).then(function (directives) { | ||||||
|         return OAUTH3._rpcHelper(providerUri, opts).then(function (directives) { |  | ||||||
|           directives.azp = directives.azp || OAUTH3.url.normalize(providerUri); |           directives.azp = directives.azp || OAUTH3.url.normalize(providerUri); | ||||||
|           directives.issuer = directives.issuer || 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))); |           directives.api = OAUTH3.url.normalize((directives.api||':hostname').replace(/:hostname/, OAUTH3.uri.normalize(directives.issuer) || OAUTH3.uri.normalize(providerUri))); | ||||||
| @ -718,8 +677,8 @@ | |||||||
|         }); |         }); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   , _rpcHelper: function(providerUri, opts) { |   , _discoverHelper: function(providerUri, opts) { | ||||||
|       return OAUTH3._browser.rpc(providerUri, opts); |       return OAUTH3._browser.discover(providerUri, opts); | ||||||
|     } |     } | ||||||
|   , request: function (preq, opts) { |   , request: function (preq, opts) { | ||||||
|       function fetch() { |       function fetch() { | ||||||
| @ -747,22 +706,7 @@ | |||||||
|       */ |       */ | ||||||
|       return OAUTH3._browser.request(preq, opts); |       return OAUTH3._browser.request(preq, opts); | ||||||
|     } |     } | ||||||
|   , issuer: function (opts) { |   , implicitGrant: function(directives, opts) { | ||||||
|       if (!opts) { opts = {}; } |  | ||||||
| 
 |  | ||||||
|       // TODO this will default to browserlogin.org
 |  | ||||||
|       var broker = opts.broker || 'https://new.oauth3.org'; |  | ||||||
|       //var broker = opts.broker || 'https://broker.oauth3.org';
 |  | ||||||
| 
 |  | ||||||
|       opts._rpc = "broker"; |  | ||||||
|       opts._scheme = "localstorage:"; |  | ||||||
|       opts._pathname = "issuer"; |  | ||||||
| 
 |  | ||||||
|       return OAUTH3._rpcHelper(broker, opts).then(function(issuer) { |  | ||||||
|         return issuer; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   , implicitGrant: function (directives, opts) { |  | ||||||
|       var promise; |       var promise; | ||||||
|       var providerUri = directives.azp || directives.issuer || directives; |       var providerUri = directives.azp || directives.issuer || directives; | ||||||
| 
 | 
 | ||||||
| @ -872,19 +816,12 @@ | |||||||
|         }); |         }); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   , logout: function(issuerUri, opts) { |   , logout: function(providerUri, opts) { | ||||||
|       var directives; |       return OAUTH3.hooks.directives.get(providerUri).then(function (directives) { | ||||||
|       if ('string' !== typeof issuerUri) { |  | ||||||
|         directives = issuerUri; |  | ||||||
|         return OAUTH3._logoutHelper(directives, opts); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return OAUTH3.hooks.directives.get(issuerUri).then(function (directives) { |  | ||||||
|         return OAUTH3._logoutHelper(directives, opts); |         return OAUTH3._logoutHelper(directives, opts); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   , _logoutHelper: function(directives, opts) { |   , _logoutHelper: function(providerUri, directives, opts) { | ||||||
|       var issuerUri = directives.issuer_uri || directives.provider_uri; |  | ||||||
|       var logoutReq = OAUTH3.urls.logout( |       var logoutReq = OAUTH3.urls.logout( | ||||||
|         directives |         directives | ||||||
|       , { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location)) |       , { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location)) | ||||||
| @ -907,10 +844,10 @@ | |||||||
| 
 | 
 | ||||||
|         if (params.error) { |         if (params.error) { | ||||||
|           // TODO directives.audience
 |           // TODO directives.audience
 | ||||||
|           return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*issuerUri*/, params)); |           return OAUTH3.PromiseA.reject(OAUTH3.error.parse(directives.issuer /*providerUri*/, params)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         OAUTH3.hooks.session.clear(issuerUri); |         OAUTH3.hooks.session.clear(providerUri); | ||||||
|         return params; |         return params; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
| @ -921,50 +858,40 @@ | |||||||
|     //
 |     //
 | ||||||
|   , _browser: { |   , _browser: { | ||||||
|       window: 'undefined' !== typeof window ? window : null |       window: 'undefined' !== typeof window ? window : null | ||||||
|     , rpc: function(providerUri, opts) { |       // TODO we don't need to include this if we're using jQuery or angular
 | ||||||
|  |     , discover: function(providerUri, opts) { | ||||||
|         opts = opts || {}; |         opts = opts || {}; | ||||||
|         providerUri = OAUTH3.url.normalize(providerUri); |         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)) { |         if (OAUTH3.uri.normalize(providerUri).replace(/\/.*/, '') === OAUTH3.uri.normalize(OAUTH3._browser.window.location.hostname)) { | ||||||
|           console.warn("It looks like you're a provider trying to run rpc on yourself," |           console.warn("It looks like you're a provider checking for your own directive," | ||||||
|             + " so we we're just gonna use" |             + " so we we're just gonna use" | ||||||
|             + " OAUTH3.request({ method: 'GET', url: " |             + " OAUTH3.request({ method: 'GET', url: '.well-known/oauth3/directive.json' })"); | ||||||
|             + "'" + opts._pathname + "' })"); |           return OAUTH3.request({ | ||||||
| 
 |             method: 'GET' | ||||||
|           if (/localstorage/i.test(opts._scheme)) { |           , url: OAUTH3.url.normalize(providerUri) + '/.well-known/oauth3/directives.json' | ||||||
|             return OAUTH3.PromiseA.resolve(localStorage.getItem(opts._pathname)); |           }).then(function (resp) { | ||||||
|           } |             return resp.data; | ||||||
|           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)) { |         if (!(opts.client_id || opts.client_uri).match(OAUTH3._browser.window.location.hostname)) { | ||||||
|           console.warn("It looks like your client_id doesn't match your current window..." |           console.warn("It looks like your client_id doesn't match your current window..." | ||||||
|             + " this probably won't end well"); |             + " this probably won't end well"); | ||||||
|           console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname); |           console.warn(opts.client_id || opts.client_uri, OAUTH3._browser.window.location.hostname); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         var discReq = OAUTH3.urls[opts._rpc || 'rpc']( |         var discReq = OAUTH3.urls.discover( | ||||||
|           providerUri |           providerUri | ||||||
|         , { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location)) |         , { client_id: (opts.client_id || opts.client_uri || OAUTH3.clientUri(OAUTH3._browser.window.location)) | ||||||
|           , windowType: opts.broker && opts.windowType || 'background' |           , windowType: opts.broker && opts.windowType || 'background' | ||||||
|           , broker: opts.broker |           , broker: opts.broker | ||||||
|           , state: opts._state || undefined |           , state: opts._state || undefined | ||||||
|           , debug: opts.debug |           , debug: opts.debug | ||||||
|           , _scheme: opts._scheme |  | ||||||
|           , _pathname: opts._pathname |  | ||||||
|           , _method: opts._method |  | ||||||
|           } |           } | ||||||
|         ); |         ); | ||||||
|         opts._state = discReq.state; |         opts._state = discReq.state; | ||||||
|         //var discReq = OAUTH3.urls.rpc(providerUri, opts);
 |         //var discReq = OAUTH3.urls.discover(providerUri, opts);
 | ||||||
| 
 | 
 | ||||||
|         // hmm... we're gonna need a broker for this since switching windows is distracting,
 |         // 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
 |         // popups are obnoxious, iframes are sometimes blocked, and most servers don't implement CORS
 | ||||||
| @ -974,36 +901,27 @@ | |||||||
|         // TODO allow node to open a desktop browser window
 |         // TODO allow node to open a desktop browser window
 | ||||||
|         opts._windowType = opts.windowType; |         opts._windowType = opts.windowType; | ||||||
|         opts.windowType = opts.windowType || 'background'; |         opts.windowType = opts.windowType || 'background'; | ||||||
|         return OAUTH3._browser.testPixel(providerUri).then(function () { |         return OAUTH3._browser.frameRequest( | ||||||
|           return OAUTH3._browser.frameRequest( |           OAUTH3.url.resolve(providerUri, discReq.url) | ||||||
|             OAUTH3.url.resolve(providerUri, discReq.url) |         , discReq.state | ||||||
|           , discReq.state |           // why not just pass opts whole?
 | ||||||
|             // why not just pass opts whole?
 |         , { windowType: opts.windowType | ||||||
|           , { windowType: opts.windowType |           , reuseWindow: opts.broker && '-broker' | ||||||
|             , reuseWindow: opts.broker && '-broker' |           , debug: opts.debug | ||||||
|             , debug: opts.debug |           } | ||||||
|             } |         ).then(function (params) { | ||||||
|           ).then(function (params) { |           opts.windowType = opts._windowType; | ||||||
|             opts.windowType = opts._windowType; |  | ||||||
| 
 | 
 | ||||||
|             // caller will call OAUTH3._browser.closeFrame(discReq.state, { debug: opts.debug || params.debug });
 |           // caller will call OAUTH3._browser.closeFrame(discReq.state, { debug: opts.debug || params.debug });
 | ||||||
|             if (params.error) { |           if (params.error) { | ||||||
|               // TODO directives.issuer || directives.audience
 |             // TODO directives.issuer || directives.audience
 | ||||||
|               return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, params)); |             return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, params)); | ||||||
|             } |           } | ||||||
| 
 | 
 | ||||||
|             // TODO params should have response_type indicating json, binary, etc
 |           // TODO params should have response_type indicating json, binary, etc
 | ||||||
|             var result; |           var directives = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.result || params.directives)); | ||||||
|             try { |           // caller will call OAUTH3.hooks.directives.set(providerUri, directives);
 | ||||||
|               result = JSON.parse(OAUTH3._base64.decodeUrlSafe(params.data || params.result || params.directives)); |           return directives; | ||||||
|             } catch(e) { |  | ||||||
|               result = params.data || params.result; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             console.log('result:', result); |  | ||||||
|             // caller will call OAUTH3.hooks.directives.set(providerUri, directives);
 |  | ||||||
|             return result; |  | ||||||
|           }); |  | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     , request: function (preq, _sys) { |     , request: function (preq, _sys) { | ||||||
| @ -1102,28 +1020,6 @@ | |||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     , testPixel: function (targetUri) { |  | ||||||
|         var url = OAUTH3.url.resolve(OAUTH3.url.normalize(targetUri), '.well-known/oauth3/clear.gif'); |  | ||||||
|         return new OAUTH3.PromiseA(function (resolve, reject) { |  | ||||||
|           var img = document.createElement('img'); |  | ||||||
|           img.addEventListener('load', function () { |  | ||||||
|             resolve(); |  | ||||||
|           }); |  | ||||||
|           img.addEventListener('error', function () { |  | ||||||
|             var err = new Error("OAuth3 support not detected: '" + url + "' not found"); |  | ||||||
|             err.code = 'E_NOT_SUPPORTED'; |  | ||||||
|             reject(err); |  | ||||||
|           }); |  | ||||||
|           // works with CSP
 |  | ||||||
|           img.style.position = 'absolute'; |  | ||||||
|           img.style.left = '-2px'; |  | ||||||
|           img.style.bottom = '-2px'; |  | ||||||
|           img.className = 'js-oauth3-discover'; |  | ||||||
|           img.src = url; |  | ||||||
|           document.body.appendChild(img); |  | ||||||
|           console.log('img', img); |  | ||||||
|         }); |  | ||||||
|       } |  | ||||||
|     , frameRequest: function (url, state, opts) { |     , frameRequest: function (url, state, opts) { | ||||||
|         opts = opts || {}; |         opts = opts || {}; | ||||||
|         var previousFrame = OAUTH3._browser._frames[state]; |         var previousFrame = OAUTH3._browser._frames[state]; | ||||||
| @ -1134,10 +1030,11 @@ | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         var timeout = opts.timeout; |         var timeout = opts.timeout; | ||||||
|         if ('background' === windowType) { |         if (opts.debug) { | ||||||
|           if (!timeout) { |           timeout = timeout || 3 * 60 * 1000; | ||||||
|             timeout = 7 * 1000; |         } | ||||||
|           } |         else { | ||||||
|  |           timeout = timeout || ('background' === windowType ? 15 * 1000 : 3 * 60 * 1000); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return new OAUTH3.PromiseA(function (resolve, reject) { |         return new OAUTH3.PromiseA(function (resolve, reject) { | ||||||
| @ -1159,16 +1056,14 @@ | |||||||
|             cleanup(); |             cleanup(); | ||||||
|           }; |           }; | ||||||
| 
 | 
 | ||||||
|           if (timeout) { |           tok = setTimeout(function () { | ||||||
|             tok = setTimeout(function () { |             var err = new Error( | ||||||
|               var err = new Error( |               "the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s" | ||||||
|                 "the '" + windowType + "' request did not complete within " + Math.round(timeout / 1000) + "s" |             ); | ||||||
|               ); |             err.code = "E_TIMEOUT"; | ||||||
|               err.code = "E_TIMEOUT"; |             reject(err); | ||||||
|               reject(err); |             cleanup(); | ||||||
|               cleanup(); |           }, timeout); | ||||||
|             }, timeout); |  | ||||||
|           } |  | ||||||
| 
 | 
 | ||||||
|           setTimeout(function () { |           setTimeout(function () { | ||||||
|             if (!OAUTH3._browser._frames[state]) { |             if (!OAUTH3._browser._frames[state]) { | ||||||
| @ -1371,23 +1266,6 @@ | |||||||
|   OAUTH3.utils = { |   OAUTH3.utils = { | ||||||
|     clientUri: OAUTH3.clientUri |     clientUri: OAUTH3.clientUri | ||||||
|   , query: OAUTH3.query |   , query: OAUTH3.query | ||||||
|   , parseSubject: function (sub) { |  | ||||||
|       var parts = sub.split('@'); |  | ||||||
|       var issuer; |  | ||||||
|       var subject; |  | ||||||
| 
 |  | ||||||
|       if (/@/.test(sub)) { |  | ||||||
|         // The username may have a single @, the provider may not
 |  | ||||||
|         // user@thing.com@whatever.com -> user@thing.com, whatever.com
 |  | ||||||
|         issuer = parts.pop(); |  | ||||||
|         subject = parts.join('@'); |  | ||||||
|       } else { |  | ||||||
|         //subject = '';
 |  | ||||||
|         issuer = parts.join('@'); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return { subject: subject, issuer: issuer }; |  | ||||||
|     } |  | ||||||
|   , scope: OAUTH3.scope |   , scope: OAUTH3.scope | ||||||
|   , uri: OAUTH3.uri |   , uri: OAUTH3.uri | ||||||
|   , url: OAUTH3.url |   , url: OAUTH3.url | ||||||
| @ -1555,25 +1433,23 @@ | |||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     , logout: function (opts) { |     , logout: function (opts) { | ||||||
|         var me = this; |         this._session = false; | ||||||
|         me._session = false; |  | ||||||
|         opts = opts || {}; |         opts = opts || {}; | ||||||
|         return OAUTH3.hooks.session.get(me._identityProviderUri).then(function (session) { |         return OAUTH3.hooks.session.get(this._identityProviderUri).then(function (session) { | ||||||
|           opts.client_uri = me._clientUri; |           opts.client_uri = this._clientUri; | ||||||
|           opts.client_id = me._clientUri; |           opts.client_id = this._clientUri; | ||||||
|           opts.session = session; |           opts.session = session; | ||||||
| 
 | 
 | ||||||
|           return OAUTH3.logout(me._identityProviderUri, opts); |           return OAUTH3.logout(this._identityProviderUri, opts); | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     , api: function (api, opts) { |     , api: function (api, opts) { | ||||||
|         var me = this; |  | ||||||
|         opts = opts || {}; |         opts = opts || {}; | ||||||
|         return OAUTH3.hooks.session.get(me._identityProviderUri).then(function (session) { |         return OAUTH3.hooks.session.get(this._identityProviderUri).then(function (session) { | ||||||
|           opts.api = api; |           opts.api = api; | ||||||
|           opts.session = session; |           opts.session = session; | ||||||
| 
 | 
 | ||||||
|           return OAUTH3.api(me._resourceProviderDirectives.api, opts); |           return OAUTH3.api(this._resourceProviderDirectives.api, opts); | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     , pkg: function (pkgname) { |     , pkg: function (pkgname) { | ||||||
|  | |||||||
							
								
								
									
										142
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								oauth3.issuer.js
									
									
									
									
									
								
							| @ -192,9 +192,8 @@ OAUTH3.urls.grants = function (directive, opts) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var url = OAUTH3.url.resolve(directive.api, grantsDir.url) |   var url = OAUTH3.url.resolve(directive.api, grantsDir.url) | ||||||
|  |     .replace(/(:azp|:client_id)/g, OAUTH3.uri.normalize(opts.client_id || opts.client_uri)) | ||||||
|     .replace(/(:sub|:account_id)/g, opts.session.token.sub || 'ISSUER:GRANT:TOKEN_SUB:UNDEFINED') |     .replace(/(:sub|:account_id)/g, opts.session.token.sub || 'ISSUER:GRANT:TOKEN_SUB:UNDEFINED') | ||||||
|     .replace(/(:azp|:client_id)/g, !opts.all && OAUTH3.uri.normalize(opts.client_id || opts.client_uri) || '') |  | ||||||
|     .replace(/\/\/$/, '/') // if there's a double slash due to the sub not existing
 |  | ||||||
|     ; |     ; | ||||||
|   var data = { |   var data = { | ||||||
|     client_id: opts.client_id |     client_id: opts.client_id | ||||||
| @ -218,7 +217,6 @@ OAUTH3.urls.grants = function (directive, opts) { | |||||||
|   , session: opts.session |   , session: opts.session | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| //OAUTH3.urls.accessToken = function (directive, opts)
 |  | ||||||
| OAUTH3.urls.clientToken = function (directive, opts) { | OAUTH3.urls.clientToken = function (directive, opts) { | ||||||
|   var tokenDir = directive.access_token; |   var tokenDir = directive.access_token; | ||||||
|   if (!tokenDir) { |   if (!tokenDir) { | ||||||
| @ -289,25 +287,21 @@ OAUTH3.urls.publishKey = function (directive, opts) { | |||||||
|   , session: opts.session |   , session: opts.session | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| OAUTH3.urls.credentialMeta = function (directive, opts) { |  | ||||||
|   return OAUTH3.url.resolve(directive.api, directive.credential_meta.url) |  | ||||||
|       .replace(':type', 'email') |  | ||||||
|       .replace(':id', opts.email) |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| OAUTH3.authn = OAUTH3.authn || {}; | OAUTH3.authn = {}; | ||||||
| OAUTH3.authn.loginMeta = function (directive, opts) { | OAUTH3.authn.loginMeta = function (directive, opts) { | ||||||
|   var url = OAUTH3.urls.credentialMeta(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
 | ||||||
|     // TODO client_uri
 |     // TODO client_uri
 | ||||||
|   , url: url |   , url: OAUTH3.url.resolve(directive.api, directive.credential_meta.url) | ||||||
|  |       .replace(':type', 'email') | ||||||
|  |       .replace(':id', opts.email) | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| OAUTH3.urls.otp = function (directive, opts) { | OAUTH3.authn.otp = function (directive, opts) { | ||||||
|   // TODO client_uri
 |   // TODO client_uri
 | ||||||
|   return { |   var preq = { | ||||||
|     method: directive.credential_otp.method || 'POST' |     method: directive.credential_otp.method || 'POST' | ||||||
|   , url: OAUTH3.url.resolve(directive.api, directive.credential_otp.url) |   , url: OAUTH3.url.resolve(directive.api, directive.credential_otp.url) | ||||||
|   , data: { |   , data: { | ||||||
| @ -320,9 +314,6 @@ OAUTH3.urls.otp = function (directive, opts) { | |||||||
|     , username: opts.email |     , username: opts.email | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| }; |  | ||||||
| OAUTH3.authn.otp = function (directive, opts) { |  | ||||||
|   var preq = OAUTH3.urls.otp(directive, opts); |  | ||||||
| 
 | 
 | ||||||
|   return OAUTH3.request(preq); |   return OAUTH3.request(preq); | ||||||
| }; | }; | ||||||
| @ -371,8 +362,8 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) { | |||||||
| OAUTH3.authz = {}; | OAUTH3.authz = {}; | ||||||
| OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | ||||||
|   var clientUri = OAUTH3.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 || 'authn@oauth3.org'; |   var scope = clientParams.scope || 'oauth3_authn'; | ||||||
|   if ('authn@oauth3.org' === scope.toString()) { |   if ('oauth3_authn' === scope) { | ||||||
|     // implicit ppid grant is automatic
 |     // implicit ppid grant is automatic
 | ||||||
|     console.warn('[security] fix scope checking on backend so that we can do automatic grants'); |     console.warn('[security] fix scope checking on backend so that we can do automatic grants'); | ||||||
|     // TODO check user preference if implicit ppid grant is allowed
 |     // TODO check user preference if implicit ppid grant is allowed
 | ||||||
| @ -434,7 +425,7 @@ OAUTH3.authz.grants = function (providerUri, opts) { | |||||||
|     } |     } | ||||||
|     // the responses for GET and POST requests are now the same, so we should alway be able to
 |     // the responses for GET and POST requests are now the same, so we should alway be able to
 | ||||||
|     // use the response and save it the same way.
 |     // use the response and save it the same way.
 | ||||||
|     if (opts.all || ('GET' !== opts.method && 'POST' !== opts.method)) { |     if ('GET' !== opts.method && 'POST' !== opts.method) { | ||||||
|       return grants; |       return grants; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -574,85 +565,68 @@ OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, s | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| OAUTH3.requests = {}; | OAUTH3.requests = {}; | ||||||
| //OAUTH3.accounts = {};
 |  | ||||||
| OAUTH3.requests.accounts = {}; | OAUTH3.requests.accounts = {}; | ||||||
| OAUTH3.urls.accounts = {}; | OAUTH3.requests.accounts.update = function (directive, session, opts) { | ||||||
| OAUTH3.urls.accounts._ = function (directives, directive, session, opts) { |   var dir = directive.update_account || { | ||||||
|   opts = opts || {}; |     method: 'POST' | ||||||
|   var dir = directive || { |   , url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts/:accountId' | ||||||
|      //url: OAUTH3.url.normalize(directives.api) + '/api/issuer@oauth3.org/accounts/:accountId'
 |  | ||||||
|      url: OAUTH3.url.normalize(directives.api) + '/api/issuer@oauth3.org/acl/profiles/:accountId' |  | ||||||
|   //, method: 'GET'
 |  | ||||||
|   , bearer: 'Bearer' |   , bearer: 'Bearer' | ||||||
|   }; |   }; | ||||||
|   var url = dir.url |   var url = dir.url | ||||||
|     .replace(/:accountId/, opts.accountId || '') |     .replace(/:accountId/, opts.accountId) | ||||||
|     .replace(/\/$/, '') |  | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
|   return { |   return OAUTH3.request({ | ||||||
|     url: url |     method: dir.method || 'POST' | ||||||
|     //, method: dir.method || 'POST'
 |   , url: url | ||||||
|   , session: session |  | ||||||
|     /* |  | ||||||
|   , headers: { |   , headers: { | ||||||
|       'Authorization': (dir.bearer || 'Bearer') + ' ' + (session.access_token || session.accessToken) |       'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken | ||||||
|     } |     } | ||||||
|     */ |   , json: { | ||||||
|   }; |       name: opts.name | ||||||
|  |     , comment: opts.comment | ||||||
|  |     , displayName: opts.displayName | ||||||
|  |     , priority: opts.priority | ||||||
|  |     } | ||||||
|  |   }); | ||||||
| }; | }; | ||||||
| OAUTH3.urls.accounts.get = function (directives, session) { | OAUTH3.requests.accounts.create = function (directive, session, account) { | ||||||
|   var urlObj = OAUTH3.urls.accounts._(directives, directives.account, session); |   var dir = directive.create_account || { | ||||||
|   urlObj.method = (directives.account || { method: 'GET' }).method; |     method: 'POST' | ||||||
|   return urlObj; |   , url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts' | ||||||
| }; |   , bearer: 'Bearer' | ||||||
| OAUTH3.urls.accounts.update = function (directives, session, opts) { |  | ||||||
|   var urlObj = OAUTH3.urls.accounts._(directives, directives.update_account, session, opts); |  | ||||||
|   urlObj.method = (directives.update_account || { method: 'POST' }).method; |  | ||||||
|   urlObj.json = { |  | ||||||
|     name: opts.name |  | ||||||
|   , comment: opts.comment |  | ||||||
|   , displayName: opts.displayName |  | ||||||
|   , priority: opts.priority |  | ||||||
|   }; |   }; | ||||||
|   return urlObj; |   var data = { | ||||||
| }; |  | ||||||
| OAUTH3.urls.accounts.create = function (directives, session, account) { |  | ||||||
|   var urlObj = OAUTH3.urls.accounts._(directives, directives.create_account, session); |  | ||||||
|   var profile = { |  | ||||||
|     nick: account.display_name |  | ||||||
|     // "name" is unique and what would be reserved in a url {{name}}.issuer.org or issuer.org/users/{{name}}
 |  | ||||||
|   , name: account.name |  | ||||||
|   , comment: account.comment |  | ||||||
|   , display_name: account.display_name |  | ||||||
|   , priority: account.priority |  | ||||||
|   }; |  | ||||||
|   var credentials = [ { token: session.access_token } ]; |  | ||||||
|   urlObj.method = (directives.create_account || { method: 'POST' }).method; |  | ||||||
|   urlObj.json = { |  | ||||||
|     // TODO fix the server to just use one scheme
 |     // TODO fix the server to just use one scheme
 | ||||||
|     // account = { nick, self: { comment, username } }
 |     // account = { nick, self: { comment, username } }
 | ||||||
|     // account = { name, comment, display_name, priority }
 |     // account = { name, comment, display_name, priority }
 | ||||||
|     credentials: credentials |     account: { | ||||||
|   , profile: profile |       nick: account.display_name | ||||||
|     // 'account' is deprecated in favor of 'profile'
 |     , name: account.name | ||||||
|   , account: profile |     , comment: account.comment | ||||||
|     // 'logins' is deprecated in favor of 'credentials'
 |     , display_name: account.display_name | ||||||
|   , logins: credentials |     , priority: account.priority | ||||||
|  |     , self: { | ||||||
|  |         nick: account.display_name | ||||||
|  |       , name: account.name | ||||||
|  |       , comment: account.comment | ||||||
|  |       , display_name: account.display_name | ||||||
|  |       , priority: account.priority | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   , logins: [ | ||||||
|  |       { | ||||||
|  |         token: session.access_token | ||||||
|  |       } | ||||||
|  |     ] | ||||||
|   }; |   }; | ||||||
|   return urlObj; | 
 | ||||||
| }; |   return OAUTH3.request({ | ||||||
| OAUTH3.requests.accounts.get = function (directives, session) { |     method: dir.method || 'POST' | ||||||
|   var urlObj = OAUTH3.urls.accounts.get(directives, session); |   , url: dir.url | ||||||
|   return OAUTH3.request(urlObj); |   , session: session | ||||||
| }; |   , data: data | ||||||
| OAUTH3.requests.accounts.update = function (directives, session, opts) { |   }); | ||||||
|   var urlObj = OAUTH3.urls.accounts.update(directives, session, opts); |  | ||||||
|   return OAUTH3.request(urlObj); |  | ||||||
| }; |  | ||||||
| OAUTH3.requests.accounts.create = function (directive, session, account) { |  | ||||||
|   var urlObj = OAUTH3.urls.accounts.create(directives, session, account); |  | ||||||
|   return OAUTH3.request(urlObj); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| OAUTH3.hooks.grants = { | OAUTH3.hooks.grants = { | ||||||
|  | |||||||
| @ -27,10 +27,10 @@ | |||||||
| 
 | 
 | ||||||
|   OAUTH3.authz.scopes = function () { |   OAUTH3.authz.scopes = function () { | ||||||
|     return OAUTH3.PromiseA.resolve({ |     return OAUTH3.PromiseA.resolve({ | ||||||
|       pending: [ 'authn@oauth3.org' ]     // not yet accepted
 |       pending: ['oauth3_authn']   // not yet accepted
 | ||||||
|     , granted: []                         // all granted, ever
 |     , granted: []                 // all granted, ever
 | ||||||
|     , requested: [ 'authn@oauth3.org' ]   // all requested, now
 |     , requested: ['oauth3_authn'] // all requested, now
 | ||||||
|     , accepted: []                        // granted (ever) and requested (now)
 |     , accepted: []                // granted (ever) and requested (now)
 | ||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
|   OAUTH3.authz.grants = function (providerUri, opts) { |   OAUTH3.authz.grants = function (providerUri, opts) { | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| _apis |  | ||||||
							
								
								
									
										71
									
								
								well-known/oauth3/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								well-known/oauth3/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  |   <head> | ||||||
|  |     <style> | ||||||
|  |       body { | ||||||
|  |         background-color: #ffcccc; | ||||||
|  |       } | ||||||
|  |     </style> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |   OAuth3 RPC | ||||||
|  | 
 | ||||||
|  |   <script src="../../assets/oauth3.org/oauth3.core.js"></script> | ||||||
|  |   <script> | ||||||
|  |     ;(function () { | ||||||
|  |     'use strict'; | ||||||
|  | 
 | ||||||
|  |     // Taken from oauth3.core.js | ||||||
|  | 
 | ||||||
|  |     // 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."); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     console.log(prefix, 'hash||search:'); | ||||||
|  |     console.log(window.location.hash || window.location.search); | ||||||
|  | 
 | ||||||
|  |     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 { | ||||||
|  |         // yes, we're violating the security lint with purpose | ||||||
|  |         document.body.innerHTML += window.location.host + window.location.pathname | ||||||
|  |           + '<br/><br/>You\'ve passed the \'debug\' parameter so we\'re pausing' | ||||||
|  |           + ' to let you look at logs or whatever it is that you intended to do.' | ||||||
|  |           + '<br/><br/>Continue with redirect: <a href="' + redirect + '">' + redirect + '</' + 'a>'; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     }()); | ||||||
|  |   </script> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user