Added client-side password checking
parent
de827a5543
commit
fc80498f2d
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
const slug = require('slug'),
|
const slug = require('slug'),
|
||||||
xss = require('xss'),
|
xss = require('xss'),
|
||||||
|
mellt = require('mellt'),
|
||||||
mw = require('../middleware.js'),
|
mw = require('../middleware.js'),
|
||||||
User = require('../models.js').user,
|
User = require('../models.js').user,
|
||||||
mail = require('../mail.js'),
|
mail = require('../mail.js'),
|
||||||
|
@ -130,37 +131,45 @@ router.route('/password/:token')
|
||||||
.get( (req,res)=>{
|
.get( (req,res)=>{
|
||||||
res.render('password');
|
res.render('password');
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
// Set new password
|
||||||
.post( (req,res,next)=>{
|
.post( (req,res,next)=>{
|
||||||
|
|
||||||
//TODO: Validate password
|
// Validate password
|
||||||
|
let daysToCrack = mellt.CheckPassword(req.body.password);
|
||||||
// Delete token
|
if (daysToCrack<10) {
|
||||||
res.locals.passwordUser.auth.passToken = undefined;
|
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.locals.passwordUser.auth.tokenExpires = undefined;
|
res.redirect(`/settings/password/${req.params.token}`);
|
||||||
|
} else {
|
||||||
// Create hash
|
|
||||||
res.locals.passwordUser.generateHash( req.body.password, (err,hash)=>{
|
// Delete token
|
||||||
if (err){
|
res.locals.passwordUser.auth.passToken = undefined;
|
||||||
mw.throwErr(err,req);
|
res.locals.passwordUser.auth.tokenExpires = undefined;
|
||||||
res.redirect(`/password/${req.params.token}`);
|
|
||||||
}
|
// Create hash
|
||||||
else {
|
res.locals.passwordUser.generateHash( req.body.password, (err,hash)=>{
|
||||||
|
if (err){
|
||||||
// Save new password to db
|
mw.throwErr(err,req);
|
||||||
res.locals.passwordUser.auth.password = hash;
|
res.redirect(`/password/${req.params.token}`);
|
||||||
res.locals.passwordUser.save()
|
}
|
||||||
.then( ()=>{
|
else {
|
||||||
req.flash('success', 'Password set. You can use it to log in now. ');
|
|
||||||
res.redirect('/login#login');
|
// Save new password to db
|
||||||
})
|
res.locals.passwordUser.auth.password = hash;
|
||||||
.catch( (err)=>{
|
res.locals.passwordUser.save()
|
||||||
mw.throwErr(err,req);
|
.then( ()=>{
|
||||||
res.redirect('/login#signup');
|
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');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
|
@ -13,17 +13,23 @@ router
|
||||||
subject: 'Test email',
|
subject: 'Test email',
|
||||||
text: mail.text("Looks like everything's working! "),
|
text: mail.text("Looks like everything's working! "),
|
||||||
html: mail.html("<p>Looks like everything's working! </p>")
|
html: mail.html("<p>Looks like everything's working! </p>")
|
||||||
}).then(()=>{
|
})
|
||||||
|
.then(()=>{
|
||||||
console.log("Test email should have sent...");
|
console.log("Test email should have sent...");
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
}).catch((err)=>{
|
})
|
||||||
|
.catch((err)=>{
|
||||||
mw.throwErr(err,req);
|
mw.throwErr(err,req);
|
||||||
next();
|
res.sendStatus(500);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
.get('/password', (req,res)=>{
|
.get('/password', (req,res)=>{
|
||||||
res.render('password');
|
res.render('password');
|
||||||
|
})
|
||||||
|
.post('/password', (req,res)=>{
|
||||||
|
//TODO: Server-side checks
|
||||||
|
res.sendStatus(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
|
@ -13,6 +13,7 @@
|
||||||
"express-validator": "^3.1.3",
|
"express-validator": "^3.1.3",
|
||||||
"firebase": "^3.7.2",
|
"firebase": "^3.7.2",
|
||||||
"kerberos": "0.0.17",
|
"kerberos": "0.0.17",
|
||||||
|
"mellt": "^1.0.0",
|
||||||
"moment": "^2.12.0",
|
"moment": "^2.12.0",
|
||||||
"mongodb": "^2.1.4",
|
"mongodb": "^2.1.4",
|
||||||
"mongoose": "^4.9.0",
|
"mongoose": "^4.9.0",
|
||||||
|
|
|
@ -87,6 +87,8 @@ pre {
|
||||||
.hide { display: none !important; }
|
.hide { display: none !important; }
|
||||||
.red, .red:hover { color: #fb6e3d !important; }
|
.red, .red:hover { color: #fb6e3d !important; }
|
||||||
.yellow, .yellow:hover { color: #fbc93d !important; }
|
.yellow, .yellow:hover { color: #fbc93d !important; }
|
||||||
|
.green, .green:hover { color: #8ae137 !important; }
|
||||||
|
|
||||||
.shadow {
|
.shadow {
|
||||||
-moz-box-shadow: .18vw .18vw .36vw #000;
|
-moz-box-shadow: .18vw .18vw .36vw #000;
|
||||||
-webkit-box-shadow: .18vw .18vw .36vw #000;
|
-webkit-box-shadow: .18vw .18vw .36vw #000;
|
||||||
|
@ -134,13 +136,13 @@ section {
|
||||||
font-weight:600;
|
font-weight:600;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 15px 30px;
|
padding: 15px 30px;
|
||||||
transition: 100ms;
|
|
||||||
cursor: pointer;
|
|
||||||
background: rgba(255,255,255,0.1);
|
background: rgba(255,255,255,0.1);
|
||||||
color: #eee;
|
color: #eee;
|
||||||
border: 1px solid #666;
|
|
||||||
border-radius: .5vw;
|
border-radius: .5vw;
|
||||||
} .btn:not(.disabled) {
|
} .btn:not(:disabled) {
|
||||||
|
border: 1px solid #666;
|
||||||
|
transition: 100ms;
|
||||||
|
cursor: pointer;
|
||||||
-moz-box-shadow:
|
-moz-box-shadow:
|
||||||
inset .11vw .18vw .52vw rgba(255,255,255,.2),
|
inset .11vw .18vw .52vw rgba(255,255,255,.2),
|
||||||
inset -.11vw -.18vw .52vw rgba(0,0,0,.4),
|
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(255,255,255,.2),
|
||||||
inset -.11vw -.18vw .52vw rgba(0,0,0,.4),
|
inset -.11vw -.18vw .52vw rgba(0,0,0,.4),
|
||||||
.18vw .18vw .36vw #000;
|
.18vw .18vw .36vw #000;
|
||||||
} .btn:hover:not(.disabled) {
|
} .btn:disabled {
|
||||||
|
border: 1px solid #999;
|
||||||
|
} .btn:hover:not(:disabled) {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: rgba(255,255,255,0.2);
|
background: rgba(255,255,255,0.2);
|
||||||
} .btn:active:not(.disabled) {
|
} .btn:active:not(:disabled) {
|
||||||
-moz-box-shadow:
|
-moz-box-shadow:
|
||||||
inset .11vw .18vw .52vw rgba(0,0,0,.4),
|
inset .11vw .18vw .52vw rgba(0,0,0,.4),
|
||||||
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
|
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
|
||||||
|
@ -166,10 +170,10 @@ section {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset .11vw .18vw .52vw rgba(0,0,0,.4),
|
inset .11vw .18vw .52vw rgba(0,0,0,.4),
|
||||||
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
|
inset -.11vw -.18vw .52vw rgba(255,255,255,.2);
|
||||||
} .btn:focus:not(.disabled){
|
} .btn:focus:not(:disabled){
|
||||||
border: 1px solid #fbc93d;
|
border: 1px solid #fbc93d;
|
||||||
}
|
}
|
||||||
.btn.main {
|
.btn.main:not(:disabled) {
|
||||||
color: #fbc93d;
|
color: #fbc93d;
|
||||||
}
|
}
|
||||||
.btn .fa {
|
.btn .fa {
|
||||||
|
|
|
@ -17,16 +17,21 @@ form label {
|
||||||
|
|
||||||
/* Input formatting */
|
/* Input formatting */
|
||||||
form input, form textarea, form select {
|
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;
|
color: #eee;
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
padding: 1% 1.5%;
|
padding: 1% 1.5%;
|
||||||
border: 1px solid #666;
|
|
||||||
border-radius: .3vw;
|
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:not(.input-addon):not(.input-with-addon):not([type="radio"]):not([type="checkbox"]),
|
||||||
form .input-with-addon-group {
|
form .input-with-addon-group {
|
||||||
min-width: 50%;
|
min-width: 50%;
|
||||||
|
|
|
@ -13,24 +13,40 @@
|
||||||
|
|
||||||
<form id='password-form' role="form" method="post">
|
<form id='password-form' role="form" method="post">
|
||||||
<style>
|
<style>
|
||||||
#password input {
|
#password-form .password {
|
||||||
min-width: 40%;
|
min-width: 40%;
|
||||||
|
margin-bottom: 2%;
|
||||||
|
}
|
||||||
|
#password-help {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
</style>
|
</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>
|
<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 id='password' class='form-group' title="Type your new password here">
|
<div class='form-group' style="flex-wrap:wrap">
|
||||||
<input class='form-control' name="password" type="password" placeholder="enter password" minlength="8" maxlength="160">
|
<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 class='form-control' name="repassword" type="password" placeholder="retype password" 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>
|
</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">
|
<div id='submit-group' class='form-group flexbox' style="justify-content:space-around">
|
||||||
<input class='btn yellow' style="width:50%; background:#333" type="submit" value="Save">
|
<input id='submit' class='btn main' style="min-width:50%" type="submit" value="Save" title="You need to enter a password first. " disabled>
|
||||||
<a href="#" class='btn'>cancel</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</section>
|
</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 %}
|
{% endblock %}
|
Loading…
Reference in New Issue