oauth3.org is now its own thing

This commit is contained in:
AJ ONeal 2017-05-22 23:25:43 +00:00
commit 3327521bd3
23 changed files with 18366 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.*sw*

1
.well-known/oauth3 Symbolic link
View File

@ -0,0 +1 @@
../assets/org.oauth3/.well-known/oauth3

3
README.md Normal file
View File

@ -0,0 +1,3 @@
This is taken from parts of org.oauth3-frontend and oauth3.js
Needs a proper README. TODO cc / @coolaj86

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

10220
assets/com.jquery/jquery-3.1.1.js vendored Normal file

File diff suppressed because it is too large Load Diff

12
authnocode.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>authNoCode</title>
</head>
<body>
Trouble shooting steps to get the code
</body>
<script src=""></script>
</html>

12
authnopass.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>authNoCode</title>
</head>
<body>
Explanation for no password
</body>
<script src=""></script>
</html>

7
css/main.css Normal file
View File

@ -0,0 +1,7 @@
.dap-main {
background-color: #add8e6;
}
.dap-logo {
height: 80px;
width: 80px;
}

8
css/mock-provider.css Normal file
View File

@ -0,0 +1,8 @@
.mock-main {
background-color: #98fb98;
}
.js-provider-logo {
height: 80px;
width: 80px;
}

296
css/style.css Normal file
View File

