Merge pull request #238 from zaach/real-password-reset

Password reset with fxa-client #235

Travis is finally green. r+. Thanks for the explanations @zaach!
This commit is contained in:
Shane Tomlinson 2014-01-17 04:54:20 -08:00
Родитель 1a3ce8c4ad 38b122f3d8
Коммит 504400ecff
7 изменённых файлов: 162 добавлений и 31 удалений

Просмотреть файл

@ -13,25 +13,6 @@ define([
'processed/constants'
],
function (FxaClient, Constants) {
// placeholder promise to stand in for FxaClient functionality that is
// not yet ready.
function PromiseMock() {
}
PromiseMock.prototype = {
then: function (callback) {
var promise = new PromiseMock();
if (callback) {
callback();
}
return promise;
},
done: function (callback) {
if (callback) {
callback();
}
}
};
function FxaClientWrapper() {
this.client = new FxaClient(Constants.FXA_ACCOUNT_SERVER);
}
@ -54,12 +35,17 @@ function (FxaClient, Constants) {
return this.client.verifyCode(uid, code);
},
requestPasswordReset: function () {
return new PromiseMock();
requestPasswordReset: function (email) {
return this.client.passwordForgotSendCode(email);
},
completePasswordReset: function () {
return new PromiseMock();
completePasswordReset: function (email, newPassword, token, code) {
return this.client.passwordForgotVerifyCode(code, token)
.then(function (result) {
return this.client.accountReset(email,
newPassword,
result.accountResetToken);
}.bind(this));
}
};

Просмотреть файл

@ -22,22 +22,28 @@ function (_, BaseView, Template, FxaClient, Session, Url) {
},
afterRender: function () {
this.uid = Url.searchParam('uid');
if (! this.uid) {
return this.displayError('no uid specified');
this.token = Url.searchParam('token');
if (! this.token) {
return this.displayError('no token specified');
}
this.code = Url.searchParam('code');
if (! this.code) {
return this.displayError('no code specified');
}
this.email = Url.searchParam('email');
if (! this.email) {
return this.displayError('no email specified');
}
},
submit: function (event) {
event.preventDefault();
if (! (this.uid &&
if (! (this.token &&
this.code &&
this.email &&
this._validatePasswords())) {
return;
}
@ -45,7 +51,7 @@ function (_, BaseView, Template, FxaClient, Session, Url) {
var password = this._getPassword();
var client = new FxaClient();
client.completePasswordReset(password, this.uid, this.code)
client.completePasswordReset(this.email, password, this.token, this.code)
.done(_.bind(this._onResetCompleteSuccess, this),
_.bind(this._onResetCompleteFailure, this));
},

Просмотреть файл

@ -6,6 +6,11 @@ const config = require('./configuration');
const path = require('path');
module.exports = function(app) {
// handle password reset links
app.get('/v1/complete_reset_password', function(req, res) {
res.redirect(req.originalUrl.slice(3));
});
// handle email verification links
app.get('/v1/verify_email', function(req, res) {
res.redirect(req.originalUrl.slice(3));

Просмотреть файл

@ -5,24 +5,76 @@
define([
'intern!object',
'intern/chai!assert',
'require'
], function (registerSuite, assert, require) {
'require',
'intern/node_modules/dojo/node!xmlhttprequest',
'app/bower_components/fxa-js-client/fxa-client',
'intern/node_modules/dojo/Deferred',
'tests/lib/restmail'
], function (registerSuite, assert, require, nodeXMLHttpRequest, FxaClient, Deferred, restmail) {
'use strict';
var url = 'http://localhost:3030/complete_reset_password';
var AUTH_SERVER_ROOT = 'http://127.0.0.1:9000/v1';
var EMAIL_SERVER_ROOT = 'http://127.0.0.1:9001';
var PAGE_URL_ROOT = 'http://localhost:3030/complete_reset_password';
var PASSWORD = 'password';
var email;
var code;
var token;
registerSuite({
name: 'complete_reset_password',
setup: function () {
var dfd = new Deferred();
var user = 'signin' + Math.random();
email = user + '@restmail.net';
var client = new FxaClient(AUTH_SERVER_ROOT, {
xhr: nodeXMLHttpRequest.XMLHttpRequest
});
client.signUp(email, PASSWORD)
.then(function () {
return client.passwordForgotSendCode(email);
})
.then(function (result) {
token = result.passwordForgotToken;
restmail(EMAIL_SERVER_ROOT + '/mail/' + user, 2,
function (err, emails) {
code = emails[1].html.match(/code=([A-Za-z0-9]+)/)[1];
dfd.resolve(code);
}
);
}, dfd.reject.bind(dfd));
return dfd.promise;
},
'open page': function () {
var url = PAGE_URL_ROOT + '?token=' + token + '&code=' + code + '&email=' + encodeURIComponent(email);
return this.get('remote')
.get(require.toUrl(url))
.waitForElementById('fxa-complete-reset-password-header')
.elementByCssSelector('form input#password')
.click()
.type(PASSWORD)
.end()
.elementByCssSelector('form input#vpassword')
.click()
.type(PASSWORD)
.end()
.elementByCssSelector('button[type="submit"]')
.click()
.end()
.waitForElementById('fxa-reset-password-complete-header')
.end();
}
});

Просмотреть файл

@ -33,6 +33,16 @@ define([
.get(require.toUrl(PAGE_URL))
.waitForElementById('fxa-reset-password-header')
.elementByCssSelector('form input.email')
.click()
.type(email)
.end()
.elementByCssSelector('button[type="submit"]')
.click()
.end()
.waitForElementById('fxa-confirm-reset-password-header')
.end();
}
});

40
tests/lib/request.js Normal file
Просмотреть файл

@ -0,0 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define([
'intern/node_modules/dojo/node!xmlhttprequest',
], function (nodeXMLHttpRequest) {
'use strict';
function request(uri, method, jsonPayload, cb) {
var xhr = new nodeXMLHttpRequest.XMLHttpRequest();
var payload;
xhr.open(method, uri);
xhr.onerror = function onerror() {
cb(xhr.responseText);
};
xhr.onload = function onload() {
var result;
try {
result = JSON.parse(xhr.responseText);
} catch (e) {
return cb(e);
}
if (result.error) {
return cb(result.error);
}
cb(null, result);
};
if (jsonPayload) {
payload = JSON.stringify(jsonPayload);
xhr.setRequestHeader('Content-Type', 'application/json');
}
xhr.send(payload);
}
return request;
});

32
tests/lib/restmail.js Normal file
Просмотреть файл

@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define([
'tests/lib/request',
], function (request) {
'use strict';
function waitForEmail(uri, number, cb) {
if (!number) {
number = 1;
}
console.log('Waiting for email...');
request(uri, 'GET', null, function (err, result) {
if (err) {
return cb(err);
}
if (result.length >= number) {
return cb(null, result);
} else {
setTimeout(function() {
waitForEmail(uri, number, cb);
}, 1000);
}
});
}
return waitForEmail;
});