Added client-side password checking

master
Keith Irwin 2017-04-15 10:22:13 -04:00
parent de827a5543
commit fc80498f2d
No known key found for this signature in database
GPG Key ID: 378933C743E2BBC0
6 changed files with 95 additions and 54 deletions

View File

@ -2,6 +2,7 @@
const slug = require('slug'),
xss = require('xss'),
mellt = require('mellt'),
mw = require('../middleware.js'),
User = require('../models.js').user,
mail = require('../mail.js'),
@ -130,37 +131,45 @@ router.route('/password/:token')
.get( (req,res)=>{
res.render('password');
} )
// Set new password
.post( (req,res,next)=>{
//TODO: Validate password
// Delete token
res.locals.passwordUser.auth.passToken = undefined;
res.locals.passwordUser.auth.tokenExpires = undefined;
// Create hash
res.locals.passwordUser.generateHash( req.body.password, (err,hash)=>{
if (err){
mw.throwErr(err,req);
res.redirect(`/password/${req.params.token}`);
}
else {
// Save new password to db
res.locals.passwordUser.auth.password = hash;
res.locals.passwordUser.save()
.then( ()=>{
req.flash('success', 'Password set. You can use it to log in now. ');
res.redirect('/login#login');
})
.catch( (err)=>{
mw.throwErr(err,req);
res.redirect('/login#signup');
});
}
} );
// Validate password
let daysToCrack = mellt.CheckPassword(req.body.password);
if (daysToCrack<10) {
mw.throwErr(new Error(`That password could be cracked in ${daysToCrack} days! Come up with a more complex password that would take at least 10 days to crack. `));
res.redirect(`/settings/password/${req.params.token}`);
} else {
// Delete token
res.locals.passwordUser.auth.passToken = undefined;
res.locals.passwordUser.auth.tokenExpires = undefined;
// Create hash
res.locals.passwordUser.generateHash( req.body.password, (err,hash)=>{
if (err){
mw.throwErr(err,req);
res.redirect(`/password/${req.params.token}`);
}
else {
// Save new password to db
res.locals.passwordUser.auth.password = hash;
res.locals.passwordUser.save()
.then( ()=>{
req.flash('success', 'Password set. You can use it to log in now. ');
res.redirect('/login#login');
})
.catch( (err)=>{
mw.throwErr(err,req);
res.redirect('/login#signup');
});
}
} );
}
} );

View File

@ -13,17 +13,23 @@ router
subject: 'Test email',
text: mail.text("Looks like everything's working! "),
html: mail.html("<p>Looks like everything's working! </p>")
}).then(()=>{
})
.then(()=>{
console.log("Test email should have sent...");
res.sendStatus(200);
}).catch((err)=>{
})
.catch((err)=>{
mw.throwErr(err,req);
next();
res.sendStatus(500);
});
})
.get('/password', (req,res)=>{
res.render('password');
})
.post('/password', (req,res)=>{
//TODO: Server-side checks
res.sendStatus(200);
});
module.exports = router;

View File

@ -13,6 +13,7 @@
"express-validator": "^3.1.3",
"firebase": "^3.7.2",
"kerberos": "0.0.17",
"mellt": "^1.0.0",
"moment": "^2.12.0",
"mongodb": "^2.1.4",
"mongoose": "^4.9.0",

View File

