Merge pull request #6908 from piousbox/api-v3-password-reset
api-v3 password reset
This commit is contained in:
@@ -12,6 +12,10 @@
|
||||
"usernameTaken": "Username already taken.",
|
||||
"passwordConfirmationMatch": "Password confirmation doesn't match password.",
|
||||
"invalidLoginCredentials": "Incorrect username / email and / or password.",
|
||||
"passwordReset": "If we have your email on file, your password reset link has been sent to your email.",
|
||||
"passwordResetEmailSubject": "Password Reset for Habitica",
|
||||
"passwordResetEmailText": "Password for <%= username %> has been reset to <%= newPassword %> . Important! Both username and password are case-sensitive -- you must enter both exactly as shown here. We recommend copying and pasting both instead of typing them. Log in at <%= baseUrl %>. After you have logged in, head to <%= baseUrl %>/#/options/settings/settings and change your password.",
|
||||
"passwordResetEmailHtml": "Password for <strong><%= username %></strong> has been reset to <strong><%= newPassword %></strong>.<br /><br />Important! Both username and password are case-sensitive -- you must enter both exactly as shown here. We recommend copying and pasting both instead of typing them.<br /><br />Log in at <%= baseUrl %>. After you have logged in, head to <%= baseUrl %>/#/options/settings/settings and change your password.",
|
||||
"invalidCredentials": "User not found with given auth credentials.",
|
||||
"accountSuspended": "Account has been suspended, please contact leslie@habitica.com with your UUID \"<%= userId %>\" for assistance.",
|
||||
"onlyFbSupported": "Only Facebook supported currently.",
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
|
||||
describe('POST /user/reset-password', async () => {
|
||||
let endpoint = '/user/reset-password';
|
||||
let user;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('resets password', async () => {
|
||||
let previousPassword = user.auth.local.hashed_password;
|
||||
let response = await user.post(endpoint, {
|
||||
email: user.auth.local.email,
|
||||
});
|
||||
expect(response).to.eql({ message: t('passwordReset') });
|
||||
await user.sync();
|
||||
expect(user.auth.local.hashed_password).to.not.eql(previousPassword);
|
||||
});
|
||||
|
||||
it('same message on error as on success', async () => {
|
||||
let response = await user.post(endpoint, {
|
||||
email: 'nonExistent@email.com',
|
||||
});
|
||||
expect(response).to.eql({ message: t('passwordReset') });
|
||||
});
|
||||
|
||||
it('errors if email is not provided', async () => {
|
||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { model as EmailUnsubscription } from '../../models/emailUnsubscription';
|
||||
import { sendTxn as sendTxnEmail } from '../../libs/api-v3/email';
|
||||
import { decrypt } from '../../libs/api-v3/encryption';
|
||||
import FirebaseTokenGenerator from 'firebase-token-generator';
|
||||
import { send as sendEmail } from '../../libs/api-v3/email';
|
||||
|
||||
let api = {};
|
||||
|
||||
@@ -368,6 +369,56 @@ api.updatePassword = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {post} /user/reset-password
|
||||
* @apiVersion 3.0.0
|
||||
* @apiName resetPassword
|
||||
* @apiGroup User
|
||||
* @apiParam {string} email email
|
||||
* @apiSuccess {Object} The success message
|
||||
**/
|
||||
api.resetPassword = {
|
||||
method: 'POST',
|
||||
middlewares: [],
|
||||
url: '/user/reset-password',
|
||||
async handler (req, res) {
|
||||
req.checkBody({
|
||||
email: {
|
||||
notEmpty: {errorMessage: res.t('missingEmail')},
|
||||
},
|
||||
});
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
let email = req.body.email.toLowerCase();
|
||||
let salt = passwordUtils.makeSalt();
|
||||
let newPassword = passwordUtils.makeSalt(); // use a salt as the new password too (they'll change it later)
|
||||
let hashedPassword = passwordUtils.encrypt(newPassword, salt);
|
||||
|
||||
let user = await User.findOne({ 'auth.local.email': email }, { 'auth.local': 1 });
|
||||
|
||||
if (user) {
|
||||
user.auth.local.salt = salt;
|
||||
user.auth.local.hashed_password = hashedPassword; // eslint-disable-line camelcase
|
||||
sendEmail({
|
||||
from: 'Habitica <admin@habitica.com>',
|
||||
to: email,
|
||||
subject: res.t('passwordResetEmailSubject'),
|
||||
text: res.t('passwordResetEmailText', { username: user.auth.local.username,
|
||||
newPassword,
|
||||
baseUrl: nconf.get('BASE_URL'),
|
||||
}),
|
||||
html: res.t('passwordResetEmailHtml', { username: user.auth.local.username,
|
||||
newPassword,
|
||||
baseUrl: nconf.get('BASE_URL'),
|
||||
}),
|
||||
});
|
||||
await user.save();
|
||||
}
|
||||
res.respond(200, { message: res.t('passwordReset') });
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @api {put} /user/auth/update-email
|
||||
* @apiVersion 3.0.0
|
||||
|
||||
@@ -28,7 +28,6 @@ api.unsubscribe = {
|
||||
notEmpty: {errorMessage: res.t('missingUnsubscriptionCode')},
|
||||
},
|
||||
});
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user