@ -0,0 +1,296 @@
.dap-centered-text {
text-align: center;
}
.dap-centered-div {
display: flex;
margin: 0 auto;
flex-direction: column;
}
.dap-space-on-top {
margin-top: 10px;
}
.js-remember-label {
display: flex;
margin: 0 auto;
}
.dap-scrunch-bottom {
margin-top: 0;
}
.dap-scrunch-top {
margin-bottom: 0;
}
.dap-scrunch-both {
margin-bottom: 0;
margin-top: 0;
}
.js-remember-checkbox {
display: none;
}
.js-auth-checkbox {
display: none;
}
.dap-bordered {
margin: 0 auto;
width: 400px;
padding: 20px 20px 5px 20px;
border-top: 3px solid #6D99ed;
border-bottom: 3px solid #5C6FE0;
background-image: linear-gradient(#6D99ed, #5C6FE0),
linear-gradient(#6D99ed, #5C6FE0);
background-size: 3px 100%;
background-position: 0 0, 100% 0;
background-repeat: no-repeat;
}
.dap-normal-text {
font-family: 'Lato', sans-serif;
font-size: 25px;
}
.dap-med-text {
font-family: 'Lato', sans-serif;
font-size: 18px;
}
.dap-small-text {
font-family: 'Lato', sans-serif;
font-size: 14px;
color: #777;
}
.dap-purple-text {
font-family: 'Lato', sans-serif;
font-size: 18px;
color: #7464ed;
}
.dap-help-text {
font-family: 'Lato', sans-serif;
font-size: 14px;
text-decoration: underline;
color: #999;
}
.dap-input {
height: 50px;
width: 350px;
margin: 0 6% 0 6%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #777;
}
.dap-input::-webkit-input-placeholder {
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #ccc;
}
.dap-full-button-green {
background-image: -webkit-linear-gradient(top, #00C267, #22A05C);
height: 52px;
width: 356px;
box-shadow: 0 0 8px #ccc;
border-radius: 5px;
border: none;
padding: 1px;
margin: 10px 6% 0 6%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #fff;
}
.dap-full-button-pink {
background-image: -webkit-linear-gradient(top, #FF5C5C, #E54043);
height: 52px;
width: 356px;
box-shadow: 0 0 8px #ccc;
border-radius: 5px;
border: none;
padding: 1px;
margin: 10px 6% 0 6%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #fff;
}
.dap-full-button-purple {
background-image: -webkit-linear-gradient(top, #6d99ed, #5C6FE0);
height: 52px;
width: 356px;
box-shadow: 0 0 8px #ccc;
border-radius: 5px;
border: none;
padding: 1px;
margin: 10px 6% 0 6%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #fff;
}
.dap-3-4-button-green {
background-image: -webkit-linear-gradient(top, #93d89c, #39a04a);
height: 52px;
width: 238px;
box-shadow: 0 0 8px #ccc;
border-radius: 5px;
border: none;
padding: 1px;
margin: 10px 2% 0 2%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #fff;
}
.dap-1-4-button-purple {
background-image: -webkit-linear-gradient(top, #6d99ed, #5C6FE0);
height: 52px;
width: 119px;
box-shadow: 0 0 8px #ccc;
border-radius: 5px;
border: none;
padding: 1px;
margin: 10px 2% 0 2%;
text-align: center;
font-family: 'Lato', sans-serif;
font-size: 25px;
color: #fff;
}
.dap-3-4-span {
float: left;
margin-left: 10%;
}
.dap-1-4-span {
float: right;
}
.dap-social-media {
display: flex;
height: 50px;
width: 330px;
margin: 0 5% 0 5%;
padding-left: 15px;
padding-right: 15px;
justify-content: space-between;
}
.fa-gray {
color: #777;
}
.fa-purple {
color: #5C6FE0;
}
.icon-centered-3x {
margin: 0 162px 0 162px;
}
.dap-user-plus-app {
width: 300px;
display: flex;
justify-content: space-around;
margin: 0 auto;
}
.dap-user-plus-app > .fa-gray {
margin-top: 12px;
}
.dap-app-auth-list {
display: flex;
flex-direction: column;
}
.dap-app-auth-list > li {
display: flex;
}
.fa-square-o > span {
margin-left: 12px !important;
}
.dap-remember-margin {
margin-right: 7px !important;
}
.dap-remember-me {
margin-top: 7px;
margin-left: 5px;
}
.dap-app-auth-list > li > span {
margin-top: 4px;
margin-left: 8px;
}
.dap-li-disabled {
opacity: 0.4;
}
/* --------------- Line Around Effect ----------- */
.dap-line-around {
overflow: hidden;
text-align: center;
color: #777;
font-family: 'Lato', sans-serif;
font-size: 14px;
}
.dap-line-around:before, .dap-line-around:after {
background-color: #ccc;
content: "";
display: inline-block;
height: 1px;
position: relative;
vertical-align: middle;
width: 41%;
}
.dap-line-around:before {
right: .5em;
margin-left: -50%;
}
.dap-line-around:after {
left: .5em;
margin-right: -50%;
}
/* ------------------------------------------------ */
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
button:disabled {
opacity: 0.6;
}
.dap-lab-logo {
height: 78px;
width: auto;
border-radius: 50px;
}

BIN
img/Daplie-Badge-Purple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

BIN
img/Daplie-Labs-800x800.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
img/daplie-provider.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
img/not-provider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

130
index.html Normal file
View File

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login Facilitator: OAuth3.org</title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:300">
<script src="https://use.fontawesome.com/3af0faae66.js"></script>
</head>
<body class="fade mock-main">
<!-- STEP 1: ask the user where they want to log in -->
<!-- STEP 2: ask the user for their email -->
<!-- STEP 3+4: ask for login code and to remember device -->
<!-- TODO: remember-me-not implementation? -->
<!-- <button class="btn btn-secondary js-authz-show js-authz-remember-me-not">Just this once</button>-->
<!-- Step 5: ask for permissions -->
<div class="dap-bordered js-userid-container" style="display: none;">
<p class="dap-centered-text dap-normal-text">Please, sign in to Daplie Labs...</p>
<form method="post" action="">
<input type="email" class="dap-input js-oauth3-email emailInput" placeholder="Input your e-mail"></input>
<button class="dap-full-button-green js-authn-show" disabled>CONTINUE</button>
</form>
<p class="dap-line-around">or</p>
<div class="dap-social-media dap-normal-text">
<span class="fa fa-2x fa-gray fa-facebook-square js-facebook-login"></span>
<span class="fa fa-2x fa-gray fa-twitter-square js-twitter-login"></span>
<span class="fa fa-2x fa-gray fa-google-plus-square js-google-login"></span>
<span class="fa fa-2x fa-gray fa-github-square js-github-login"></span>
<span class="fa fa-2x fa-gray fa-plus-square js-gitlab-login"></span>
</div>
<br>
<a href="./loginwhatis.html" target="_blank"><p class="dap-centered-text dap-help-text">What is this?</p></a>
</div>
<div class="dap-bordered js-authn">
<div class="dap-normal-text">
<span class="fa fa-3x icon-centered-3x fa-purple fa-envelope"></span>
</div>
<p class="dap-centered-text dap-scrunch-top dap-normal-text">A special sign-in code was sent to:</p>
<p class="dap-centered-text dap-scrunch-both dap-purple-text"><span class="js-user-email">&nbsp;</span></p>
<p class="dap-centered-text dap-scrunch-bottom dap-med-text">Please enter the code below:</p>
<form method="post" onsubmit="">
<input type="hidden" class="js-authn-otp-uuid">
<input class="dap-input js-authn-otp-code" placeholder="XXXX-XXXX-XXXX"></input>
<div class="dap-centered-div dap-space-on-top">
<label class="js-remember-label dap-normal-text">
<span class="fa fa-2x fa-purple fa-square-o dap-remember-margin js-remember-status"></span>
<span class="dap-remember-me noselect">Remember this device.</span>
<input class="js-remember-checkbox" type="checkbox" checked="false"></input>
</label>
</div>
<button class="dap-full-button-green js-remember-btn js-authz-remember-me">SIGN IN ONCE</button>
</form>
<a href="./authnocode.html" target="_blank">
<p class="dap-centered-text dap-help-text">I didn't receive my code...</p>
</a>
<a href="./authnopass.html" target="_blank">
<p class="dap-centered-text dap-help-text">Why am I not using a password?</p>
</a>
</div>
<div class="dap-bordered dap-normal-text js-authz">
<br>
<div class="dap-user-plus-app">
<span class="fa fa-3x fa-purple fa-user-circle"></span>
<span class="fa fa-2x fa-gray fa-plus"></span>
<img class="dap-lab-logo" src="./img/Daplie-Badge-Purple.png" alt="Daplie Labs Logo">
</div>
<p class="dap-centered-text dap-normal-text"> OK! Almost done. Allow app to...?</p>
<br>
<form class="js-authorization-decision" action="#">
<ul class="js-scopes-container dap-app-auth-list">
<li class="checkbox fa fa-check-square-o dap-purple-text js-auth-li-enabled">
<span class="dap-small-text js-scope-desc noselect">&nbsp;</span>
<input class="checkbox js-scope-toggle js-auth-checkbox" type="checkbox">
</li>
</ul>
<div>
<button class="dap-full-button-green js-login-allow" type="button">AUTHORIZE THIS APP</button>
<button class="dap-full-button-pink js-login-deny" type="button">DENY THIS APP</button>
</div>
</form>
</div>
<!-- TODO: Remove Inline Style - Hidden until added into process -->
<div style="display: none" class="dap-bordered dap-normal-text">
<br>
<div class="dap-user-plus-app">
<span class="fa fa-3x fa-purple fa-user-circle"></span>
<span class="fa fa-2x fa-gray fa-plus"></span>
<span class="fa fa-3x fa-purple fa-laptop"></span>
</div>
<p class="dap-centered-text dap-scrunch-top dap-normal-text">It looks like your user agent is</p>
<p><span class="js-sniffed-device"></span></p>
<p class="dap-centered-text dap-scrunch-bottom dap-med-text">How long would you like to trust this device?</p>
<button class="dap-3-4-button-green js-authz-remember-me">FOREVER</button>
<button class="dap-1-4-button-purple js-authz-remember-me-not">ONE DAY</button>
<span class="dap-help-text dap-3-4-span">Great if you aren't paranoid.</span>
<span class="dap-help-text dap-1-4-span">Great if you're paranoid.</span>
<br>
<br>
<br>
<br>
<p class="dap-centered-text dap-help-text">What is this?</p>
</div>
<div class="dap-bordered dap-normal-text js-logout-container">
<p class="dap-centered-text">Sign out of Daplie and all Applications?</p>
<button type="button" class="dap-full-button-green js-logout">Sign Out</button>
</div>
<!--[if IE]><script src="bower_components/rsvp.js/rsvp.js"></script><![endif]-->
<script src="/assets/com.jquery/jquery-3.1.1.js"></script>
<script src="./js/mock.js"></script>
<script src="./js/script.js"></script>
<script src="/assets/org.oauth3/oauth3.core.js"></script>
<script src="/assets/org.oauth3/oauth3.issuer.js"></script>
<!--script src="/assets/org.oauth3/oauth3.mock.js"></script-->
</body>
</html>

11
install.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
mkdir -p assets
if [ -d ./assets/org.oauth3 ]; then
git clone git@git.daplie.com:Daplie/oauth3.js.git ./assets/org.oauth3
fi
pushd ./assets/org.oauth3
git checkout v1
git pull
popd
bower install rsvp

182
js/3rd-party.js Normal file
View File

@ -0,0 +1,182 @@
(function () {
'use strict';
////////////////////////
// //
// 3rd Party Logins //
// //
////////////////////////
util.facebookLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var ppid = '';
var authObj = window.OAUTH3.core.implicitGrant(
{ authorization_dialog: { url:'https:////www.facebook.com/v2.8/dialog/oauth' }
}
, { redirectUri: 'https://' + CONFIG.host + '/.well-known/oauth3/callback.html'
, appId: '590912911107527'
}
);
var signinW = window.open(
authObj.url
, "third-party-provider"
);
var callbackName = '--oauth3-callback-' + authObj.state;
console.log('authobj: ', authObj);
console.log('callback: ',callbackName);
window[callbackName] = function (obj) {
console.log('callback obj: ', obj);
$.ajax({
url: "https://graph.facebook.com/me"
, headers: {authorization: "Bearer " + obj.access_token}
}).then( function (ajaxObj) {
console.log("Ajax obj: ", ajaxObj);
ppid = ajaxObj.id;
});
};
};
util.twitterLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var authObj = window.OAUTH3.core.implicitGrant(
{ authorization_dialog: { url:'https://api.twitter.com/oauth/authorize' }
}
, { redirectUri: 'https://' + CONFIG.host + '/.well-known/oauth3/callback.html'
, appId: 'HJuxVttZUX4kPmbafvzmcuU1O'
}
);
var signinW = window.open(
authObj.url
, "third-party-provider"
);
var callbackName = '--oauth3-callback-' + authObj.state;
console.log('authobj: ', authObj);
console.log('callback: ',callbackName);
window[callbackName] = function (obj) {
console.log('callback obj: ', obj);
};
};
util.googleLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var authObj = window.OAUTH3.core.implicitGrant(
{ authorization_dialog: { url:'https://accounts.google.com/o/oauth2/v2/auth' }
}
, { redirectUri: 'https://' + CONFIG.host + '/.well-known/oauth3/callback.html'
, appId: '458817232132-sdk9eioi22k36jqpj0mq3i89h6tsohut.apps.googleusercontent.com'
, scope: 'profile'
}
);
var signinW = window.open(
authObj.url
, "third-party-provider"
);
var callbackName = '--oauth3-callback-' + authObj.state;
console.log('authobj: ', authObj);
console.log('callback: ',callbackName);
window[callbackName] = function (obj) {
console.log('callback obj: ', obj);
$.ajax({
url: "https://www.googleapis.com/oauth2/v3/userinfo"
, headers: {authorization: "Bearer " + obj.access_token}
}).then( function (ajaxObj) {
console.log("Ajax obj: ", ajaxObj);
});
};
};
util.githubLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var ppid = '';
var authObj = window.OAUTH3.core.implicitGrant(
{ authorization_dialog: { url:'https://github.com/login/oauth/authorize' }
}
, { redirect_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/callback.html'
, client_id: 'df4d46a358c1f3519c60'
}
);
var signinW = window.open(
authObj.url
, "third-party-provider"
);
var callbackName = '--oauth3-callback-' + authObj.state;
console.log('authobj: ', authObj);
console.log('callback: ',callbackName);
window[callbackName] = function (obj) {
console.log('callback obj: ', obj);
$.ajax({
url: "https://api.github.com/user"
, headers: {authorization: "Bearer " + obj.access_token}
}).then( function (ajaxObj) {
console.log("Ajax obj: ", ajaxObj);
ppid = ajaxObj.id;
});
};
};
util.gitlabLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var ppid = '';
var authObj = window.OAUTH3.core.implicitGrant(
{ authorization_dialog: { url:'https://github.com/login/oauth/authorize' }
}
, { redirect_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/callback.html'
, client_id: 'df4d46a358c1f3519c60'
}
);
var signinW = window.open(
authObj.url
, "third-party-provider"
);
var callbackName = '--oauth3-callback-' + authObj.state;
console.log('authobj: ', authObj);
console.log('callback: ',callbackName);
window[callbackName] = function (obj) {
console.log('callback obj: ', obj);
$.ajax({
url: "https://api.github.com/user"
, headers: {authorization: "Bearer " + obj.access_token}
}).then( function (ajaxObj) {
console.log("Ajax obj: ", ajaxObj);
ppid = ajaxObj.id;
});
};
};
$('body').on('click', '.js-facebook-login', util.facebookLogin);
//$('body').on('click', '.js-twitter-login', util.twitterLogin);
$('body').on('click', '.js-google-login', util.googleLogin);
//$('body').on('click', '.js-github-login', util.githubLogin);
//$('body').on('click', '.js-gitlab-login', util.gitlabLogin);
//
// END 3rd Party Logins
//
}());

57
js/app.js Normal file
View File

@ -0,0 +1,57 @@
$(function () {
'use strict';
var OAUTH3 = window.OAUTH3;
//var myPort = window.location.host.replace(/[^:]+(:)?/, '$1');
//var providerUri = 'https://localhost.bar.daplie.me' + myPort;
var providerUri = 'oauth3.org';
var auth = OAUTH3.create();
auth.init().then(function () {
$('body').addClass('in');
});
auth.setProvider(providerUri).then(function () {
$('.js-signin').removeAttr('disabled');
return auth.authenticate({ windowType: 'background' }).then(function (session) {
console.info("Previously Granted:", session);
$('.js-signin').removeClass('in').hide();
$('.js-logout').show().addClass('in');
}, function (err) {
console.info("Pre-Auth Fail (okay):", err);
});
});
$('body').on('click', '.js-signin', function (ev) {
ev.preventDefault();
ev.stopPropagation();
auth.login().then(function (session) {
console.info('authorization tokens!', session);
$('.js-signin').removeClass('in').hide();
$('.js-logout').show().addClass('in');
}, function (err) {
window.alert(err.message);
});
});
$('body').on('click', '.js-logout', function (ev) {
ev.preventDefault();
ev.stopPropagation();
return auth.logout().then(function () {
localStorage.clear();
$('.js-signin').show().addClass('in');
$('.js-logout').removeClass('in').hide();
});
});
$('.js-logout').hide();
});

407
js/mock.js Normal file
View File

@ -0,0 +1,407 @@
$(function () {
'use strict';
var OAUTH3 = window.OAUTH3;
var CONFIG = {
host: OAUTH3.utils.clientUri(window.location)
, directives: null // will be populated before the login button appears
};
var loc = window.location;
var util = {};
var email;
var tpls = {
scope: $('.js-scopes-container').html()
};
$('.js-scopes-container').html('');
// TODO let query.parse do location.hash || location.search || location
var clientParams = OAUTH3.query.parse(window.location.hash || window.location.search);
if (/authorization_dialog/.test(window.location.href)) {
// OAUTH3.lintClientParams(params, window)
// OAUTH3.normalizeClientParams(params, window)
if (clientParams.debug) {
console.info("'debug' exists, debug mode enabled. :)");
}
if (-1 === [ 'token', 'code' ].indexOf(clientParams.response_type)) {
window.alert("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)");
return;
}
if (!clientParams.state || -1 !== [ 'undefined', 'null' ].indexOf(clientParams.state)) {
// TODO check bits
window.alert("'state' should exist as a crypto-random string with 128-bits of entropy (32 hex characters)");
return;
}
if (!clientParams.client_id || -1 !== [ 'undefined', 'null' ].indexOf(clientParams.client_id)) {
console.warn(
"'client_id' should exist as the uri identifying the client,"
+ " such as example.com or example.com:8080/my-app or, well,"
+ "'" + OAUTH3.url.normalize(window.document.referrer) + "'"
);
}
if (clientParams.client_uri) {
console.warn("'client_id' should be used instead of 'client_uri'");
}
if (!(clientParams.client_id || clientParams.client_uri)) {
window.alert("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)");
console.error("'response_type' must exist and be either 'token' (implicit flow) or 'code' (authorization flow)");
clientParams.client_id = clientParams.client_uri = OAUTH3.url.normalize(window.document.referrer);
}
if (!clientParams.redirect_uri) {
clientParams.redirect_uri = OAUTH3.url.normalize(clientParams.client_uri)
+ "/.well-known/oauth3/callback.html'";
window.alert("'redirect_uri' must exist and should point to '" + clientParams.redirect_uri + "'");
console.error("'redirect_uri' must exist and should point to '" + clientParams.redirect_uri + "'");
}
clientParams.referrer = window.document.referrer;
}
function normalizeSession(session) {
// TODO casing
// TODO expiry calculation
// TODO leave this up to OAUTH3
session.provider_uri = session.provider_rui || CONFIG.host;
session.client_uri = session.client_uri || CONFIG.host; // same as provider in this case
}
function getSession(providerUri) {
return OAUTH3.hooks.session.get(providerUri).then(function (session) {
if (session && session.access_token) {
normalizeSession(session);
return OAUTH3.PromiseA.resolve(session);
}
else {
return OAUTH3.PromiseA.reject(new Error("no access_token in session"));
}
});
}
function getGrants(session) {
var clientObj = OAUTH3.query.parse(loc.hash || loc.search);
var clientLogo = OAUTH3.url.normalize(clientObj.client_uri) // optional relative logo ?
+ '/.well-known/oauth3/logo-128x128.png'
;
var callbackUrl;
// TODO put in directives.json or similar
var grantDescriptions = {
'oauth3_authn': "Basic secure authentication"
, 'wallet': "Access to payments and subscriptions"
, 'bucket': "Access to file storage"
, 'db': "Access to app data"
, 'domains': "Domain registration (and Glue and NS records)" // TODO make an alias
, 'domains:glue': "Glue Record management (for vanity nameservers)"
, 'domains:ns': "Name Server management"
, 'dns': "DNS records (A/AAAA, TXT, SRV, MX, etc)"
, '*': "FULL ACCOUNT ACCESS"
};
if ('oauth3_authn' === clientParams.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);
}
$('.js-client-logo').attr('src', clientLogo);
//$('.js-user-avatar').attr('src', userAvatar);
return OAUTH3.authz.scopes(CONFIG.host, session, clientObj).then(function (scopes) {
if (!scopes.pending.length) {
// looks like we've done all of this before
OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientObj, scopes);
return;
}
// This is to prevent click-jacking
// TODO secure iFrame from click-jacking by requiring input?
// ex: input.security-code[type="text"].val(Math.random()); input.js-verify-code[placeholder="Type what you see"]
if (OAUTH3._browser.isIframe()) {
callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&error_description='
+ encodeURIComponent("You're requesting permission in an iframe, but the permissions have not yet been granted")
+ '&error_uri=' + encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED');
location.href = callbackUrl;
return;
}
// TODO handle special scopes
// ! always show permission dialog
// ^ switch user
// @n require actual login if not within n seconds
// * account takeover
scopes.pending.forEach(function (scope) {
var $scope = $(tpls.scope);
$scope.find('.js-scope-toggle').attr('name', scope);
$scope.find('.js-scope-toggle').prop('checked', true);
if (-1 !== scopes.granted.indexOf(scope)) {
$scope.find('.js-scope-toggle').prop('disabled', true);
}
// the front-end recognizes the scope as valid
// TODO list scopes in directive
if (grantDescriptions[scope]) {
$scope.find('.js-scope-desc').text(grantDescriptions[scope]);
}
else {
$scope.find('.js-scope-toggle').prop('checked', false);
$scope.find('.js-scope-toggle').prop('disabled', true);
$scope.find('.js-scope-desc').text(scope);
}
$('.js-scopes-container').append($scope);
});
$('.js-authz').show().addClass('in');
}, function (err) {
window.alert('grantResults: ' + err.message);
console.error('scope results', err);
});
}
util.checkAuthEmail = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var email = $(this).val();
// wizarding - email detection
if (/gmail|yahoo|msn|live/.test(email)) {
$('.js-provider-logo').attr('src', 'img/not-provider.png');
}
else {
$('.js-provider-logo').attr('src', 'img/daplie-provider.jpeg');
}
// TODO debounce 150ms
// TODO test email by mx record
if (/.+@.+\..+/.test(email)) {
$('.js-authn-show').removeAttr('disabled');
$('.js-oauth3-email').val(email);
}
else {
$('.js-authn-show').prop('disabled', true);
}
};
util.submitAuthEmail = function (ev) {
ev.preventDefault();
ev.stopPropagation();
$('.js-authn-show').prop('disabled', true);
// TODO loading
email = $('.js-oauth3-email').val();
return OAUTH3.authn.loginMeta(CONFIG.directives, {email: email, mock: true}).then(function (userResults) {
if (!userResults.data.error) {
console.log('User exists:', userResults);
}
if (userResults.data.error) {
$('.js-authn-show').removeAttr('disabled');
console.warn('User does not exist:', email);
console.warn('User Results:', userResults);
//window.alert('userResults: ' + userResults.data.error_description || userResults.data.error.message);
//return;
}
return OAUTH3.authn.otp(CONFIG.directives, {email: email, mock: true}).then(function (otpResults) {
if (otpResults.data.error) {
window.alert('otpResults: ' + otpResults.data.error_description || otpResults.data.error.message);
return;
}
var ua = window.navigator.userAgent;
$('.js-sniffed-device').text(ua);
$('.js-userid-container').removeClass('in').hide();
$('.js-authn').show().addClass('in');
$('.js-authn-otp-uuid').val(otpResults.data.uuid);
$('.js-user-email').text(email);
});
});
};
util.rememberDevice = function (ev) {
ev.preventDefault();
ev.stopPropagation();
util.submitLoginCode({
rememberDevice: true
});
};
util.rememberDeviceNot = function (ev) {
ev.preventDefault();
ev.stopPropagation();
util.submitLoginCode({
rememberDevice: false
});
};
// Reference Implementation
util.submitLoginCode = function (opts) {
// TODO
// perhaps we should check that the code is valid before continuing to login (so that we don't send the key)
// TODO
// we should be sending the public key for this device as a jwk along with the authentication
// (and how long to remember this device)
var uuid = $('.js-authn-otp-uuid').val();
var code = $('.js-authn-otp-code').val().trim();
return OAUTH3.authn.resourceOwnerPassword(CONFIG.directives, {
// TODO replace with signed hosted file
client_agree_tos: 'oauth3.org/tos/draft'
, client_id: CONFIG.host
, client_uri: CONFIG.host
, username: email
, password: undefined
, otp_code: code
// TODO should be otp_id (agnostic of uuid)
, otp_uuid: uuid
// add expiration to the refresh token and/or public key
, expire: opts.rememberDevice || (1 * 60 * 60 * 1000)
, mock: true
}).then(function (session) {
$('.js-authn').removeClass('in').hide();
function getAccount(session) {
if (session.token.sub) {
return OAUTH3.PromiseA.resolve(session);
}
return OAUTH3.requests.accounts.create(CONFIG.directives, session, {
display_name: email.replace(/@.*/, '')
, comment: "created for '" + email + "' by '" + CONFIG.host + "'"
, priority: 1000 // default priority for first account
, name: undefined // TODO we could ask in the UI
}).then(function (resp) {
var results = resp.data;
return OAUTH3.hooks.session.refresh(session, {
access_token: (results.access_token || results.accessToken)
, refresh_token: (results.refresh_token || results.refreshToken)
});
});
}
return getAccount(session).then(function () {
return getGrants(session);
});
});
};
util.acceptScopesAndLogin = function (ev) {
ev.preventDefault();
ev.stopPropagation();
// TODO choose from the selected accepted scopes
var acceptedScopes = [];
$('form.js-authorization-decision').find('input[type=checkbox]').each(function (i, el) {
var $input = $(el);
if ($input.prop('checked')/* && !$input.prop('disabled')*/) {
acceptedScopes.push($input.attr('name'));
}
});
getSession(CONFIG.host).then(function (session) {
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
return OAUTH3.authz.scopes(CONFIG.host, session, clientParams).then(function (scopes) {
scopes.new = acceptedScopes;
return OAUTH3.authz.redirectWithToken(CONFIG.host, session, clientParams, scopes);
});
}, function (err) {
console.error("Accept Scopes and Login");
console.error(err);
});
};
util.closeLoginDeny = function (ev) {
ev.preventDefault();
ev.stopPropagation();
var loginWinObj = OAUTH3.query.parse(loc.hash || loc.search);
var denyObj = {
error: 'access_denied'
, error_description: 'The user has denied access.'
, error_uri: 'https://' + CONFIG.host + '/.well-known/oauth3/errors.html#/?error=access_denied'
, state: loginWinObj.state
, scope: loginWinObj.scope
};
window.location = loginWinObj.redirect_uri + '#' + OAUTH3.query.stringify(denyObj);
};
util.handleLogout = function () {
var clientParams = OAUTH3.query.parse(loc.hash || loc.search);
localStorage.clear();
clientParams.redirect_uri += '?' + OAUTH3.query.stringify({
state: clientParams.state
, debug: clientParams.debug
});
window.location = OAUTH3.url.resolve(clientParams.client_uri, clientParams.redirect_uri);
};
//
// Page Setup
//
$('.js-userid-container').hide();
$('.js-authn').hide();
$('.js-authz').hide();
$('body').on('click', '.js-logout', util.handleLogout);
$('body').on('click', '.js-authn-show', util.submitAuthEmail);
$('body').on('click', '.js-authz-remember-me', util.rememberDevice);
$('body').on('click', '.js-authz-remember-me-not', util.rememberDeviceNot);
$('body').on('click', '.js-login-allow', util.acceptScopesAndLogin);
$('body').on('click', '.js-login-deny', util.closeLoginDeny);
$('body').on('keyup', 'form .js-oauth3-email', util.checkAuthEmail);
function handleAuthorizationDialog() {
return getSession(CONFIG.host).then(function (session) {
return getGrants(session);
}, function (e) {
var clientObj = OAUTH3.query.parse(loc.hash || loc.search);
// TODO select the providers the client wants to show
// providers=daplie.com,facebook.com,google.com // etc
// TODO let the client specify switch_user
// TODO let the client specify relogin if stale
if (OAUTH3._browser.isIframe()) {
var callbackUrl = clientObj.redirect_uri + '#state=' + clientObj.state + '&error=access_denied&error_description='
+ encodeURIComponent("You're requesting permission in an iframe, but the user is not yet authenticated")
+ '&error_uri=' + encodeURIComponent('https://oauth3.org/docs/errors/#E_IFRAME_DENIED');
location.href = callbackUrl;
}
$('.js-userid-container').show();
}).then(function () {
//$('body').addClass('in');
});
}
// Session initialization
return $.ajax({ url: '.well-known/oauth3/directives.json' }).then(function (directives) {
// TODO cache directives in memory (and storage)
CONFIG.directives = directives;
directives.issuer = directives.issuer || (window.location.host + window.location.pathname).replace(/\/$/, '');
$('.js-authorization-dialog').hide();
$('.js-logout-container').hide();
if (/authorization_dialog/.test(window.location.href)) {
$('.js-authorization-dialog').show();
handleAuthorizationDialog();
}
else if (/logout/.test(window.location.href)) {
$('.js-logout-container').show();
}
$('body').addClass('in');
});
});

