From 11a0f01e25459a86fac0a8a68b9beae6a12eb21d Mon Sep 17 00:00:00 2001 From: Hugo Jobling Date: Thu, 20 Nov 2014 11:24:31 +0000 Subject: [PATCH] Make tokens URL safe Base64 encoding causes some issues when the token is URL encoded as the = symbol is not a valid URL character. We replace any = symbols with a - as this is valid in a URL, but is guaranteed not to appear in a base64 string. This fix ensures that Ghost password resets work with mail providers such as Mailgun that add their own tracking redirects closes #3872 (for real this time) --- core/server/models/user.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/server/models/user.js b/core/server/models/user.js index 944a65fa68..203184d45e 100644 --- a/core/server/models/user.js +++ b/core/server/models/user.js @@ -706,7 +706,7 @@ User = ghostBookshelf.Model.extend({ text = ''; // Token: - // BASE64(TIMESTAMP + email + HASH(TIMESTAMP + email + oldPasswordHash + dbHash )) + // BASE64(TIMESTAMP + email + HASH(TIMESTAMP + email + oldPasswordHash + dbHash )).replace('=', '-') hash.update(String(expires)); hash.update(email.toLocaleLowerCase()); @@ -715,13 +715,19 @@ User = ghostBookshelf.Model.extend({ text += [expires, email, hash.digest('base64')].join('|'); - return new Buffer(text).toString('base64'); + // it's possible that the token might get URI encoded, which breaks it + // we replace any `=`s with `-`s as they aren't valid base64 characters + // but are valid in a URL, so won't suffer encoding issues + return new Buffer(text).toString('base64').replace('=', '-'); }); }, validateToken: function (token, dbHash) { /*jslint bitwise:true*/ // TODO: Is there a chance the use of ascii here will cause problems if oldPassword has weird characters? + // We replaced `=`s with `-`s when we sent the token via email, so + // now we reverse that change to get a valid base64 string to decode + token = token.replace('-', '='); var tokenText = new Buffer(token, 'base64').toString('ascii'), parts, expires,