@ -87,6 +87,8 @@ pre {
.hide { display: none !important; }
.red, .red:hover { color: #fb6e3d !important; }
.yellow, .yellow:hover { color: #fbc93d !important; }
.green, .green:hover { color: #8ae137 !important; }
.shadow {
-moz-box-shadow: .18vw .18vw .36vw #000;
-webkit-box-shadow: .18vw .18vw .36vw #000;
@ -134,13 +136,13 @@ section {
font-weight:600;
display: inline-block;
padding: 15px 30px;
transition: 100ms;
cursor: pointer;
background: rgba(255,255,255,0.1);
color: #eee;
border: 1px solid #666;
border-radius: .5vw;
} .btn:not(.disabled) {
} .btn:not(:disabled) {
border: 1px solid #666;
transition: 100ms;
cursor: pointer;
-moz-box-shadow:
inset .11vw .18vw .52vw rgba(255,255,255,.2),
inset -.11vw -.18vw .52vw rgba(0,0,0,.4),
@ -153,10 +155,12 @@ section {
inset .11vw .18vw .52vw rgba(255,255,255,.2),
inset -.11vw -.18vw .52vw rgba(0,0,0,.4),
.18vw .18vw .36vw #000;
} .btn:hover:not(.disabled) {
} .btn:disabled {
border: 1px solid #999;
} .btn:hover:not(:disabled) {
text-decoration: none;
background: rgba(255,255,255,0.2);
} .btn:active:not(.disabled) {
} .btn:active:not(:disabled) {
-moz-box-shadow:
inset .11vw .18vw .52vw rgba(0,0,0,.4),
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
@ -166,10 +170,10 @@ section {
box-shadow:
inset .11vw .18vw .52vw rgba(0,0,0,.4),
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
} .btn:focus:not(.disabled){
} .btn:focus:not(:disabled){
border: 1px solid #fbc93d;
}
.btn.main {
.btn.main:not(:disabled) {
color: #fbc93d;
}
.btn .fa {

View File

@ -17,16 +17,21 @@ form label {
/* Input formatting */
form input, form textarea, form select {
-moz-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
-webkit-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
color: #eee;
background-color: #202020;
background-color: rgba(255,255,255,0.1);
padding: 1% 1.5%;
border: 1px solid #666;
border-radius: .3vw;
}
form input:not(:disabled), form textarea:not(:disabled), form select:not(:disabled) {
border: 1px solid #666;
-moz-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
-webkit-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
}
form input:disabled, form textarea:disabled form select:disabled {
border: 1px solid #999;
}
form input:not(.input-addon):not(.input-with-addon):not([type="radio"]):not([type="checkbox"]),
form .input-with-addon-group {
min-width: 50%;

View File

@ -13,24 +13,40 @@
<form id='password-form' role="form" method="post">
<style>
#password input {
#password-form .password {
min-width: 40%;
margin-bottom: 2%;
}
#password-help {
display: none;
}
</style>
<p>Your password must be at least 8 characters long. You can use any letter, number, symbol, emoji, or spaces. Your password will be stored as a secure hash on the server. </p>
<div id='password' class='form-group' title="Type your new password here">
<input class='form-control' name="password" type="password" placeholder="enter password" minlength="8" maxlength="160">
<input class='form-control' name="repassword" type="password" placeholder="retype password" minlength="8" maxlength="160">
<p>Your password must be at least 8 characters long. You can use any letter, number, symbol, emoji, or spaces. Your password will be stored as a salted hash on the server. </p>
<div class='form-group' style="flex-wrap:wrap">
<input id='p1' class='form-control password' name="password" type="password" placeholder="enter password" title="Type your new password here" minlength="8" maxlength="160">
<input id='p2' class='form-control password' name="repassword" type="password" placeholder="retype password" title="Retype your new password here" minlength="8" maxlength="160">
<span title="Show your passwords if nobody's looking over your shoulder. " style="margin:auto">
<input id='show' name="show" type="checkbox">
<label for="show">show</label>
</span>
</div>
<p id='password-help' title="Your passwords are checked using Mellt password cracker. "></p>
<div id='submit-group' class='form-group flexbox' style="padding:0 0 60px; justify-content:space-around">
<input class='btn yellow' style="width:50%; background:#333" type="submit" value="Save">
<a href="#" class='btn'>cancel</a>
<div id='submit-group' class='form-group flexbox' style="justify-content:space-around">
<input id='submit' class='btn main' style="min-width:50%" type="submit" value="Save" title="You need to enter a password first. " disabled>
</div>
</form>
</section>
{% endblock %}
{% block javascript %}
{{super()}}
<script src="/static/js/.mellt.min.js"></script>
<script src="/static/js/.common-passwords.min.js"></script>
<script src="/static/js/.password.min.js"></script>
{% endblock %}