move .well-known/oauth3 to assets/org.oauth3/.well-known/oauth3
This commit is contained in:
		
							parent
							
								
									35e2a29e4c
								
							
						
					
					
						commit
						a449358dd6
					
				
							
								
								
									
										21
									
								
								.well-known/oauth3/callback.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								.well-known/oauth3/callback.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8"> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|         <title>Redirecting...</title> | ||||
|         <style> | ||||
|         body { | ||||
|           background-color: #ffcccc; | ||||
|         } | ||||
|         </style> | ||||
|     </head> | ||||
|     <body> | ||||
|         Redirecting... | ||||
| 
 | ||||
|         <!-- TODO permanently cache with appcache (or service worker?) --> | ||||
|         <!-- TODO slim this all down to a single file --> | ||||
|         <script src="/assets/org.oauth3/oauth3.core.js"></script> | ||||
|         <script src="callback.js"></script> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										66
									
								
								.well-known/oauth3/callback.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								.well-known/oauth3/callback.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | ||||
| (function () { | ||||
| 	"use strict"; | ||||
| 
 | ||||
| 	var loc = window.location; | ||||
| 	var loginWinObj = window.OAUTH3_CORE.queryparse(loc.hash || loc.search); | ||||
|   var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/callback.html]"; | ||||
| 
 | ||||
|   if (loginWinObj.debug) { | ||||
|     console.warn(prefix, "DEBUG MODE ENABLED. Automatic redirects disabled."); | ||||
|   } | ||||
|   // '--oauth3-callback-' prefix exist for security so that an attacker can't social engineer execution an arbitrary function
 | ||||
|   // TODO finalize name of '--oauth3-callback-', this will be a defacto standard
 | ||||
|   // TODO maybe call it 'self-xss-' or 'hack-my-account-' to discourage people from doing dumb things?
 | ||||
| 	var callbackName = '--oauth3-callback-' + loginWinObj.state; | ||||
| 
 | ||||
| 	console.log(prefix, loc.href); | ||||
| 	console.log('Parsed URL Obj: ', loginWinObj); | ||||
| 	console.log('callbackName: ', callbackName); | ||||
| 
 | ||||
|   window.oauth3complete = function () { | ||||
|     // The hacks that used to be necessary for this on iOS should no longer be necessary in iOS 9+
 | ||||
|     // see https://bugs.chromium.org/p/chromium/issues/detail?id=136610 and https://crbug.com/423444
 | ||||
|     // TODO Should we still create an abstraction for older versions?
 | ||||
|     if (window.parent) { | ||||
|       // iframe
 | ||||
|       try { | ||||
|         window.parent[callbackName](loginWinObj); | ||||
|         return; | ||||
|       } catch(e) { | ||||
|         console.warn(e); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (window.opener) { | ||||
|       try { | ||||
|         window.opener[callbackName](loginWinObj); | ||||
|         return; | ||||
|       } catch(e) { | ||||
|         console.warn(e); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     console.error("neither window.parent nor window.opener existed to complete callback"); | ||||
| 
 | ||||
|     /* | ||||
|     // the caller should close (or signal to close) the window
 | ||||
|     try { | ||||
|       window.close(); | ||||
|     } catch (err) { | ||||
|       console.log('Error: ', err); | ||||
|     } | ||||
|     */ | ||||
|   }; | ||||
| 
 | ||||
|   if (!loginWinObj.debug) { | ||||
|     window.oauth3complete(); | ||||
|   } | ||||
|   else { | ||||
|     document.body.innerHTML = window.location.hostname + 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 callback: <a href="javascript:window.oauth3complete()">javascript:window.oauth3complete()</' + 'a>'; | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
| }()); | ||||
							
								
								
									
										0
									
								
								.well-known/oauth3/crossdomain.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.well-known/oauth3/crossdomain.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								.well-known/oauth3/crossdomain.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.well-known/oauth3/crossdomain.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										330
									
								
								.well-known/oauth3/directives.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								.well-known/oauth3/directives.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,330 @@ | ||||
| (function () { | ||||
|   'use strict'; | ||||
| 
 | ||||
|   console.log('[DAPLIE oauth3 directives.js]'); | ||||
|   console.log(window.location); | ||||
| 
 | ||||
|   var iter = 0; | ||||
| 
 | ||||
|   function main() { | ||||
| 
 | ||||
|     var rpc = {}; | ||||
|     //var myself = location.protocol + '//' + location.host + location.pathname;
 | ||||
|     var incoming; | ||||
|     var forwarding = {}; | ||||
|     var err; | ||||
|     var browserState; | ||||
|     var browserCallback; | ||||
|     var action; | ||||
| 
 | ||||
|     function parseParams() { | ||||
|       var params = {}; | ||||
| 
 | ||||
|       function parseParamsString(str) { | ||||
|         str.substr(1).split('&').filter(function (el) { return el; }).forEach(function (pair) { | ||||
|           pair = pair.split('='); | ||||
|           var key = decodeURIComponent(pair[0]); | ||||
|           var val = decodeURIComponent(pair[1]); | ||||
| 
 | ||||
|           if (params[key]) { | ||||
|             console.warn("overwriting key '" + key + "' '" + params[key] + "'"); | ||||
|           } | ||||
|           params[key] = val; | ||||
|         }); | ||||
|       } | ||||
| 
 | ||||
|       parseParamsString(window.location.search); | ||||
|       // handle cases where hash is treated like it's own href
 | ||||
|       // TODO /#/?search=blah
 | ||||
|       parseParamsString(window.location.hash); | ||||
| 
 | ||||
|       return params; | ||||
|     } | ||||
| 
 | ||||
|     function querystringify(params) { | ||||
|       var arr = []; | ||||
| 
 | ||||
|       Object.keys(params).forEach(function (k) { | ||||
|         arr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k])); | ||||
|       }); | ||||
| 
 | ||||
|       return arr.join('&'); | ||||
|     } | ||||
| 
 | ||||
|     function phoneAway(/*redirectURi, params*/) { | ||||
|       // TODO test for ? / #
 | ||||
|       window.location.href = incoming.redirect_uri + '#' + querystringify(forwarding); | ||||
|     } | ||||
| 
 | ||||
|     function lintAndSetRedirectable(browserState, params) { | ||||
|       if (!params.redirect_uri) { | ||||
|         window.alert('redirect_uri not defined'); | ||||
|         err = new Error('redirect_uri not defined'); | ||||
|         console.error(err.message); | ||||
|         console.warn(err.stack); | ||||
|         params.redirect_uri = document.referer; | ||||
|         return false; | ||||
|       } | ||||
| 
 | ||||
|       if (!browserState) { | ||||
|         forwarding.error = "E_NO_BROWSER_STATE"; | ||||
|         forwarding.error_description = "you must specify a state parameter"; | ||||
|         return false; | ||||
|       } | ||||
| 
 | ||||
|       localStorage.setItem('oauth3.states.' + browserState, JSON.stringify(params)); | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     function redirectCallback() { | ||||
|       var redirect_uri = incoming.redirect_uri; | ||||
|       forwarding.callback = browserState; | ||||
|       forwarding.action = 'close'; | ||||
| 
 | ||||
|       var url = redirect_uri + '#' + querystringify(forwarding); | ||||
| 
 | ||||
|       console.log('[debug] redirect_uri + params:', url); | ||||
|       window.location.href = url; | ||||
|       setTimeout(function () { | ||||
|         if (iter >= 3) { | ||||
|           console.log("dancing way too much... stopping now"); | ||||
|           return; | ||||
|         } | ||||
|         iter += 1; | ||||
|         console.log("I'm dancing by myse-e-elf"); | ||||
|         // in case I'm redirecting to myself
 | ||||
|         main(); | ||||
|       }, 0); | ||||
|     } | ||||
| 
 | ||||
|     rpc = {}; | ||||
| 
 | ||||
|     // Act as a provider and log the user out
 | ||||
|     rpc.logout = function (browserState, incoming) { | ||||
|       var url; | ||||
|       if (!lintAndSetRedirectable(browserState, incoming)) { | ||||
|         // TODO fail
 | ||||
|       } | ||||
| 
 | ||||
|       localStorage.setItem('oauth3.states.' + browserState, JSON.stringify(incoming)); | ||||
|       url = '/#/logout/' + browserState; | ||||
| 
 | ||||
|       // TODO specify specific account or all?
 | ||||
|       window.location.href = url; | ||||
|       setTimeout(function () { | ||||
|         // in case I'm redirecting to myself
 | ||||
|         main(); | ||||
|       }, 0); | ||||
|     }; | ||||
| 
 | ||||
|     // Act as a provider and inform the consumer the logout is complete
 | ||||
|     rpc.logout_callback = function (browserState/*, incoming*/) { | ||||
|       // TODO pass redirect_uri and state through here so we can avoid localStorage
 | ||||
|       var forwarding = {}; | ||||
|       var originalRequest; | ||||
| 
 | ||||
|       if (!browserState) { | ||||
|         forwarding.error = "E_NO_BROWSER_STATE"; | ||||
|         forwarding.error_description = "you must specify a state parameter"; | ||||
|         if (incoming.redirect_uri) { | ||||
|           phoneAway(incoming.redirect_uri, forwarding); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       originalRequest = JSON.parse(localStorage.getItem('oauth3.states.' + browserState)); | ||||
|       forwarding.action = 'close'; | ||||
|       forwarding.state = browserState; | ||||
|       //phoneAway(originalRequest.redirect_uri, forwarding);
 | ||||
|       window.location.href = originalRequest.redirect_uri + '#' + querystringify(forwarding); | ||||
|     }; | ||||
| 
 | ||||
|     rpc.directives = function (browserState, incoming) { | ||||
|       if (!lintAndSetRedirectable(browserState, incoming)) { | ||||
|         phoneAway(); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       var updatedAt = new Date(localStorage.getItem('oauth3.directives.updated_at')).valueOf(); | ||||
|       var fresh = (Date.now() - updatedAt) < (24 * 60 * 60 * 1000); | ||||
|       var directives = localStorage.getItem('oauth3.directives'); | ||||
|       var redirected = false; | ||||
| 
 | ||||
|       function redirectIf() { | ||||
|         if (redirected) { | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         redirected = true; | ||||
|         redirectCallback(); | ||||
|       } | ||||
| 
 | ||||
|       if (directives) { | ||||
|         forwarding.directives = directives; | ||||
|         redirectIf(); | ||||
|         if (fresh) { | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       var req = new XMLHttpRequest(); | ||||
|       req.open('GET', '.well-known/oauth3.json', true); | ||||
|       req.addEventListener('readystatechange', function () { | ||||
|         if (4 !== req.readyState) { | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         if (200 !== req.status) { | ||||
|           forwarding.error = "E_STATUS_" + req.status; | ||||
|           forwarding.error_description = "expected 200 OK json or text response for oauth3.json but got '" + req.status + "'"; | ||||
|           redirectIf(); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|           directives = btoa(JSON.stringify(JSON.parse(req.responseText))); | ||||
|           forwarding.directives = directives; | ||||
|           forwarding.callback = browserState; | ||||
|           localStorage.setItem('oauth3.directives', directives); | ||||
|           localStorage.setItem('oauth3.directives.updated_at', new Date().toISOString()); | ||||
|         } catch(e) { | ||||
|           forwarding.error = "E_PARSE_JSON"; | ||||
|           forwarding.error_description = e.message; | ||||
|           console.error(forwarding.error); | ||||
|           console.error(forwarding.error_description); | ||||
|           console.error(req.responseText); | ||||
|         } | ||||
| 
 | ||||
|         redirectIf(); | ||||
|       }); | ||||
|       req.send(); | ||||
|     }; | ||||
| 
 | ||||
|     // the provider is contacting me
 | ||||
|     rpc.close = function (browserState, incoming) { | ||||
|       incoming.callback = browserState; | ||||
|       catchAll(); | ||||
|     }; | ||||
|     // the provider is contacting me
 | ||||
|     rpc.redirect = function (/*browserState, incoming*/) { | ||||
|       catchAll(); | ||||
|     }; | ||||
| 
 | ||||
|     function catchAll() { | ||||
|       function phoneHome() { | ||||
|         if (browserCallback === 'completeLogin') { | ||||
|           // Deprecated
 | ||||
|           console.log('[deprecated] callback completeLogin'); | ||||
|           (window.opener||window.parent).completeLogin(null, null, incoming); | ||||
|         } else { | ||||
|           console.log('[DEBUG] I would be closed by my parent now'); | ||||
|           console.log('__oauth3_' + browserCallback); | ||||
|           console.log(window.opener && window.opener['__oauth3_' + browserCallback]); | ||||
|           console.log(window.parent && window.parent['__oauth3_' + browserCallback]); | ||||
|           console.log(incoming); | ||||
|           (window.opener||window.parent)['__oauth3_' + browserCallback](incoming); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (!(incoming.browser_state || incoming.state)) { | ||||
|         window.alert("callback URLs should include 'browser_state' (authorization code)" | ||||
|           + " or 'state' (implicit grant))"); | ||||
|       } | ||||
| 
 | ||||
|       setTimeout(function () { | ||||
|         // opener is for popup window, new tab
 | ||||
|         // parent is for iframe
 | ||||
|         phoneHome(); | ||||
|       }, 10); | ||||
| 
 | ||||
|       // iOS Webview (namely Chrome) workaround
 | ||||
|       setTimeout(function () { | ||||
|         console.log('I would close now'); | ||||
|         // XXX OAUTH3 DEBUG FRAME XXX // make this easy to find
 | ||||
|         window.open('', '_self', ''); | ||||
|         window.close(); | ||||
|       }, 50); | ||||
| 
 | ||||
|       setTimeout(function () { | ||||
|         var i; | ||||
|         var len = localStorage.length; | ||||
|         var key; | ||||
|         var json; | ||||
|         var fresh; | ||||
| 
 | ||||
|         for (i = 0; i < len; i += 1) { | ||||
|           key = localStorage.key(i); | ||||
|           // TODO check updatedAt
 | ||||
|           if (/^oauth3\./.test(key)) { | ||||
|             try { | ||||
|               json = localStorage.getItem(key); | ||||
|               if (json) { | ||||
|                 json = JSON.parse(json); | ||||
|               } | ||||
|             } catch (e) { | ||||
|               // ignore
 | ||||
|               json = null; | ||||
|             } | ||||
| 
 | ||||
|             fresh = json && (Date.now() - json.updatedAt < (5 * 60 * 1000)); | ||||
| 
 | ||||
|             if (!fresh) { | ||||
|               localStorage.removeItem(key); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         forwarding.updatedAt = Date.now(); | ||||
|         localStorage.setItem('oauth3.' + (forwarding.browser_state || forwarding.state), JSON.stringify(forwarding)); | ||||
|       }, 0); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     function parseAction(params) { | ||||
|       if (params.action) { | ||||
|         return params.action; | ||||
|       } | ||||
| 
 | ||||
|       if (params.close) { | ||||
|         return 'close'; | ||||
|       } | ||||
|       if (params.logout_callback) { | ||||
|         return 'logout_callback'; | ||||
|       } | ||||
|       if (params.logout) { | ||||
|         return 'logout'; | ||||
|       } | ||||
|       if (params.callback) { | ||||
|         return 'close'; | ||||
|       } | ||||
|       if (params.directives) { | ||||
|         return 'directives'; | ||||
|       } | ||||
| 
 | ||||
|       return 'redirect'; | ||||
|     } | ||||
| 
 | ||||
|     incoming = parseParams(); | ||||
|     browserState = incoming.browser_state || incoming.state; | ||||
|     action = parseAction(incoming); | ||||
|     forwarding.url = window.location.href; | ||||
|     forwarding.browser_state = browserState; | ||||
|     forwarding.state = browserState; | ||||
| 
 | ||||
|     if (!incoming.provider_uri) { | ||||
|       browserCallback = incoming.callback || browserState; | ||||
|     } else { | ||||
|       // deprecated
 | ||||
|       browserCallback = 'completeLogin'; | ||||
|     } | ||||
| 
 | ||||
|     console.log('[debug]', action, incoming); | ||||
| 
 | ||||
|     if (rpc[action]) { | ||||
|       rpc[action](browserState, incoming); | ||||
|     } else { | ||||
|       window.alert('unsupported action'); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   main(); | ||||
| }()); | ||||
							
								
								
									
										9
									
								
								.well-known/oauth3/directives.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.well-known/oauth3/directives.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| { "authorization_dialog": { "url": "#/authorization_dialog" } | ||||
| , "access_token": { "method": "POST", "url": "api/org.oauth3.provider/access_token" } | ||||
| , "otp": { "method": "POST" , "url": "api/org.oauth3.provider/otp" } | ||||
| , "credential_otp": { "method": "POST" , "url": "api/org.oauth3.provider/otp" } | ||||
| , "credential_meta": { "url": "api/org.oauth3.provider/logins/meta/:type/:id" } | ||||
| , "credential_create": { "method": "POST" , "url": "api/org.oauth3.provider/logins" } | ||||
| , "grants": { "method": "GET", "url": "api/org.oauth3.provider/grants/:azp/:sub" } | ||||
| , "authorization_decision": { "method": "POST", "url": "api/org.oauth3.provider/authorization_decision" } | ||||
| } | ||||
							
								
								
									
										68
									
								
								.well-known/oauth3/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								.well-known/oauth3/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|   <head> | ||||
|     <style> | ||||
|       body { | ||||
|         background-color: #ffcccc; | ||||
|       } | ||||
|     </style> | ||||
|   </head> | ||||
|   <body> | ||||
|   OAuth3 RPC | ||||
| 
 | ||||
|   <script src="/assets/com.jquery/jquery-3.1.1.js"></script> | ||||
|   <script src="/assets/org.oauth3/oauth3.core.js"></script> | ||||
|   <script> | ||||
|     'use strict'; | ||||
| 
 | ||||
|     // TODO what about search within hash? | ||||
|     var prefix = "(" + window.location.hostname + ") [.well-known/oauth3/]"; | ||||
|     var params = OAUTH3_CORE.queryparse(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); | ||||
| 
 | ||||
|     $.ajax({ url: 'directives.json' }).then(function (resp) { | ||||
|       var b64 = btoa(JSON.stringify(resp, null, 0)) | ||||
|       var urlsafe64 = OAUTH3_CORE.utils.base64ToUrlSafeBase64(b64); | ||||
|       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_CORE.querystringify({ | ||||
|         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> | ||||
							
								
								
									
										0
									
								
								.well-known/oauth3/logout.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.well-known/oauth3/logout.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								.well-known/oauth3/logout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.well-known/oauth3/logout.js
									
									
									
									
									
										Normal file
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user