38
js/script.js Normal file
View File

@ -0,0 +1,38 @@
$('body').on('click', '.js-remember-label', function (ev) {
ev.preventDefault();
ev.stopPropagation();
if ($('.js-remember-label').find('.js-remember-checkbox').prop('checked') === true ) {
$('.js-remember-label').find('.js-remember-status').removeClass('fa-check-square-o');
$('.js-remember-label').find('.js-remember-status').addClass('fa-square-o dap-remember-margin');
$('.js-remember-label').find('.js-remember-checkbox').prop('checked', false);
$('.js-remember-btn').removeClass('dap-full-button-purple');
$('.js-remember-btn').addClass('dap-full-button-green');
$('.js-remember-btn').text('SIGN IN ONCE');
} else if ($('.js-remember-label').find('.js-remember-checkbox').prop('checked') === false ) {
$('.js-remember-label').find('.js-remember-status').removeClass('fa-square-o dap-remember-margin');
$('.js-remember-label').find('.js-remember-status').addClass('fa-check-square-o');
$('.js-remember-label').find('.js-remember-checkbox').prop('checked', true);
$('.js-remember-btn').removeClass('dap-full-button-green');
$('.js-remember-btn').addClass('dap-full-button-purple');
$('.js-remember-btn').text('SIGN IN FOREVER');
}
});
$('body').on('click', '.js-auth-li-enabled', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var $checkbox = $(this)
if ($checkbox.find('.js-auth-checkbox').prop('checked') === true ) {
$checkbox.removeClass('fa-check-square-o');
$checkbox.addClass('fa-square-o');
$checkbox.find('.js-auth-checkbox').prop('checked', false);
} else if ($checkbox.find('.js-auth-checkbox').prop('checked') === false ) {
$checkbox.removeClass('fa-square-o');
$checkbox.addClass('fa-check-square-o');
$checkbox.find('.js-auth-checkbox').prop('checked', true);
}
});

12
loginwhatis.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>loginWhatIs</title>
</head>
<body>
Helpful information about login
</body>
<script src=""></script>
</html>