Skip to content

Instantly share code, notes, and snippets.

@MikeLuDev
Last active March 29, 2018 17:31
Show Gist options
  • Save MikeLuDev/6429cb8d6b1f4fbf4e613cd1143b51ce to your computer and use it in GitHub Desktop.
Save MikeLuDev/6429cb8d6b1f4fbf4e613cd1143b51ce to your computer and use it in GitHub Desktop.
Password recovery implementation
//===============================================================================
// RECOVERY CALLS
//===============================================================================
const express = require('express');
const app = express();
const crypto = require('crypto');
app.get('/recovery', (req, res) => {
let messages = req.session.flash;
req.session.flash = null;
let recovery_page = ReactDOMServer.renderToString(
React.createElement(RecoveryPage, {
name: 'Tokes - Password Recovery',
dashboard: false,
messages: messages })
);
res.send(recovery_page);
req.session.flash = null;
});
app.post('/recovery', (req, res) => {
const crypto = require('crypto'),
algorithm = process.env.ENCRYPT_ALGORITHM,
password = process.env.ENCRYPT_PASSWORD;
let email = req.body.email;
// Generate recovery token with crypto
let recoveryToken = crypto.randomBytes(60).toString('hex');
// Ensure user email and recovery token exist
if (email && recoveryToken) {
// Query string
let emailQuery = `SELECT * FROM users WHERE email='${email}'`
// Query database by user email
db.query(emailQuery, function(err, rows) {
if (err) {
console.log(err);
req.flash('errorMessages', 'There was an error');
res.redirect('/');
}
// If the user exists, update user rows with recovery token and flash success
if (rows.length) {
let user = new User(rows[0]);
user.update({
recovery_token: recoveryToken
});
user.SendConfirmationEmail();
req.flash('appMessages', `We've sent an email to you with instructions to reset your password.`);
res.redirect('/');
} else {
req.flash('errorMessages', `Invalid email address. Please try again.`);
res.redirect('/recovery');
}
});
} else {
req.flash('errorMessages', 'There was an error generating your recovery email');
res.redirect('/');
}
});
// No token validation here to prevent sniffing based on url
app.get('/recovery/:recovery_token', (req, res) => {
let messages = req.session.flash;
req.session.flash = null;
let recoveryToken = req.params.recovery_token;
const reset_page = ReactDOMServer.renderToString(
React.createElement(ResetPage, {
name: 'Tokes - Reset Password',
dashboard: false,
messages: messages,
recovery_token: recoveryToken
})
);
res.send(reset_page);
});
app.post('/password/new', (req, res) => {
let recoveryToken = req.body.recovery_token;
let email = req.body.email;
let newPassword = req.body.new_password;
let verifyPassword = req.body.verify_password;
// Ensure passwords match each other
let passwordsMatch = (newPassword === verifyPassword);
if (!passwordsMatch) {
res.send({'status': 'error', 'message': 'The passwords you submitted did not match'});
}
else if (passwordsMatch) {
// Query for both email and recovery token
let recoveryQuery = `SELECT * FROM users WHERE email='${email}' AND recovery_token='${recoveryToken}'`;
db.query(recoveryQuery, function(err, rows){
if (err) {
console.log(err);
res.send({'status': 'error', 'message': 'There was an error'});
}
// If match is found
if (rows.length) {
let user = new User(rows[0]);
// Update user with new encrypted password, reset recovery token to null
user.update({
encrypted_password: user.generateHash(newPassword),
recovery_token: null
}).then( () => {
res.send({'status': 'success', 'message': 'Your password has been updated! You may now log in.'});
}).catch( () => {
res.send({'status': 'failure', 'message': 'There was an error updating your password'});
});
} else {
res.send({'status': 'error', 'message': 'Invalid email address or recovery link'});
}
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment