459 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			459 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (function () {
 | |
|   'use strict';
 | |
| 
 | |
|   window.ngOauth3App = angular.module('oauth3Playground', [ 'oauth3.org' ])
 | |
|   //window.ngOauth3App = angular.module('oauth3Playground', [ 'ui.router' ])
 | |
| /*
 | |
| 	ngOauth3App.config(function($stateProvider) {
 | |
| 		var helloState = {
 | |
| 			name: 'hello',
 | |
| 			url: '/hello',
 | |
| 			template: '<h3>hello world!</h3>'
 | |
| 		}
 | |
| 
 | |
| 		var aboutState = {
 | |
| 			name: 'about',
 | |
| 			url: '/about',
 | |
| 			template: '<h3>Its the UI-Router hello world app!</h3>'
 | |
| 		}
 | |
| 
 | |
| 		$stateProvider.state(helloState);
 | |
| 		$stateProvider.state(aboutState);
 | |
| 	});
 | |
| */
 | |
| 	.controller('PlaygroundCtrl', [ '$timeout', 'azp@oauth3.org', function ($timeout, OAUTH3) {
 | |
|     // NOTE: This OAUTH3 is the same as window.OAUTH3, but with angular's promise injected
 | |
|     // TODO: how to load more than one version of oauth3 on the page (i.e. a vanilla version without angular entaglement)
 | |
| 		var vm = this;
 | |
| 
 | |
|     vm.framework = 'none';
 | |
|     vm.clientUri = OAUTH3.clientUri(window.location);
 | |
|     vm.conf = { debug: undefined, client_id: vm.clientUri, client_uri: vm.clientUri, provider_uri: vm.clientUri };
 | |
|     vm.providerUri = vm.conf.client_uri;
 | |
|     // map of things being debounced presently
 | |
|     vm.debouncing = {};
 | |
|     vm.defaults = { provider: vm.conf.provider_uri, directives: null };
 | |
| 		vm.defaults.scopes = [
 | |
| 			{ name: 'oauth3_authn', desc: "Basic secure authentication", checked: true }
 | |
| 			//{ name: 'authn@oauth3.org', desc: "Basic secure authentication" }
 | |
| 		, { name: 'photos@daplie.com', desc: "Access to photos" }
 | |
| 		, { name: 'dns', desc: "DNS records (A/AAAA, TXT, SRV, MX, etc)" }
 | |
| 		, { name: '*', desc: "FULL ACCOUNT ACCESS" }
 | |
| 		];
 | |
| 
 | |
|     vm.form = {};
 | |
|     vm.form.id = 'coolaj86@gmail.com';
 | |
|     vm.form.subject = '';
 | |
|     vm.form.userProvider = '';
 | |
|     vm.form.provider = 'sso.hellabit.com';
 | |
|     vm.form.scopes = '';
 | |
| 
 | |
|     vm.locks = {};
 | |
|     vm.validated = {};
 | |
|     vm.responses = {};
 | |
| 
 | |
|     //
 | |
|     // Convenience for our app
 | |
|     //
 | |
|     vm.fn = {};
 | |
|     vm.fn.updateUrls = function () {
 | |
|       Object.keys(vm.api.urls).forEach(function (key) {
 | |
|         var fn = vm.api.urls[key];
 | |
|         fn();
 | |
|       });
 | |
|     };
 | |
|     vm.fn._debounce = {};
 | |
|     vm.fn.debounceUi = function () {
 | |
|       if (vm.debouncing.user || vm.debouncing.provider) {
 | |
|         vm.locks['login'] = true;
 | |
|       } else {
 | |
|         vm.locks['login'] = false;
 | |
|       }
 | |
|     };
 | |
|     vm.fn.debounce = function (name, time) {
 | |
|       vm.debouncing[name] = true;
 | |
|       vm.fn.debounceUi();
 | |
|       $timeout.cancel(vm.fn._debounce[name]);
 | |
|       vm.fn._debounce[name] = $timeout(function () {
 | |
|         vm.debouncing[name] = false;
 | |
|         vm.fn.debounceUi();
 | |
|         // do nothing, just use promise
 | |
|         return;
 | |
|       }, time || 250);
 | |
|       return vm.fn._debounce[name];
 | |
|     }
 | |
|     vm.fn.changeUser = function () {
 | |
|       var parts = vm.form.id.split('@');
 | |
|       var user;
 | |
|       var provider;
 | |
| 
 | |
|       if (/@/.test(vm.form.id)) {
 | |
|         // The username may have a single @, the provider may not
 | |
|         // user@thing.com@whatever.com -> user@thing.com, whatever.com
 | |
|         provider = parts.pop();
 | |
|         user = parts.join('');
 | |
|       } else {
 | |
|         //vm.form.hasUser = false;
 | |
|         user = '';
 | |
|         provider = parts.join('');
 | |
|       }
 | |
| 
 | |
|       vm.form.subject = vm.form.id;
 | |
| 
 | |
|       return vm.fn.debounce('provider', 250).then(function () {
 | |
|         var parts = vm.form.provider.split('.');
 | |
|         if (!vm.form.providerIndependent) {
 | |
|           vm.form.provider = provider;
 | |
|         }
 | |
|         vm.form.userProvider = provider;
 | |
|         // Careful: don't use state within a debounce function
 | |
|         // uses vm.form.provider for lookup
 | |
|         if (parts.length >= 2 && parts[parts.length - 1].length >= 2 && parts.every(function (p) {return p.length})) {
 | |
|           return vm.api.discover().then(function () {
 | |
|             console.log('[changeUser] vm.directives:');
 | |
|             console.log(vm.directives);
 | |
|             console.log(provider);
 | |
|             console.log(OAUTH3.uri.normalize(vm.directives.issuer));
 | |
|             if (vm.directives && provider === OAUTH3.uri.normalize(vm.directives.issuer)) {
 | |
|               vm.form.subject = user;
 | |
|             } else {
 | |
|               vm.form.subject = vm.form.id;
 | |
|             }
 | |
|           });
 | |
|         }
 | |
|       });
 | |
|     };
 | |
|     vm.fn.changeProvider = function () {
 | |
|       vm.form.providerIndependent = true;
 | |
| 
 | |
|       var parts = vm.form.provider.split('.');
 | |
|       vm.fn.debounce('provider', 250).then(function () {
 | |
|         // Careful: don't use state within a debounce function
 | |
|         if (parts.length >= 2 && parts[parts.length - 1].length >= 2 && parts.every(function (p) {return p.length})) {
 | |
|           return vm.api.discover();
 | |
|         }
 | |
|       });
 | |
|     };
 | |
|     vm.fn.toggleAdvanced = function () {
 | |
|       vm.advanced = !vm.advanced;
 | |
|       vm.form.provider = vm.form.userProvider;
 | |
|       if (!vm.advanced) {
 | |
|         vm.form.providerIndependent = false;
 | |
|         vm.fn.changeUser();
 | |
|       }
 | |
|     };
 | |
|     vm.fn.updateDebug = function () {
 | |
|       if (!vm.conf.debug) {
 | |
|         vm.conf.debug = undefined;
 | |
|       }
 | |
|     };
 | |
|     vm.fn.updateScopes = function () {
 | |
|       var scopes = {};
 | |
| 
 | |
|       (vm.scopes && vm.scopes.split(',') || []).forEach(function (name) {
 | |
|         scopes[name] = true;
 | |
|       });
 | |
| 
 | |
|       vm.defaults.scopes.forEach(function (scope) {
 | |
|         if (scope.checked) {
 | |
|           scopes[scope.name] = true;
 | |
|         } else {
 | |
|           scopes[scope.name] = false;
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       vm.form.scopes = Object.keys(scopes).filter(function (key) {
 | |
|         return scopes[key];
 | |
|       }).map(function (key) {
 | |
|         return key;
 | |
|       }).join(',');
 | |
| 
 | |
|       vm.fn.updateUrls(); // vm.api.urls.implicitGrant();
 | |
|     };
 | |
| 
 | |
|     vm.fn.lock = function () {
 | |
|       vm._working = true;
 | |
|     };
 | |
|     vm.fn.unlock = function () {
 | |
|       vm._working = false;
 | |
|     };
 | |
|     vm.fn.clearError = function () {
 | |
|       vm.error = null;
 | |
|     };
 | |
|     vm.fn.clearDirectives = function () {
 | |
|       vm.directives = null;
 | |
|     };
 | |
| 
 | |
|     // A place for all the generated urls
 | |
|     vm.urls = {};
 | |
| 
 | |
|     //
 | |
|     // Wrap around the OAUTH3 APIs
 | |
|     //
 | |
|     vm.api = {};
 | |
|     vm.api.urls = {};
 | |
|     vm.api.authn = {};
 | |
|     vm.api.jwt = {};
 | |
|     vm.api.urls.credentialMeta = function () {
 | |
|       if (!vm.directives ||!vm.directives.credential_meta || !vm.form.id) { return; }
 | |
|       vm.urls.credentialMeta = OAUTH3.urls.credentialMeta(vm.directives, { email: vm.form.id });
 | |
|     };
 | |
|     vm.api.urls.otp = function () {
 | |
|       if (!vm.directives || !vm.form.id) { return; }
 | |
|       vm.urls.otp = OAUTH3.urls.otp(vm.directives, { email: vm.form.id });
 | |
|     };
 | |
|     vm.api.authn.otp = function () {
 | |
|       vm.fn.updateUrls(); // vm.api.urls.otp();
 | |
|       OAUTH3.authn.otp(vm.directives, { email: vm.form.id }).then(function (resp) {
 | |
|         vm.responses.otp = resp;
 | |
|         vm.form.otpUuid = resp.data.code_id;
 | |
|         console.log('vm.responses.otp: (' + typeof resp + ')');
 | |
|         console.log(vm.responses.otp);
 | |
| 
 | |
|         console.log('vm.form.otpUuid:');
 | |
|         console.log(vm.form.otpUuid);
 | |
| 
 | |
|         vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword();
 | |
|       });
 | |
|     };
 | |
|     vm.api.authn.credentialMeta = function () {
 | |
|       vm.fn.updateUrls(); // vm.api.urls.credentialMeta();
 | |
|       OAUTH3.authn.loginMeta(vm.directives, { email: vm.form.id }).then(function () {
 | |
|         vm.fn.updateUrls(); // vm.api.urls.credentialMeta();
 | |
|       });
 | |
|     };
 | |
| 
 | |
| 
 | |
|     vm.api.authn._ropOpts = function () {
 | |
|       //var opts = { email: vm.form.id, uuid: vm.form.otpUuid, code: vm.form.otpCode };
 | |
|       return vm.api.authn._ropOpts_ = {
 | |
|         client_id: vm.conf.client_uid || undefined
 | |
|       , client_uri: vm.conf.client_uri || undefined
 | |
|       , grant_type: 'password'
 | |
|       , username: vm.form.id || undefined
 | |
|       , password: vm.form.otpCode || undefined
 | |
|       , totp: vm.form.totpToken || undefined
 | |
|       , otp: vm.form.otpCode || "{{otp-code}}"
 | |
|       , password_type: vm.form.otpCode && 'otp' || undefined
 | |
|       , otp_code: vm.form.otpCode || undefined
 | |
|       , otp_id: vm.form.otpUuid || undefined
 | |
|       , otp_uuid: vm.form.otpUuid || undefined
 | |
|       , user_agent: navigator.userAgent || undefined // "AJ's Macbook" for a specific device?
 | |
|       , jwk: vm.form.rememberDevice && opts.jwk || undefined
 | |
|       //, "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: vm.form.debug || undefined
 | |
|       };
 | |
|     };
 | |
|     vm.api.urls.resourceOwnerPassword = function () {
 | |
|       if (!vm.directives || !vm.form.otpUuid) { return; }
 | |
|       vm.urls.resourceOwnerPassword = OAUTH3.urls.resourceOwnerPassword(vm.directives, vm.api.authn._ropOpts());
 | |
|     };
 | |
|     vm.api.authn.resourceOwnerPassword = function () {
 | |
|       vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword();
 | |
|       OAUTH3.authn.resourceOwnerPassword(vm.directives, vm.api.authn._ropOpts()).then(function (resp) {
 | |
|         vm.responses.resourceOwnerPassword = { status: 0, data: resp };
 | |
|         vm.form.accessToken = vm.accessToken = resp.access_token;
 | |
|         vm.form.refreshToken = vm.refreshToken = resp.refresh_token;
 | |
|         vm.ropSession = resp;
 | |
|         vm.ropToken = resp.token;
 | |
| 
 | |
|         vm.fn.updateUrls(); // vm.api.urls.resourceOwnerPassword(); also grants
 | |
|       });
 | |
|     };
 | |
| 
 | |
| 
 | |
|     vm.api.jwt.decode = function () {
 | |
|       vm.ropToken = OAUTH3.jwt.decode(vm.form.accessToken || vm.accessToken);
 | |
|     };
 | |
|     vm.api.jwt.decodeRefresh = function () {
 | |
|       vm.ropToken = OAUTH3.jwt.decode(vm.form.refreshToken || vm.refreshToken);
 | |
|     };
 | |
| 
 | |
|     vm.api.providerUri = function () {
 | |
|       console.log('[DEBUG] providerUri:', vm.providerUri);
 | |
|       try {
 | |
|         vm.providerUri = OAUTH3.uri.normalize(vm.providerUri);
 | |
|         vm.conf.provider_uri = vm.providerUri;
 | |
|       } catch(e) {
 | |
|         vm.error = e;
 | |
|       }
 | |
|     };
 | |
|     vm.api.clientUri = function () {
 | |
|       console.log('[DEBUG] clientUri:', vm.clientUri);
 | |
|       try {
 | |
|         vm.clientUri = OAUTH3.clientUri({ host: vm.clientUri });
 | |
|         if (vm.clientUri) {
 | |
|       console.log('[DEBUG] clientUri:', vm.clientUri);
 | |
|           vm.conf.client_uri = vm.clientUri;
 | |
|           vm.conf.client_id = vm.clientUri;
 | |
|         }
 | |
|       } catch(e) {
 | |
|         vm.error = e;
 | |
|       }
 | |
|     };
 | |
|     vm.api._discoverCount = 0;
 | |
|     vm.api.urls.implicitGrant = function (provider) {
 | |
|       if (!vm.directives) {
 | |
|         console.log('[DEBUG] skipping implicit grant due to missing directives');
 | |
|         return;
 | |
|       }
 | |
|       var opts = {
 | |
|         client_uri: vm.conf.client_uri
 | |
|       , subject: vm.form.subject || undefined
 | |
|       , debug: vm.conf.debug || undefined
 | |
|       , scope: vm.form.scopes || undefined
 | |
|       };
 | |
|       var implicitGrantObj = OAUTH3.urls.implicitGrant(vm.directives, opts);
 | |
|       vm.implicitGrantUrl = (OAUTH3.url.normalize(provider || vm.form.provider) + '/' + implicitGrantObj.url).replace(implicitGrantObj.state, '{{random}}');
 | |
|     }
 | |
|     vm.api.discover = function () {
 | |
|       vm.directives = null;
 | |
|       vm.validated.provider = '';
 | |
|       vm.api._discoverCount += 1;
 | |
|       var latest = vm.api._discoverCount;
 | |
|       var provider = vm.form.provider; // shouldn't be mutable during this time but...
 | |
| 
 | |
|       vm.fn.lock();
 | |
| 
 | |
|       vm.discoveryObj = OAUTH3.urls.discover(provider, vm.conf);
 | |
|       vm.directivesUrl = OAUTH3.url.normalize(provider) + '/' + vm.discoveryObj.query._pathname;
 | |
|       vm.discoveryUrl = vm.discoveryObj.method + ' ' + vm.discoveryObj.url;
 | |
| 
 | |
|       console.log('about to discover');
 | |
| 
 | |
|       return OAUTH3.discover(provider, vm.conf).then(function (dir) {
 | |
|         if (latest !== vm.api._discoverCount) {
 | |
|           console.log('[DEBUG] ignoring stale discover response for', provider);
 | |
|           return;
 | |
|         }
 | |
|         console.log('[DEBUG] directives:');
 | |
|         console.log(dir);
 | |
|         vm.validated.provider = provider;
 | |
|         vm.directives = dir;
 | |
| 
 | |
|         vm.api.urls.implicitGrant(provider);
 | |
|         //JSON.stringify(dir, null, 2);
 | |
|       }, function (err) {
 | |
|         vm.form.provider = vm.defaults.provider;
 | |
|         vm.validated.provider = vm.defaults.provider;
 | |
|         vm.directives = vm.defaults.directives;
 | |
|         if (latest !== vm.api._discoverCount) {
 | |
|           console.warn('[DEBUG] ignoring stale discover error for', provider);
 | |
|           console.warn(err);
 | |
|           return;
 | |
|         }
 | |
|         console.log('error on discover');
 | |
|         vm.error = err;
 | |
|       }).then(function () {
 | |
|         vm.fn.unlock();
 | |
|       });
 | |
|     };
 | |
|     vm.api.discoverScopes = function () {
 | |
|       var scopes = vm.form.scopes && vm.form.scopes.split(',') || [];
 | |
|       vm.scopesObj = [];
 | |
| 
 | |
|       function nextScope() {
 | |
|         var scopename = scopes.shift();
 | |
|         if (!scopename) {
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         // something like https://example.com/.well-known/oauth3.org/scopes/:scopename.json
 | |
|         var scopeUrlObj = OAUTH3.urls.discoverScope(vm.form.provider, {
 | |
|           client_uri: vm.conf.client_uri
 | |
|         , scope: scopename
 | |
|         , debug: vm.conf.debug || undefined
 | |
|         });
 | |
|         vm.scopeUrl = OAUTH3.url.normalize(provider) + '/' + scopeUrlObj.query._pathname;
 | |
| 
 | |
|         // something like the discovery url that loads in an iframe
 | |
|         var discoverScopeObj = OAUTH3.urls.discoverScope(vm.form.provider, {
 | |
|           client_uri: vm.conf.client_uri
 | |
|         , scope: scopename
 | |
|         , debug: vm.conf.debug || undefined
 | |
|         });
 | |
|         vm.discoverScopeUrl = OAUTH3.url.normalize(provider) + '/' + discoverScopeObj.url;
 | |
| 
 | |
|         // Go and fetch!
 | |
|         return OAUTH3.discoverScopes(vm.form.provider, {
 | |
|           client_uri: vm.conf.client_uri
 | |
|         , scope: scopename
 | |
|         , debug: vm.conf.debug || undefined
 | |
|         }).then(function (scope) {
 | |
|           var allScopes = {};
 | |
|           vm.scopesObj.push(scope);
 | |
|           vm.defaults.scopes.push(scope);
 | |
|           vm.defaults.scopes = vm.defaults.scopes.filter(function (scope) {
 | |
|             if (allScopes[scope.name]) {
 | |
|               return false;
 | |
|             }
 | |
|             allScopes[scope.name] = true;
 | |
|             return true;
 | |
|           });
 | |
|         }, function (err) {
 | |
|           console.error("Error in discover scope:");
 | |
|           console.error(err);
 | |
|           vm.scopesObj.push({ name: scopename, desc: "Error, not found" });
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       return nextScope();
 | |
|     };
 | |
|     vm.api.implicitGrant = function () {
 | |
|       var provider = vm.validated.provider;
 | |
|       var opts = {
 | |
|         client_uri: vm.conf.client_uri
 | |
|       , subject: vm.form.subject || undefined
 | |
|       , debug: vm.conf.debug || undefined
 | |
|       , scope: vm.form.scopes || undefined
 | |
|       };
 | |
| 
 | |
|       console.log('[DEBUG] vm.directives');
 | |
|       console.log(vm.directives);
 | |
|       vm.implicitGrantObj = OAUTH3.urls.implicitGrant(vm.directives, opts);
 | |
|       console.log('[DEBUG] vm.implicitGrantObj');
 | |
|       console.log(vm.implicitGrantObj);
 | |
|       vm.implicitGrantUrl = (OAUTH3.url.normalize(provider) + '/' + vm.implicitGrantObj.url);
 | |
|       return OAUTH3.implicitGrant(vm.directives, opts).then(function (session) {
 | |
|         vm.session = session;
 | |
|       });
 | |
|     };
 | |
|     vm.api.authz = {};
 | |
|     vm.api.authz._grantsOpts = function () {
 | |
|       return vm.api.authz._grantsOpts_ = {
 | |
|         method: 'GET'
 | |
|       , client_id: vm.conf.client_id
 | |
|       , client_uri: vm.conf.client_uri
 | |
|       , session: vm.ropSession
 | |
|       , debug: vm.conf.debug
 | |
|       , all: true
 | |
|       };
 | |
|     };
 | |
|     vm.api.urls.grants = function () {
 | |
|       if (!vm.directives || !vm.ropSession || !vm.form.id) { return; }
 | |
|       vm.urls.grants = OAUTH3.urls.grants(vm.directives, vm.api.authz._grantsOpts());
 | |
|     };
 | |
|     vm.api.authz.grants = function () {
 | |
|       vm.fn.updateUrls(); // vm.api.urls.grants();
 | |
|       return OAUTH3.authz.grants(vm.form.provider, vm.api.authz._grantsOpts()).then(function (resp) {
 | |
|         vm.responses.grants = { status: 0, data: resp };
 | |
|         vm.fn.updateUrls(); // vm.api.urls.grants();
 | |
|       }, function (err) {
 | |
|         console.error('[error] authz.grants:');
 | |
|         console.error(err);
 | |
|         vm.error = err;
 | |
|       });
 | |
|     };
 | |
| 
 | |
|     vm.form.provider = vm.defaults.provider;
 | |
|     vm.validated.provider = vm.defaults.provider;
 | |
|     vm.api.discover().then(function () {
 | |
|       vm.defaults.directives = vm.directives;
 | |
|     });
 | |
| 
 | |
|     vm.fn.updateScopes();
 | |
| 	} ] );
 | |
| }());
 |