Added authentication/verification flow to account creation

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-10-03 22:04:41 -07:00
parent 389185a59c
commit 0b12ac9d20
4 changed files with 120 additions and 44 deletions

View File

@ -28,7 +28,7 @@
return callback(this.responseText, this); return callback(this.responseText, this);
} }
if (this.status == 200) { if (this.status >= 200 && this.status < 300) {
return callback(undefined, this); return callback(undefined, this);
} }
}; };

View File

@ -61,6 +61,11 @@
box-sizing: border-box; box-sizing: border-box;
} }
#requestAccess paper-button,
#login paper-button {
margin-top: 1em;
}
#header { #header {
padding: 0.5em; padding: 0.5em;
background: #ddd; background: #ddd;
@ -258,18 +263,42 @@
font-weight: bold; font-weight: bold;
} }
#loginStatus {
padding: 1em;
border: 2px solid #444;
margin: 1.5em -0.5em;
color: #222;
box-sizing: border-box;
}
#loginStatus iron-icon {
margin-right: 1em;
min-width: 1.5em;
display: inline-block;
}
#loginStatus .title {
font-weight: bold;
line-height: 1.5em;
}
#loginStatus .status {
margin-top: 0.5em;
}
#requestAccess { #requestAccess {
max-width: 60ex; max-width: 60ex;
border: 1px solid #444; border: 1px solid #444;
box-sizing: border-box; box-sizing: border-box;
} }
#requestAccess div > div { #requestAccess .title {
padding: 0.5em; padding: 0.5em;
background-color: #ddd;
} }
#requestAccess .title { #requestAccess #createButton {
background-color: #ddd; margin-top: 1.5em;
} }
</style> </style>
@ -365,6 +394,13 @@
provide your email address, and tell me who in the extended Ketrenos provide your email address, and tell me who in the extended Ketrenos
universe you know. If you're not a bot, I'll very likely give you access :)</p> universe you know. If you're not a bot, I'll very likely give you access :)</p>
</div> </div>
<div id="loginStatus" hidden$="[[!loginStatus]]" class="layout vertical justified start">
<div class="layout horizontal center">
<iron-icon icon="info-outline"></iron-icon>
<div class="title self-start">[[loginStatusTitle]]</div>
</div>
<div class="status self-start">[[loginStatus]]</div>
</div>
<paper-input tabindex=0 autofocus id="username" label="User ID" value="{{username}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 autofocus id="username" label="User ID" value="{{username}}" on-keypress="enterCheck"></paper-input>
<paper-input tabindex=0 id="password" label="Password" type="password" value="{{password}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 id="password" label="Password" type="password" value="{{password}}" on-keypress="enterCheck"></paper-input>
<paper-button tabindex=0 id="loginButton" disabled$="[[disableLogin(username,password)]]" on-tap="login" raised><div hidden$="[[loggingIn]]">login</div><div hidden$="[[!loggingIn]]"><paper-spinner active$="[[loggingIn]]"></paper-spinner></div></paper-button> <paper-button tabindex=0 id="loginButton" disabled$="[[disableLogin(username,password)]]" on-tap="login" raised><div hidden$="[[loggingIn]]">login</div><div hidden$="[[!loggingIn]]"><paper-spinner active$="[[loggingIn]]"></paper-spinner></div></paper-button>
@ -383,15 +419,18 @@
<div class="layout vertical"> <div class="layout vertical">
<div class="title">Create an account</div> <div class="title">Create an account</div>
<div> <div>
<p>To have your account activated, tell me who you know in the 'who do you know?' field.</p> <p>To have your account activated, tell me who you know in the 'who do you know?' field. You will receive
<p>Thanks,</p> an email with an authentication token; click the link in the email, and you're account will be verified. Once
<p>James</p> verified, I can grant you access to the system.
</p>
<p>Thanks,<br>
James</p>
</div> </div>
<paper-input tabindex=0 autofocus id="mail" label="E-mail" value="{{mail}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 autofocus id="mail" label="E-mail" value="{{username}}" on-keypress="enterCheck"></paper-input>
<paper-input tabindex=0 id="password" label="Password" type="password" value="{{password}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 id="password" label="Password" type="password" value="{{password}}" on-keypress="enterCheck"></paper-input>
<paper-input tabindex=0 id="name" label="Display name" value="{{name}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 id="name" label="Display name" value="{{name}}" on-keypress="enterCheck"></paper-input>
<paper-input tabindex=0 id="who" label="Who do you know?" value="{{who}}" on-keypress="enterCheck"></paper-input> <paper-input tabindex=0 id="who" label="Who do you know?" value="{{who}}" on-keypress="enterCheck"></paper-input>
<paper-button tabindex=0 id="createButton" disabled$="[[disableCreate(mail,password,name,who)]]" on-tap="create" raised><div hidden$="[[loggingIn]]">create</div><div hidden$="[[!loggingIn]]"><paper-spinner active$="[[loggingIn]]"></paper-spinner></div></paper-button> <paper-button tabindex=0 id="createButton" disabled$="[[disableCreate(username,password,name,who)]]" on-tap="create" raised><div hidden$="[[loggingIn]]">create</div><div hidden$="[[!loggingIn]]"><paper-spinner active$="[[loggingIn]]"></paper-spinner></div></paper-button>
</div> </div>
</paper-dialog> </paper-dialog>
<paper-toast id="toast"></paper-toast> <paper-toast id="toast"></paper-toast>
@ -409,6 +448,10 @@
type: String, type: String,
value: "" value: ""
}, },
loginStatus: {
type: String,
value: ""
},
username: { username: {
type: String, type: String,
value: "" value: ""
@ -417,10 +460,6 @@
type: String, type: String,
value: "" value: ""
}, },
mail: {
type: String,
value: ""
},
years: { years: {
type: Array, type: Array,
value: [] value: []
@ -484,8 +523,8 @@
return !username || username == "" || !password || password == ""; return !username || username == "" || !password || password == "";
}, },
disableCreate: function(mail, password, name, who) { disableCreate: function(username, password, name, who) {
return !mail || mail == "" || return !username || username == "" ||
!password || password == "" || !password || password == "" ||
!name || name == "" || !name || name == "" ||
!who || who == ""; !who || who == "";
@ -493,8 +532,16 @@
enterCheck: function(event) { enterCheck: function(event) {
if (event.key == 'Enter') { if (event.key == 'Enter') {
var next = event.currentTarget.nextElementSibling;
event.preventDefault(); event.preventDefault();
var next = event.currentTarget.nextElementSibling;
while (next && !next.hasAttribute("tabindex")) {
next = event.currentTarget.nextElementSibling;
}
if (!next) {
return;
}
if (next.tagName.toLowerCase() == "paper-button") { if (next.tagName.toLowerCase() == "paper-button") {
if (!next.disabled) { if (!next.disabled) {
next.click(); next.click();
@ -542,7 +589,7 @@
window.fetch("api/v1/users/login", function(error, xhr) { window.fetch("api/v1/users/login", function(error, xhr) {
this.loggingIn = false; this.loggingIn = false;
this.loading = false; this.loading = false;
this.password = ""; // this.password = "";
var user; var user;
if (error) { if (error) {
@ -566,9 +613,7 @@
return; return;
} }
if (user && user.username) {
this.user = user; this.user = user;
}
}.bind(this), null, "POST", { u: this.username, p: this.password }); }.bind(this), null, "POST", { u: this.username, p: this.password });
}, },
@ -582,7 +627,7 @@
window.fetch("api/v1/users/create", function(error, xhr) { window.fetch("api/v1/users/create", function(error, xhr) {
this.loggingIn = false; this.loggingIn = false;
this.loading = false; this.loading = false;
this.password = ""; // this.password = "";
var user; var user;
this.$.requestAccess.close(); this.$.requestAccess.close();
@ -615,7 +660,7 @@
w: this.who, w: this.who,
p: this.password, p: this.password,
n: this.name, n: this.name,
m: this.mail m: this.username
}); });
}, },
@ -1255,10 +1300,29 @@
this.resetPhotos(); this.resetPhotos();
this.path = ""; this.path = "";
if (user) {
this.mode = "memories"; if (!user) {
} else {
this.mode = "login"; this.mode = "login";
this.loginStatus = null;
return;
}
if (user.authenticated && user.mailVerified) {
this.loginStatus = null;
this.mode = "memories";
return;
}
this.mode = "login";
if (!user.mailVerified) {
this.loginStatusTitle = "Account not verified";
this.loginStatus = "An email has been sent to " + user.mail + ". " +
"Click the link in that email to verify your email address.";
} else if (!user.authenticated) {
this.loginStatusTitle = "Account not authorized";
this.loginStatus = "Your email address has been verified. Next, James needs to authorize your account. " +
"He has received an email and will process the request as quickly as he can.";
} }
}, },

View File

@ -149,6 +149,7 @@ app.use(basePath, function(req, res, next) {
if (results.length == 0) { if (results.length == 0) {
throw "DB mis-match between authentications and users table"; throw "DB mis-match between authentications and users table";
} }
let user = results[0], let user = results[0],
envelope = { envelope = {
to: config.get("admin.mail"), to: config.get("admin.mail"),
@ -160,6 +161,14 @@ app.use(basePath, function(req, res, next) {
html: hb.compile(templates.html)(user) html: hb.compile(templates.html)(user)
}; };
req.session.user = {
name: user.displayName,
mail: user.mail,
username: user.uid,
authenticated: user.authenticated,
mailVerified: user.mailVerified
};
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
let attempts = 10; let attempts = 10;

View File

@ -29,6 +29,8 @@ require("../db/users").then(function(db) {
}); });
router.get("/", function(req, res/*, next*/) { router.get("/", function(req, res/*, next*/) {
console.log("/users");
if (req.session.user) { if (req.session.user) {
return res.status(200).send(req.session.user); return res.status(200).send(req.session.user);
} }
@ -174,16 +176,14 @@ router.post("/create", function(req, res) {
send(envelope); send(envelope);
}); });
}).then(function() { }).then(function() {
/*
req.session.user = { req.session.user = {
name: name, name: name,
mail: mail, mail: mail,
username: username, username: mail,
authenticated: false,
mailVerified: false
}; };
return res.status(200).send(req.session.user); return res.status(200).send(req.session.user);
*/
req.session.user = {};
return res.status(401).send("Account has not been authenticated.");
}); });
}); });
}); });
@ -203,6 +203,7 @@ router.post("/login", function(req, res) {
return ldapPromise(username, password).then(function(user) { return ldapPromise(username, password).then(function(user) {
user.authenticated = 1; user.authenticated = 1;
user.mailVerified = 1;
return user; return user;
}).catch(function() { }).catch(function() {
console.log("User not found in LDAP. Looking up in DB."); console.log("User not found in LDAP. Looking up in DB.");
@ -226,20 +227,22 @@ router.post("/login", function(req, res) {
return res.status(401).send("Invalid login credentials"); return res.status(401).send("Invalid login credentials");
} }
if (!user.authenticated) {
console.log(username + " not authenticated.");
req.session.user = {};
return res.status(401).send("Account has not been authenticated.");
}
console.log("Logging in as " + user.displayName);
req.session.user = { req.session.user = {
name: user.displayName, name: user.displayName,
mail: user.mail, mail: user.mail,
username: user.uid username: user.uid,
authenticated: user.authenticated,
mailVerified: user.mailVerified
}; };
if (!user.mailVerified) {
console.log("Logged in as " + user.displayName + ", who is not verified email.");
} else if (!user.authenticated) {
console.log("Logged in as " + user.displayName + ", who is not authenticated.");
} else {
console.log("Logging in as " + user.displayName);
}
return res.status(200).send(req.session.user); return res.status(200).send(req.session.user);
}); });
}); });