| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | ;(function (exports) { | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-27 18:19:01 -07:00
										 |  |  | var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3; | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | OAUTH3.url.parse = function (url) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   // TODO browser
 | 
					
						
							|  |  |  |   // Node should replace this
 | 
					
						
							|  |  |  |   var parser = document.createElement('a'); | 
					
						
							|  |  |  |   parser.href = url; | 
					
						
							|  |  |  |   return parser; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | OAUTH3.url._isRedirectHostSafe = function (referrerUrl, redirectUrl) { | 
					
						
							|  |  |  |   var src = OAUTH3.url.parse(referrerUrl); | 
					
						
							|  |  |  |   var dst = OAUTH3.url.parse(redirectUrl); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   // TODO how should we handle subdomains?
 | 
					
						
							|  |  |  |   // It should be safe for api.example.com to redirect to example.com
 | 
					
						
							|  |  |  |   // But it may not be safe for to example.com to redirect to aj.example.com
 | 
					
						
							|  |  |  |   // It is also probably not safe for sally.example.com to redirect to john.example.com
 | 
					
						
							|  |  |  |   // The client should have a list of allowed URLs to choose from and perhaps a wildcard will do
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // api.example.com.evil.com SHOULD NOT match example.com
 | 
					
						
							|  |  |  |   return dst.hostname === src.hostname; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | OAUTH3.url.checkRedirect = function (client, query) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   console.warn("[security] URL path checking not yet implemented"); | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   if (!query) { | 
					
						
							|  |  |  |     query = client; | 
					
						
							|  |  |  |     client = query.client_uri; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   client = client.url || client; | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   // it doesn't matter who the referrer is as long as the destination
 | 
					
						
							|  |  |  |   // is an authorized destination for the client in question
 | 
					
						
							|  |  |  |   // (though it may not hurt to pass the referrer's info on to the client)
 | 
					
						
							|  |  |  |   var clientUrl = OAUTH3.url.normalize(client); | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |   var redirectUrl = OAUTH3.url.normalize(query.redirect_uri); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // General rule:
 | 
					
						
							|  |  |  |   // I can callback to a shorter domain (fewer subs) or a shorter path (on the same domain)
 | 
					
						
							|  |  |  |   // but not a longer (more subs) or different domain or a longer path (on the same domain)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // We can callback to an explicitly listed domain (TODO and path)
 | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |   if (OAUTH3.url._isRedirectHostSafe(clientUrl, redirectUrl)) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   var callbackUrl = 'https://oauth3.org/docs/errors#E_REDIRECT_ATTACK?'+OAUTH3.query.stringify({ | 
					
						
							|  |  |  |     'redirect_uri': redirectUrl | 
					
						
							|  |  |  |   , 'allowed_urls': clientUrl | 
					
						
							|  |  |  |   , 'client_id':    client | 
					
						
							|  |  |  |   , 'referrer_uri': OAUTH3.uri.normalize(window.document.referrer) | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   if (query.debug) { | 
					
						
							|  |  |  |     console.log('Redirect Attack'); | 
					
						
							|  |  |  |     console.log(query); | 
					
						
							|  |  |  |     window.alert("DEBUG MODE checkRedirect error encountered. Check the console."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   location.href = callbackUrl; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   return false; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | OAUTH3.url.redirect = function (clientParams, grants, tokenOrError) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   // TODO OAUTH3.redirect(clientParams, grants, tokenOrError)
 | 
					
						
							|  |  |  |   // TODO check redirect safeness right here with grants.client.urls
 | 
					
						
							|  |  |  |   // TODO check for '#' and '?'. If none, issue warning and use '?' (for backwards compat)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var authz = { | 
					
						
							|  |  |  |     access_token: tokenOrError.access_token | 
					
						
							|  |  |  |   , token_type: tokenOrError.token_type         // 'Bearer'
 | 
					
						
							|  |  |  |   , refresh_token: tokenOrError.refresh_token | 
					
						
							|  |  |  |   , expires_in: tokenOrError.expires_in         // 1800 (but superceded by jwt.exp)
 | 
					
						
							|  |  |  |   , scope: tokenOrError.scope                   // superceded by jwt.scp
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   , state: clientParams.state | 
					
						
							|  |  |  |   , debug: clientParams.debug | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if (tokenOrError.error) { | 
					
						
							|  |  |  |     authz.error = tokenOrError.error.code || tokenOrError.error; | 
					
						
							|  |  |  |     authz.error_description = tokenOrError.error.message || tokenOrError.error_description; | 
					
						
							|  |  |  |     authz.error_uri = tokenOrError.error.uri || tokenOrError.error_uri; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |   var redirect = clientParams.redirect_uri + '#' + window.OAUTH3.query.stringify(authz); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if (clientParams.debug) { | 
					
						
							|  |  |  |     console.info('final redirect_uri:', redirect); | 
					
						
							|  |  |  |     window.alert("You're in debug mode so we've taken a pause. Hit OK to continue"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   window.location = redirect; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OAUTH3.urls.resourceOwnerPassword = function (directive, opts) { | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // Example Resource Owner Password Request
 | 
					
						
							|  |  |  |   // (generally for 1st party and direct-partner mobile apps, and webapps)
 | 
					
						
							|  |  |  |   //
 | 
					
						
							| 
									
										
										
										
											2017-08-15 20:21:54 +00:00
										 |  |  |   // POST https://example.com/api/issuer@oauth3.org/access_token
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   //    { "grant_type": "password", "client_id": "<<id>>", "scope": "<<scope>>"
 | 
					
						
							|  |  |  |   //    , "username": "<<username>>", "password": "password" }
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   opts = opts || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!opts.password) { | 
					
						
							|  |  |  |     if (opts.otp) { | 
					
						
							|  |  |  |       // for backwards compat
 | 
					
						
							|  |  |  |       opts.password = opts.otp; // 'otp:' + opts.otpUuid + ':' + opts.otp;
 | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var args = directive.access_token; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined; | 
					
						
							| 
									
										
										
										
											2017-03-21 01:02:41 -06:00
										 |  |  |   // TODO require user agent
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   var params = { | 
					
						
							| 
									
										
										
										
											2017-02-24 15:05:07 -05:00
										 |  |  |     client_id: opts.client_id || opts.client_uri | 
					
						
							|  |  |  |   , client_uri: opts.client_uri | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   , grant_type: 'password' | 
					
						
							| 
									
										
										
										
											2017-02-24 15:05:07 -05:00
										 |  |  |   , username: opts.username | 
					
						
							|  |  |  |   , password: opts.password || otpCode || undefined | 
					
						
							|  |  |  |   , totp: opts.totp || opts.totpToken || opts.totp_token || undefined | 
					
						
							|  |  |  |   , otp: otpCode | 
					
						
							|  |  |  |   , password_type: otpCode && 'otp' | 
					
						
							|  |  |  |   , otp_code: otpCode | 
					
						
							|  |  |  |   , otp_uuid: opts.otpUuid || opts.otp_uuid || undefined | 
					
						
							|  |  |  |   , user_agent: opts.userAgent || opts.useragent || opts.user_agent || undefined // AJ's Macbook
 | 
					
						
							|  |  |  |   , jwk: (opts.rememberDevice || opts.remember_device) && opts.jwk || undefined | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   //, "public_key": opts.rememberDevice && opts.publicKey || undefined
 | 
					
						
							|  |  |  |   //, "public_key_type":  opts.rememberDevice && opts.publicKeyType || undefined // RSA/ECDSA
 | 
					
						
							|  |  |  |   //, "jwt": opts.jwt // TODO sign a proof with a previously loaded public_key
 | 
					
						
							|  |  |  |   , debug: opts.debug || undefined | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   if (opts.client_uri) { | 
					
						
							|  |  |  |     params.clientAgreeTos = 'oauth3.org/tos/draft'; // opts.clientAgreeTos || opts.client_agree_tos;
 | 
					
						
							|  |  |  |     if (!params.clientAgreeTos) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |       throw new Error('Developer Error: missing clientAgreeTos uri'); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var scope = opts.scope || directive.authn_scope; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if (scope) { | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |     params.scope = OAUTH3.scope.stringify(scope); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var uri = args.url; | 
					
						
							|  |  |  |   var body; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if ('GET' === args.method.toUpperCase()) { | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |     uri += '?' + OAUTH3.query.stringify(params); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     body = params; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							| 
									
										
										
										
											2017-05-24 01:00:07 +00:00
										 |  |  |     url: OAUTH3.url.resolve(directive.api, uri) | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   , method: args.method | 
					
						
							|  |  |  |   , data: body | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | OAUTH3.urls.grants = function (directive, opts) { | 
					
						
							|  |  |  |   // directive = { issuer, authorization_decision }
 | 
					
						
							|  |  |  |   // opts = { response_type, scopes{ granted, requested, pending, accepted } }
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var grantsDir = directive.grants; | 
					
						
							|  |  |  |   if (!grantsDir) { | 
					
						
							|  |  |  |     throw new Error("provider doesn't support grants"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if (!opts) { | 
					
						
							|  |  |  |     throw new Error("You must supply a directive and an options object."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.client_id) { | 
					
						
							|  |  |  |     throw new Error("You must supply options.client_id."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.session) { | 
					
						
							|  |  |  |     throw new Error("You must supply options.session."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.referrer) { | 
					
						
							|  |  |  |     console.warn("You should supply options.referrer"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.method) { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |     console.warn("You should supply options.method as either 'GET', or 'POST'"); | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |     opts.method = grantsDir.method || 'GET'; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   if ('POST' === opts.method) { | 
					
						
							|  |  |  |     if ('string' !== typeof opts.scope) { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |       throw new Error("You must supply options.scope as a comma-delimited string of scopes"); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |     if ('string' !== typeof opts.sub) { | 
					
						
							|  |  |  |       console.log("provide 'sub' to urls.grants to specify the PPID for the client"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var url = OAUTH3.url.resolve(directive.api, grantsDir.url) | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |     .replace(/(:azp|:client_id)/g, OAUTH3.uri.normalize(opts.client_id || opts.client_uri)) | 
					
						
							| 
									
										
										
										
											2017-03-22 20:13:06 -04:00
										 |  |  |     .replace(/(:sub|:account_id)/g, opts.session.token.sub || 'ISSUER:GRANT:TOKEN_SUB:UNDEFINED') | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     ; | 
					
						
							|  |  |  |   var data = { | 
					
						
							|  |  |  |     client_id: opts.client_id | 
					
						
							|  |  |  |   , client_uri: opts.client_uri | 
					
						
							|  |  |  |   , referrer: opts.referrer | 
					
						
							|  |  |  |   , scope: opts.scope | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   , sub: opts.sub | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   var body; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   if ('GET' === opts.method) { | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |     url += '?' + OAUTH3.query.stringify(data); | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     body = data; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   return { | 
					
						
							|  |  |  |     method: opts.method | 
					
						
							|  |  |  |   , url: url | 
					
						
							|  |  |  |   , data: body | 
					
						
							|  |  |  |   , session: opts.session | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  | OAUTH3.urls.clientToken = function (directive, opts) { | 
					
						
							|  |  |  |   var tokenDir = directive.access_token; | 
					
						
							|  |  |  |   if (!tokenDir) { | 
					
						
							|  |  |  |     throw new Error("provider doesn't support getting access tokens"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!opts) { | 
					
						
							|  |  |  |     throw new Error("You must supply a directive and an options object."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!(opts.azp || opts.client_id)) { | 
					
						
							|  |  |  |     throw new Error("You must supply options.client_id."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.session) { | 
					
						
							|  |  |  |     throw new Error("You must supply options.session."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.method) { | 
					
						
							|  |  |  |     opts.method = tokenDir.method || 'POST'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var params = { | 
					
						
							|  |  |  |     grant_type: 'issuer_token' | 
					
						
							|  |  |  |   , client_id:  opts.azp || opts.client_id | 
					
						
							|  |  |  |   , azp: opts.azp || opts.client_id | 
					
						
							|  |  |  |   , aud: opts.aud | 
					
						
							|  |  |  |   , exp: opts.exp | 
					
						
							|  |  |  |   , refresh_token: opts.refresh_token | 
					
						
							|  |  |  |   , refresh_exp: opts.refresh_exp | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var url = OAUTH3.url.resolve(directive.api, tokenDir.url); | 
					
						
							|  |  |  |   var body; | 
					
						
							|  |  |  |   if ('GET' === opts.method) { | 
					
						
							|  |  |  |     url += '?' + OAUTH3.query.stringify(params); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     body = params; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     method: opts.method | 
					
						
							|  |  |  |   , url: url | 
					
						
							|  |  |  |   , data: body | 
					
						
							|  |  |  |   , session: opts.session | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:19 -06:00
										 |  |  | OAUTH3.urls.publishKey = function (directive, opts) { | 
					
						
							|  |  |  |   var jwkDir = directive.publish_jwk; | 
					
						
							|  |  |  |   if (!jwkDir) { | 
					
						
							|  |  |  |     throw new Error("provider doesn't support publishing public keys"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts) { | 
					
						
							|  |  |  |     throw new Error("You must supply a directive and an options object."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!opts.session) { | 
					
						
							|  |  |  |     throw new Error("You must supply 'options.session'."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!(opts.public_key || opts.publicKey)) { | 
					
						
							|  |  |  |     throw new Error("You must supply 'options.public_key'."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var url = OAUTH3.url.resolve(directive.api, jwkDir.url) | 
					
						
							|  |  |  |     .replace(/(:sub|:account_id)/g, opts.session.token.sub) | 
					
						
							|  |  |  |     ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     method: jwkDir.method || opts.method || 'POST' | 
					
						
							|  |  |  |   , url: url | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |   , data: opts.public_key || opts.publicKey | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:19 -06:00
										 |  |  |   , session: opts.session | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | OAUTH3.authn = {}; | 
					
						
							| 
									
										
										
										
											2017-02-21 12:15:58 -07:00
										 |  |  | OAUTH3.authn.loginMeta = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   return OAUTH3.request({ | 
					
						
							|  |  |  |     method: directive.credential_meta.method || 'GET' | 
					
						
							|  |  |  |     // TODO lint urls
 | 
					
						
							| 
									
										
										
										
											2017-03-21 01:02:41 -06:00
										 |  |  |     // TODO client_uri
 | 
					
						
							| 
									
										
										
										
											2017-05-24 01:00:07 +00:00
										 |  |  |   , url: OAUTH3.url.resolve(directive.api, directive.credential_meta.url) | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |       .replace(':type', 'email') | 
					
						
							|  |  |  |       .replace(':id', opts.email) | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 12:15:58 -07:00
										 |  |  | OAUTH3.authn.otp = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-03-21 01:02:41 -06:00
										 |  |  |   // TODO client_uri
 | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  |   var preq = { | 
					
						
							|  |  |  |     method: directive.credential_otp.method || 'POST' | 
					
						
							| 
									
										
										
										
											2017-05-24 01:00:07 +00:00
										 |  |  |   , url: OAUTH3.url.resolve(directive.api, directive.credential_otp.url) | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   , data: { | 
					
						
							|  |  |  |       // TODO replace with signed hosted file
 | 
					
						
							|  |  |  |       client_agree_tos: 'oauth3.org/tos/draft' | 
					
						
							| 
									
										
										
										
											2017-03-21 01:02:41 -06:00
										 |  |  |       // TODO unbreak the client_uri option (if broken)
 | 
					
						
							|  |  |  |     , client_id: /*opts.client_id ||*/ OAUTH3.uri.normalize(directive.issuer) // In this case, the issuer is its own client
 | 
					
						
							|  |  |  |     , client_uri: /*opts.client_uri ||*/ OAUTH3.uri.normalize(directive.issuer) | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     , request_otp: true | 
					
						
							|  |  |  |     , username: opts.email | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-02-24 14:18:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  |   return OAUTH3.request(preq); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 12:15:58 -07:00
										 |  |  | OAUTH3.authn.resourceOwnerPassword = function (directive, opts) { | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   var providerUri = directive.issuer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:19 -06:00
										 |  |  |   return OAUTH3.request(OAUTH3.urls.resourceOwnerPassword(directive, opts)).then(function (resp) { | 
					
						
							|  |  |  |     var data = resp.data; | 
					
						
							|  |  |  |     data.provider_uri = providerUri; | 
					
						
							|  |  |  |     if (data.error) { | 
					
						
							|  |  |  |       return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, data)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.hooks.session.refresh( | 
					
						
							|  |  |  |       opts.session || { provider_uri: providerUri, client_uri: opts.client_uri || opts.clientUri } | 
					
						
							|  |  |  |     , data | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   }).then(function (session) { | 
					
						
							|  |  |  |     if (!opts.rememberDevice && !opts.remember_device) { | 
					
						
							|  |  |  |       return session; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve().then(function () { | 
					
						
							|  |  |  |       if (!OAUTH3.crypto) { | 
					
						
							|  |  |  |         throw new Error("OAuth3 crypto library unavailable"); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-24 14:18:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:19 -06:00
										 |  |  |       return OAUTH3.crypto.createKeyPair().then(function (keyPair) { | 
					
						
							|  |  |  |         return OAUTH3.request(OAUTH3.urls.publishKey(directive, { | 
					
						
							|  |  |  |           session: session | 
					
						
							|  |  |  |         , publicKey: keyPair.publicKey | 
					
						
							|  |  |  |         })).then(function () { | 
					
						
							|  |  |  |           return OAUTH3.hooks.keyPairs.set(session.token.sub, keyPair); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }).then(function () { | 
					
						
							|  |  |  |       return session; | 
					
						
							|  |  |  |     }, function (err) { | 
					
						
							|  |  |  |       console.error('failed to save keys to remember device', err); | 
					
						
							|  |  |  |       window.alert('Failed to remember device'); | 
					
						
							|  |  |  |       return session; | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | OAUTH3.authz = {}; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | OAUTH3.authz.scopes = function (providerUri, session, clientParams) { | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  |   var clientUri = OAUTH3.uri.normalize(clientParams.client_uri || OAUTH3._browser.window.document.referrer); | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   var scope = clientParams.scope || 'oauth3_authn'; | 
					
						
							|  |  |  |   if ('oauth3_authn' === scope) { | 
					
						
							|  |  |  |     // implicit ppid grant is automatic
 | 
					
						
							|  |  |  |     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
 | 
					
						
							|  |  |  |     //return generateToken(session, clientObj);
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |   return OAUTH3.hooks.grants.get(session.token.sub, clientUri).then(function (granted) { | 
					
						
							|  |  |  |     if (granted) { | 
					
						
							|  |  |  |       if (typeof granted.scope === 'string') { | 
					
						
							|  |  |  |         return OAUTH3.scope.parse(granted.scope); | 
					
						
							|  |  |  |       } else if (Array.isArray(granted.scope)) { | 
					
						
							|  |  |  |         return granted.scope; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.authz.grants(providerUri, { | 
					
						
							|  |  |  |       method: 'GET' | 
					
						
							|  |  |  |     , client_id: clientUri | 
					
						
							|  |  |  |     , client_uri: clientUri | 
					
						
							|  |  |  |     , session: session | 
					
						
							|  |  |  |     }).then(function (results) { | 
					
						
							|  |  |  |       return results.grants; | 
					
						
							|  |  |  |     }, function (err) { | 
					
						
							|  |  |  |       if (!/no .*grants .*found/i.test(err.message)) { | 
					
						
							|  |  |  |         throw err; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return []; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   }).then(function (granted) { | 
					
						
							|  |  |  |     var requested = OAUTH3.scope.parse(scope); | 
					
						
							|  |  |  |     var accepted = []; | 
					
						
							|  |  |  |     var pending = []; | 
					
						
							|  |  |  |     requested.forEach(function (scp) { | 
					
						
							|  |  |  |       if (granted.indexOf(scp) < 0) { | 
					
						
							|  |  |  |         pending.push(scp); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         accepted.push(scp); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |       requested: requested  // all requested, now
 | 
					
						
							|  |  |  |     , granted:   granted    // all granted, ever
 | 
					
						
							|  |  |  |     , accepted:  accepted   // intersection of granted (ever) and requested (now)
 | 
					
						
							|  |  |  |     , pending:   pending     // not yet accepted
 | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | OAUTH3.authz.grants = function (providerUri, opts) { | 
					
						
							|  |  |  |   return OAUTH3.discover(providerUri, { | 
					
						
							|  |  |  |     client_id: providerUri | 
					
						
							|  |  |  |   , debug: opts.debug | 
					
						
							|  |  |  |   }).then(function (directive) { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |     return OAUTH3.request(OAUTH3.urls.grants(directive, opts), opts); | 
					
						
							|  |  |  |   }).then(function (grantsResult) { | 
					
						
							|  |  |  |     var grants = grantsResult.originalData || grantsResult.data; | 
					
						
							|  |  |  |     if (grants.error) { | 
					
						
							|  |  |  |       return OAUTH3.PromiseA.reject(OAUTH3.error.parse(providerUri, grants)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |     // 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.
 | 
					
						
							|  |  |  |     if ('GET' !== opts.method && 'POST' !== opts.method) { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |       return grants; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |     OAUTH3.hooks.grants.set(grants.sub, grants.azp, grants); | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |     return { | 
					
						
							|  |  |  |       client: grants.azp | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |     , clientSub: grants.azpSub | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |     , grants: OAUTH3.scope.parse(grants.scope) | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  | function calcExpiration(exp, now) { | 
					
						
							|  |  |  |   if (!exp) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (typeof exp === 'string') { | 
					
						
							|  |  |  |     var match = /^(\d+\.?\d*) *(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(exp); | 
					
						
							|  |  |  |     if (!match) { | 
					
						
							|  |  |  |       return now; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var num = parseFloat(match[1]); | 
					
						
							|  |  |  |     var type = (match[2] || 's').toLowerCase()[0]; | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |       case 'y': num *= 365.25; /* falls through */ | 
					
						
							|  |  |  |       case 'd': num *= 24;     /* falls through */ | 
					
						
							|  |  |  |       case 'h': num *= 60;     /* falls through */ | 
					
						
							|  |  |  |       case 'm': num *= 60;     /* falls through */ | 
					
						
							|  |  |  |       case 's': exp = num; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (typeof exp !== 'number') { | 
					
						
							|  |  |  |     throw new Error('invalid expiration provided: '+exp); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   now = now || Math.floor(Date.now() / 1000); | 
					
						
							|  |  |  |   if (exp > now) { | 
					
						
							|  |  |  |     return exp; | 
					
						
							|  |  |  |   } else if (exp > 31557600) { | 
					
						
							|  |  |  |     console.warn('tried to set expiration to more that a year'); | 
					
						
							|  |  |  |     exp = 31557600; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return now + exp; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | OAUTH3.authz.redirectWithToken = function (providerUri, session, clientParams, scopes) { | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  |   if (!OAUTH3.url.checkRedirect(clientParams.client_uri, clientParams)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   if ('token' !== clientParams.response_type) { | 
					
						
							|  |  |  |     var message; | 
					
						
							|  |  |  |     if ('code' === clientParams.response_type) { | 
					
						
							|  |  |  |       message = "Authorization Code Redirect NOT IMPLEMENTED"; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       message = "Authorization response type '"+clientParams.response_type+"' not supported"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     window.alert(message); | 
					
						
							|  |  |  |     throw new Error(message); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   var prom; | 
					
						
							|  |  |  |   if (scopes.new) { | 
					
						
							|  |  |  |     prom = OAUTH3.authz.grants(providerUri, { | 
					
						
							|  |  |  |       session: session | 
					
						
							|  |  |  |     , method: 'POST' | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     , client_id: clientParams.client_uri | 
					
						
							|  |  |  |     , referrer: clientParams.referrer | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |     , scope: scopes.accepted.concat(scopes.new).join(',') | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     prom = OAUTH3.PromiseA.resolve(); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return prom.then(function () { | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |     return OAUTH3.hooks.keyPairs.get(session.token.sub); | 
					
						
							|  |  |  |   }).then(function (keyPair) { | 
					
						
							|  |  |  |     if (!keyPair) { | 
					
						
							|  |  |  |       return OAUTH3.discover(providerUri, { | 
					
						
							|  |  |  |         client_id: providerUri | 
					
						
							|  |  |  |       , debug: clientParams.debug | 
					
						
							|  |  |  |       }).then(function (directive) { | 
					
						
							|  |  |  |         return OAUTH3.request(OAUTH3.urls.clientToken(directive, { | 
					
						
							|  |  |  |           method: 'POST' | 
					
						
							|  |  |  |         , session: session | 
					
						
							|  |  |  |         , referrer: clientParams.referrer | 
					
						
							|  |  |  |         , response_type: clientParams.response_type | 
					
						
							|  |  |  |         , client_id:  clientParams.client_uri | 
					
						
							|  |  |  |         , azp: clientParams.client_uri | 
					
						
							|  |  |  |         , aud: clientParams.aud | 
					
						
							|  |  |  |         , exp: clientParams.exp | 
					
						
							|  |  |  |         , refresh_token: clientParams.refresh_token | 
					
						
							|  |  |  |         , refresh_exp: clientParams.refresh_exp | 
					
						
							|  |  |  |         , debug: clientParams.debug | 
					
						
							|  |  |  |         })).then(function (result) { | 
					
						
							|  |  |  |           return result.originalData || result.data; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.hooks.grants.get(keyPair.sub, clientParams.client_uri).then(function (grant) { | 
					
						
							|  |  |  |       var now = Math.floor(Date.now()/1000); | 
					
						
							|  |  |  |       var payload = { | 
					
						
							|  |  |  |         iat: now | 
					
						
							|  |  |  |       , iss: providerUri | 
					
						
							|  |  |  |       , aud: clientParams.aud || providerUri | 
					
						
							|  |  |  |       , azp: clientParams.client_uri | 
					
						
							|  |  |  |       , sub: grant.azpSub | 
					
						
							|  |  |  |       , scope: OAUTH3.scope.stringify(grant.scope) | 
					
						
							|  |  |  |     , }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var signProms = []; | 
					
						
							|  |  |  |       signProms.push(OAUTH3.jwt.sign(Object.assign({ | 
					
						
							|  |  |  |         exp: calcExpiration(clientParams.exp || '1h', now) | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |       }, payload), keyPair)); | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |       // if (clientParams.refresh_token) {
 | 
					
						
							|  |  |  |         signProms.push(OAUTH3.jwt.sign(Object.assign({ | 
					
						
							|  |  |  |           exp: calcExpiration(clientParams.refresh_exp, now) | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |         }, payload), keyPair)); | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |       // }
 | 
					
						
							|  |  |  |       return OAUTH3.PromiseA.all(signProms).then(function (tokens) { | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |         console.log('created new tokens for client'); | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |         return { | 
					
						
							|  |  |  |           access_token: tokens[0] | 
					
						
							|  |  |  |         , refresh_token: tokens[1] | 
					
						
							|  |  |  |         , scope: OAUTH3.scope.stringify(grant.scope) | 
					
						
							|  |  |  |         , token_type: 'bearer' | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }).then(function (session) { | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |     // TODO limit refresh token to an expirable token
 | 
					
						
							|  |  |  |     // TODO inform client not to persist token
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |     OAUTH3.url.redirect(clientParams, scopes, session); | 
					
						
							|  |  |  |   }, function (err) { | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |     console.error('unexpected error creating client tokens', err); | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |     OAUTH3.url.redirect(clientParams, scopes, {error: err}); | 
					
						
							| 
									
										
										
										
											2017-07-26 18:15:09 -06:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-26 16:27:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | OAUTH3.requests = {}; | 
					
						
							|  |  |  | OAUTH3.requests.accounts = {}; | 
					
						
							|  |  |  | OAUTH3.requests.accounts.update = function (directive, session, opts) { | 
					
						
							|  |  |  |   var dir = directive.update_account || { | 
					
						
							|  |  |  |     method: 'POST' | 
					
						
							| 
									
										
										
										
											2017-08-15 20:21:54 +00:00
										 |  |  |   , url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts/:accountId' | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   , bearer: 'Bearer' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   var url = dir.url | 
					
						
							|  |  |  |     .replace(/:accountId/, opts.accountId) | 
					
						
							|  |  |  |   ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return OAUTH3.request({ | 
					
						
							|  |  |  |     method: dir.method || 'POST' | 
					
						
							|  |  |  |   , url: url | 
					
						
							|  |  |  |   , headers: { | 
					
						
							|  |  |  |       'Authorization': (dir.bearer || 'Bearer') + ' ' + session.accessToken | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , json: { | 
					
						
							|  |  |  |       name: opts.name | 
					
						
							|  |  |  |     , comment: opts.comment | 
					
						
							|  |  |  |     , displayName: opts.displayName | 
					
						
							|  |  |  |     , priority: opts.priority | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | OAUTH3.requests.accounts.create = function (directive, session, account) { | 
					
						
							|  |  |  |   var dir = directive.create_account || { | 
					
						
							|  |  |  |     method: 'POST' | 
					
						
							| 
									
										
										
										
											2017-08-15 20:21:54 +00:00
										 |  |  |   , url: OAUTH3.url.normalize(directive.api) + '/api/issuer@oauth3.org/accounts' | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   , bearer: 'Bearer' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   var data = { | 
					
						
							|  |  |  |     // TODO fix the server to just use one scheme
 | 
					
						
							|  |  |  |     // account = { nick, self: { comment, username } }
 | 
					
						
							|  |  |  |     // account = { name, comment, display_name, priority }
 | 
					
						
							|  |  |  |     account: { | 
					
						
							|  |  |  |       nick: account.display_name | 
					
						
							|  |  |  |     , name: account.name | 
					
						
							|  |  |  |     , comment: account.comment | 
					
						
							|  |  |  |     , display_name: account.display_name | 
					
						
							|  |  |  |     , priority: account.priority | 
					
						
							|  |  |  |     , self: { | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |         nick: account.display_name | 
					
						
							|  |  |  |       , name: account.name | 
					
						
							|  |  |  |       , comment: account.comment | 
					
						
							|  |  |  |       , display_name: account.display_name | 
					
						
							|  |  |  |       , priority: account.priority | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   , logins: [ | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         token: session.access_token | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2017-02-20 11:12:48 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  |   return OAUTH3.request({ | 
					
						
							|  |  |  |     method: dir.method || 'POST' | 
					
						
							|  |  |  |   , url: dir.url | 
					
						
							|  |  |  |   , session: session | 
					
						
							|  |  |  |   , data: data | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  | OAUTH3.hooks.grants = { | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |   get: function (id, clientUri) { | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     OAUTH3.hooks._checkStorage('grants', 'get'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |     if (!id) { | 
					
						
							|  |  |  |       throw new Error("id is not set"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     if (!clientUri) { | 
					
						
							|  |  |  |       throw new Error("clientUri is not set"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.grants.get(id, OAUTH3.uri.normalize(clientUri))); | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  | , set: function (id, clientUri, grants) { | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     OAUTH3.hooks._checkStorage('grants', 'set'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |     if (!id) { | 
					
						
							|  |  |  |       throw new Error("id is not set"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     if (!clientUri) { | 
					
						
							|  |  |  |       throw new Error("clientUri is not set"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.grants.set(id, OAUTH3.uri.normalize(clientUri), grants)); | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , all: function () { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('grants', 'all'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.grants.all()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , clear: function () { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('grants', 'clear'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.grants.clear()); | 
					
						
							| 
									
										
										
										
											2017-02-21 20:38:45 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | OAUTH3.hooks.keyPairs = { | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |   get: function (id) { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('keyPairs', 'get'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!id) { | 
					
						
							|  |  |  |       throw new Error("id is not set"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.keyPairs.get(id)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , set: function (id, keyPair) { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('keyPairs', 'set'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |     if (!keyPair && id.privateKey && id.publicKey && id.sub) { | 
					
						
							|  |  |  |       keyPair = id; | 
					
						
							|  |  |  |       id = keyPair.sub; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!keyPair) { | 
					
						
							|  |  |  |       return OAUTH3.PromiseA.reject(new Error("no key pair provided to save")); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     if (!id) { | 
					
						
							|  |  |  |       throw new Error("id is not set"); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     keyPair.sub = keyPair.sub || id; | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.keyPairs.set(id, keyPair)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , all: function () { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('keyPairs', 'all'); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.keyPairs.all()); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  | , clear: function () { | 
					
						
							|  |  |  |     OAUTH3.hooks._checkStorage('keyPairs', 'clear'); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(OAUTH3._hooks.keyPairs.clear()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  | OAUTH3.hooks.session.get = function (providerUri, id) { | 
					
						
							|  |  |  |   OAUTH3.hooks._checkStorage('sessions', 'get'); | 
					
						
							|  |  |  |   var sessProm = OAUTH3.PromiseA.resolve(OAUTH3._hooks.sessions.get(providerUri, id)); | 
					
						
							|  |  |  |   if (providerUri !== OAUTH3.clientUri(window.location)) { | 
					
						
							|  |  |  |     return sessProm; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return sessProm.then(function (session) { | 
					
						
							|  |  |  |     if (session && OAUTH3.jwt.freshness(session.token) === 'fresh') { | 
					
						
							|  |  |  |       return session; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return OAUTH3.hooks.keyPairs.all().then(function (keyPairs) { | 
					
						
							|  |  |  |       var pair; | 
					
						
							|  |  |  |       if (id) { | 
					
						
							|  |  |  |         pair = keyPairs[id]; | 
					
						
							|  |  |  |       } else if (Object.keys(keyPairs).length === 1) { | 
					
						
							|  |  |  |         id = Object.keys(keyPairs)[0]; | 
					
						
							|  |  |  |         pair = keyPairs[id]; | 
					
						
							|  |  |  |       } else if (Object.keys(keyPairs).length > 1) { | 
					
						
							|  |  |  |         console.error("too many users, don't know which key to use"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!pair) { | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |         // even if the access token isn't fresh, the session might have a refresh token
 | 
					
						
							|  |  |  |         return session; | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |       var now = Math.floor(Date.now()/1000); | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |       var payload = { | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |         iat: now | 
					
						
							|  |  |  |       , iss: providerUri | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |       , aud: providerUri | 
					
						
							|  |  |  |       , azp: providerUri | 
					
						
							|  |  |  |       , sub: pair.sub || id | 
					
						
							|  |  |  |       , scope: '' | 
					
						
							| 
									
										
										
										
											2017-08-01 14:21:11 -06:00
										 |  |  |       , exp: now + 3600 | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |       }; | 
					
						
							|  |  |  |       return OAUTH3.jwt.sign(payload, pair.privateKey).then(function (token) { | 
					
						
							| 
									
										
										
										
											2017-08-01 15:08:21 -06:00
										 |  |  |         console.log('created new token for provider'); | 
					
						
							| 
									
										
										
										
											2017-08-01 11:15:37 -06:00
										 |  |  |         return OAUTH3.hooks.session.refresh( | 
					
						
							|  |  |  |           { provider_uri: providerUri, client_uri: providerUri || providerUri } | 
					
						
							|  |  |  |         , { access_token: token } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  | OAUTH3._defaultStorage.grants = { | 
					
						
							|  |  |  |   prefix: 'grants-' | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  | , get: function (id, clientUri) { | 
					
						
							|  |  |  |     var key = this.prefix + id+'/'+clientUri; | 
					
						
							|  |  |  |     var result = JSON.parse(window.localStorage.getItem(key) || 'null'); | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     return OAUTH3.PromiseA.resolve(result); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  | , set: function (id, clientUri, grants) { | 
					
						
							|  |  |  |     var key = this.prefix + id+'/'+clientUri; | 
					
						
							|  |  |  |     window.localStorage.setItem(key, JSON.stringify(grants)); | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     return this.get(clientUri); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , all: function () { | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     var prefix = this.prefix; | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |     var result = {}; | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     OAUTH3._defaultStorage._getStorageKeys(prefix, window.localStorage).forEach(function (key) { | 
					
						
							| 
									
										
										
										
											2017-08-01 14:13:36 -06:00
										 |  |  |       var split = key.replace(prefix, '').split('/'); | 
					
						
							|  |  |  |       if (!result[split[0]]) { result[split[0]] = {}; } | 
					
						
							|  |  |  |       result[split[0]][split[1]] = JSON.parse(window.localStorage.getItem(key) || 'null'); | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |     }); | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(result); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , clear: function () { | 
					
						
							| 
									
										
										
										
											2017-07-31 19:39:52 -06:00
										 |  |  |     OAUTH3._defaultStorage._getStorageKeys(this.prefix, window.localStorage).forEach(function (key) { | 
					
						
							|  |  |  |       window.localStorage.removeItem(key); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | OAUTH3._defaultStorage.keyPairs = { | 
					
						
							|  |  |  |   prefix: 'key_pairs-' | 
					
						
							|  |  |  | , get: function (id) { | 
					
						
							|  |  |  |     var result = JSON.parse(window.localStorage.getItem(this.prefix + id) || 'null'); | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(result); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , set: function (id, keyPair) { | 
					
						
							|  |  |  |     window.localStorage.setItem(this.prefix + id, JSON.stringify(keyPair)); | 
					
						
							|  |  |  |     return this.get(id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , all: function () { | 
					
						
							|  |  |  |     var prefix = this.prefix; | 
					
						
							|  |  |  |     var result = {}; | 
					
						
							|  |  |  |     OAUTH3._defaultStorage._getStorageKeys(prefix, window.localStorage).forEach(function (key) { | 
					
						
							|  |  |  |       result[key.replace(prefix, '')] = JSON.parse(window.localStorage.getItem(key) || 'null'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(result); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , clear: function () { | 
					
						
							|  |  |  |     OAUTH3._defaultStorage._getStorageKeys(this.prefix, window.localStorage).forEach(function (key) { | 
					
						
							| 
									
										
										
										
											2017-07-28 16:27:52 -06:00
										 |  |  |       window.localStorage.removeItem(key); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return OAUTH3.PromiseA.resolve(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-02-20 15:22:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | OAUTH3._browser.isIframe = function isIframe () { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     return window.self !== window.top; | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 11:49:41 -07:00
										 |  |  | }('undefined' !== typeof exports ? exports : window)); |