Skip to content

Commit ea05a2c

Browse files
committed
Fix creation of verification links
Fix User.prototype.verify to call `querystring.stringify` instead of concatenating query-string components directly. In particular, this fixes the bug where `options.redirect` containing a hash fragment like `#/home?arg1=value1&arg2=value2` produced incorrect URL, because the `redirect` value was not correctly encoded.
1 parent 304ecc4 commit ea05a2c

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

common/models/user.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var isEmail = require('isemail');
1313
var loopback = require('../../lib/loopback');
1414
var utils = require('../../lib/utils');
1515
var path = require('path');
16+
var qs = require('querystring');
1617
var SALT_WORK_FACTOR = 10;
1718
var crypto = require('crypto');
1819
var MAX_PASSWORD_LENGTH = 72;
@@ -436,10 +437,10 @@ module.exports = function(User) {
436437
options.host +
437438
displayPort +
438439
urlPath +
439-
'?uid=' +
440-
options.user[pkName] +
441-
'&redirect=' +
442-
options.redirect;
440+
'?' + qs.stringify({
441+
uid: options.user[pkName],
442+
redirect: options.redirect,
443+
});
443444

444445
options.templateFn = options.templateFn || createVerificationEmailBody;
445446

test/user.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var request = require('supertest');
1010
var loopback = require('../');
1111
var User, AccessToken;
1212
var async = require('async');
13+
var url = require('url');
1314

1415
describe('User', function() {
1516
this.timeout(10000);
@@ -1690,6 +1691,29 @@ describe('User', function() {
16901691
expect(result.email).to.not.have.property('template');
16911692
});
16921693
});
1694+
1695+
it('allows hash fragment in redirectUrl', function() {
1696+
return User.create({email: 'test@example.com', password: 'pass'})
1697+
.then(user => {
1698+
let actualVerifyHref;
1699+
return user.verify({
1700+
type: 'email',
1701+
to: user.email,
1702+
from: 'noreply@myapp.org',
1703+
redirect: '#/some-path?a=1&b=2',
1704+
templateFn: (options, cb) => {
1705+
actualVerifyHref = options.verifyHref;
1706+
cb(null, 'dummy body');
1707+
},
1708+
})
1709+
.then(() => actualVerifyHref);
1710+
})
1711+
.then(verifyHref => {
1712+
var parsed = url.parse(verifyHref, true);
1713+
expect(parsed.query.redirect, 'redirect query')
1714+
.to.equal('#/some-path?a=1&b=2');
1715+
});
1716+
});
16931717
});
16941718

16951719
describe('User.confirm(options, fn)', function() {

0 commit comments

Comments
 (0)