Skip to content

Instantly share code, notes, and snippets.

@nosvalds
Last active October 18, 2020 13:50
Show Gist options
  • Save nosvalds/7a0eb6f742fbfcfb0914be3854e839aa to your computer and use it in GitHub Desktop.
Save nosvalds/7a0eb6f742fbfcfb0914be3854e839aa to your computer and use it in GitHub Desktop.
forgot password controller function
const table = process.env.USERS_TABLE;
const fs = require('fs');
const fsPromises = fs.promises;
const Handlebars = require("handlebars");
// AWS
const AWS = require('aws-sdk')
const dynamodb = new AWS.DynamoDB.DocumentClient();
const ses = new AWS.SES({region: 'us-east-1'}); // Simple email service
/**
* Generate a reset password token and send email to the user
* @param {*} req body.email - required
* @param {*} res
*/
const forgotPassword = async (req, res) => {
try {
// Retrieve user by email provided in the request
let user = await User.getByEmail(req.body.email);
// User not found, don't send failure as that could let hackers know which emails do exist
if (!user) {
return res.status(200).send()
}
// expire any existing tokens for the user
await User.expirePasswordTokens(user)
// password token expires after one hour
let expireDate = new Date();
expireDate.setHours(expireDate.getHours() + 1)
let token = createResetToken();
// create a new entry in the user's password_reset_token map
let updatedTokens = {
...user.password_reset_tokens, // use spread operator to copy exisiting token entries
[token]: {
"used": false,
"expiration": expireDate.toISOString(),
"updated": new Date().toISOString(),
"created": new Date().toISOString()
}
}
// prepare params to update User with new password_reset_tokens item
const params = {
TableName: table,
Key: {
email: user.email
},
UpdateExpression: "set password_reset_tokens=:v",
ExpressionAttributeValues: { ":v": updatedTokens },
ReturnValues: "ALL_NEW"
};
// use DynamoDB.DocumentClient to update
await dynamodb.update(params).promise();
// prep data for the email
let url = domain + '/password/reset?token=' + encodeURIComponent(token) + '&email=' + req.body.email
// if we're offline just log and send the reset URL
if (process.env.IS_OFFLINE) {
console.log("password_reset_url: "+ url);
return res.status(200).json({"password_reset_url": url})
}
let emailData = {
"url": url,
"toEmail": req.body.email,
"expire": expireDate.toLocaleDateString() + " " + expireDate.toLocaleTimeString(),
"year": expireDate.getFullYear(),
};
let filePath = process.cwd() + "/emailTemplates/forgotPasswordEmail.html";
// get HTML email template
let emailHtmlTemplate = await fsPromises.readFile(filePath);
// Inject data into the template
let templateHtml = Handlebars.compile(emailHtmlTemplate.toString());
let bodyHtml = templateHtml(emailData);
// Prepare SES Parameters
let params = {
Destination: {
ToAddresses: [emailData.toEmail]
},
Message: {
Body: {
Text: { Data: 'To reset your password, please click the link below.\n\n https://' + emailData.url
},
Html: {
Data: bodyHtml
}
},
Subject: {
Data: 'DigitalHumani - Password Reset Request'
}
},
Source: "info@DigitalHumani.com"
};
await ses.sendEmail(params).promise()
return res.status(200).json(`Password Reset Email sent successfully to ${emailData.toEmail}`)
}
catch (error) { return res.status(400).json({ error: error.message }); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment