Skip to content

Commit ead50d3

Browse files
author
David Lenton
committed
Merged in add-alternative-password-reset-url (pull request auth0#26)
Add alternative password reset url
2 parents 8353789 + 6d266f6 commit ead50d3

File tree

4 files changed

+121
-56
lines changed

4 files changed

+121
-56
lines changed

models/account.js

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -999,59 +999,63 @@ class User {
999999
sendReset(resetKey, options, done) {
10001000
// Send the invitation
10011001
const _this = this;
1002-
const subject = options.sitename + ': Reset password';
1003-
const message = '<p>You are receiving this email because you asked for your password to be reset for the ' +
1004-
options.sitename +
1005-
' site. If you did not ask for your password to be reset you can ignore this email.</p>\n\n' +
1006-
// 'Your unique key: \n\n' +
1007-
// '\t' + obj.key + '\n\n' +
1008-
'<p>To reset your password follow the link below:</p>\n\n' +
1009-
'<p>\t' +
1010-
options.protocol +
1011-
'://' +
1012-
options.hostname +
1013-
'/account/reset/' +
1014-
this.ref +
1015-
'/' +
1016-
resetKey +
1017-
'/</p>\n\n<p>' +
1018-
options.email +
1019-
'<br>\nvia the ' +
1020-
options.sitename +
1021-
' site</p>';
1022-
// HTML text
1023-
let htmlText = '';
1024-
const replacementsArray = [];
1025-
replacementsArray.push(['<!--PROTOCOL-->', options.protocol]);
1026-
replacementsArray.push(['<!--HOST-->', options.hostname]);
1027-
replacementsArray.push(['<!--SITENAME-->', options.sitename]);
1028-
replacementsArray.push(['<!--TITLE-->', subject]);
1029-
replacementsArray.push(['<!--BODY-->', message]);
1030-
replacementsArray.push(['<!--EMAIL-->', options.email]);
1031-
replacementsArray.push(['<!--CODA-->', '']);
1032-
replacementsArray.push([
1033-
'<p>',
1034-
'<p style="margin-bottom: 10px; font-weight: normal; font: 13px/ 18px Arial, sans-serif; color: #000000;">'
1035-
]);
1036-
fs.readFile('./templates/mail/default.html', 'utf8', (err, f) => {
1037-
if (err)
1038-
debug(err);
1039-
htmlText = f;
1040-
for (let i = 0; i < replacementsArray.length; i++) {
1041-
const re = new RegExp(replacementsArray[i][0], 'gi');
1042-
htmlText = htmlText.replace(re, replacementsArray[i][1]);
1043-
}
1044-
// Plain text
1045-
const plainText = h2p(message);
1046-
const msg = {
1047-
to: _this.email,
1048-
from: options.email,
1049-
subject: subject,
1050-
text: plainText,
1051-
html: htmlText
1052-
};
1053-
sendMail(msg, options.hostname);
1054-
done(null);
1002+
settings.load(options.appId, (err, config) => {
1003+
if (err) console.log(err);
1004+
const host = config.web_host || options.hostname;
1005+
const subject = options.sitename + ': Reset password';
1006+
const message = '<p>You are receiving this email because you asked for your password to be reset for the ' +
1007+
options.sitename +
1008+
' site. If you did not ask for your password to be reset you can ignore this email.</p>\n\n' +
1009+
// 'Your unique key: \n\n' +
1010+
// '\t' + obj.key + '\n\n' +
1011+
'<p>To reset your password follow the link below:</p>\n\n' +
1012+
'<p>\t' +
1013+
options.protocol +
1014+
'://' +
1015+
host +
1016+
'/account/reset/' +
1017+
this.ref +
1018+
'/' +
1019+
resetKey +
1020+
'/</p>\n\n<p>' +
1021+
options.email +
1022+
'<br>\nvia the ' +
1023+
options.sitename +
1024+
' site</p>';
1025+
// HTML text
1026+
let htmlText = '';
1027+
const replacementsArray = [];
1028+
replacementsArray.push(['<!--PROTOCOL-->', options.protocol]);
1029+
replacementsArray.push(['<!--HOST-->', options.hostname]);
1030+
replacementsArray.push(['<!--SITENAME-->', options.sitename]);
1031+
replacementsArray.push(['<!--TITLE-->', subject]);
1032+
replacementsArray.push(['<!--BODY-->', message]);
1033+
replacementsArray.push(['<!--EMAIL-->', options.email]);
1034+
replacementsArray.push(['<!--CODA-->', '']);
1035+
replacementsArray.push([
1036+
'<p>',
1037+
'<p style="margin-bottom: 10px; font-weight: normal; font: 13px/ 18px Arial, sans-serif; color: #000000;">'
1038+
]);
1039+
fs.readFile('./templates/mail/default.html', 'utf8', (err, f) => {
1040+
if (err)
1041+
debug(err);
1042+
htmlText = f;
1043+
for (let i = 0; i < replacementsArray.length; i++) {
1044+
const re = new RegExp(replacementsArray[i][0], 'gi');
1045+
htmlText = htmlText.replace(re, replacementsArray[i][1]);
1046+
}
1047+
// Plain text
1048+
const plainText = h2p(message);
1049+
const msg = {
1050+
to: _this.email,
1051+
from: options.email,
1052+
subject: subject,
1053+
text: plainText,
1054+
html: htmlText
1055+
};
1056+
sendMail(msg, options.hostname);
1057+
done(null);
1058+
});
10551059
});
10561060
}
10571061
sendResetNotification(options, done) {

models/tokens.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ exports.getAccessToken = function getAccessToken(obj, done) {
2929
};
3030

3131
exports.getRefreshToken = function getRefreshToken(obj, done) {
32+
let query = 'SELECT * FROM refresh_token WHERE token = ? AND device_id is null ';
33+
const params = [obj.token];
34+
if (obj.deviceId) {
35+
query = 'SELECT * FROM refresh_token WHERE token = ? AND device_id = ? ';
36+
params.push(obj.deviceId);
37+
}
3238
db.get().query(
33-
'SELECT * FROM refresh_token WHERE token = ? AND device_id = ?',
34-
[obj.token, obj.deviceId],
39+
query,
40+
params,
3541
(err, rows) => {
3642
if (err) return done(err);
3743
if (rows.length === 0) return done(null, null);

mysql/database.mwb

260 Bytes
Binary file not shown.

routes/api/account.js

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,68 @@ module.exports = function (app) {
4747
be authenticated before they are
4848
*/
4949

50+
const ONE_DAY = 60 * 60 * 1000 * 24; /* ms */
51+
52+
/* GET reset details */
53+
router.get('/reset/:ref/:key/', cors(), (req, res, next) => {
54+
const ref = req.params.ref;
55+
const appId = req.site.server.client_id;
56+
const account = new User(appId);
57+
account.loadByRef(ref, (err, json) => {
58+
if (err) {
59+
return next(new JsonError('This reset key is not valid'));
60+
}
61+
if (json.reset_key !== req.params.key)
62+
return next(new JsonError('This reset key is not valid'));
63+
if (json.reset_date) {
64+
if (new Date() - new Date(json.reset_date) > ONE_DAY) {
65+
return next(new JsonError('This reset key is out of date'));
66+
}
67+
}
68+
account.sanitise();
69+
return res.json(account);
70+
});
71+
});
72+
73+
/* POST reset details */
74+
router.post('/reset/:ref/:key/', cors(), (req, res, next) => {
75+
const ref = req.params.ref;
76+
const password = req.body.password ? req.body.password : '';
77+
const passwordConfirm = req.body.passwordConfirm
78+
? req.body.passwordConfirm
79+
: '';
80+
const appId = req.site.server.client_id;
81+
const account = new User(appId);
82+
account.loadByRef(ref, (err, json) => {
83+
if (err) {
84+
return next(new JsonError('This reset key is not valid', 400));
85+
}
86+
if (json.reset_key !== req.params.key)
87+
return next(new JsonError('This reset key is not valid', 400));
88+
if (json.reset_date) {
89+
if (new Date() - new Date(json.reset_date) > ONE_DAY) {
90+
return next(new JsonError('This reset key is out of date', 400));
91+
}
92+
}
93+
if (password.length === 0) return next(new JsonError('Password is missing', 400));
94+
if (passwordConfirm.length === 0) return next(new JsonError('Password confirmation is missing', 400));
95+
if (password !== passwordConfirm) return next(new JsonError('Your passwords do not match', 400));
96+
account.setPassword(password, (err) => {
97+
if (err) return next(new JsonError('There was a problem setting your password'));
98+
});
99+
return res.json(new JsonInfo('Your password was successfully updated'));
100+
});
101+
});
102+
50103
/* POST forgot page */
51104
router.post('/forgot', cors(), (req, res, next) => {
52105
if (!req.body || !req.body.username)
53106
throw new JsonError('You must specify an email address', 400);
107+
if (!isEmail(req.body.username))
108+
throw new JsonError('You must specify a valid email address', 400);
54109
let account = new User(req.site.server.client_id);
55110
account.loadByUsername(req.body.username, (err, user) => {
56-
if (err) return next(new JsonError('Unable to find the specified email address'));
111+
if (err || !user) return next(new JsonError('Unable to find the specified email address', 400));
57112
account = Object.assign(account, user);
58113
const appId = req.site.server.client_id;
59114
const options = {

0 commit comments

Comments
 (0)