зеркало из https://github.com/mozilla/fxa.git
Merge pull request #3334 from mozilla/train-150
Train 150 / 150.1 release
This commit is contained in:
Коммит
f4e0bb52f9
|
@ -1,3 +1,13 @@
|
|||
## 1.150.1
|
||||
|
||||
### New features
|
||||
|
||||
* keys: Explicitly track timestamp of last key rotation. (f8dbdfad9)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* tests: Fix secondary-emails test to account for nondeterministic result order. (59c9a8c1c)
|
||||
|
||||
## 1.150.0
|
||||
|
||||
No changes.
|
||||
|
|
|
@ -2410,6 +2410,29 @@ module.exports = function(config, DB) {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should track keysChangedAt independently of verifierSetAt', async () => {
|
||||
const account1 = await db.account(accountData.uid);
|
||||
assert.equal(account1.verifierSetAt, account1.keysChangedAt);
|
||||
|
||||
accountData.verifierSetAt = now + 1;
|
||||
accountData.keysHaveChanged = false;
|
||||
await db.resetAccount(accountData.uid, accountData);
|
||||
const account2 = await db.account(accountData.uid);
|
||||
assert.notEqual(account1.verifierSetAt, account2.verifierSetAt);
|
||||
assert.equal(account1.keysChangedAt, account2.keysChangedAt);
|
||||
|
||||
accountData.verifierSetAt = now + 2;
|
||||
accountData.keysHaveChanged = true;
|
||||
await db.resetAccount(accountData.uid, accountData);
|
||||
const account3 = await db.account(accountData.uid);
|
||||
assert.notEqual(account2.verifierSetAt, account3.verifierSetAt);
|
||||
assert.notEqual(account2.keysChangedAt, account3.keysChangedAt);
|
||||
assert.equal(account3.verifierSetAt, now + 2);
|
||||
assert.equal(account3.keysChangedAt, now + 2);
|
||||
|
||||
delete accountData.keysHaveChanged;
|
||||
});
|
||||
});
|
||||
|
||||
describe('db.securityEvents', () => {
|
||||
|
|
|
@ -141,176 +141,163 @@ module.exports = function(cfg, makeServer) {
|
|||
);
|
||||
});
|
||||
|
||||
it('add account, add email, get secondary email, get emails, delete email', () => {
|
||||
var user = fake.newUserDataHex();
|
||||
var secondEmailRecord = user.email;
|
||||
var thirdEmailRecord;
|
||||
it('add account, add email, get secondary email, get emails, delete email', async () => {
|
||||
const user = fake.newUserDataHex();
|
||||
const secondEmailRecord = user.email;
|
||||
|
||||
return client
|
||||
.putThen('/account/' + user.accountId, user.account)
|
||||
.then(function(r) {
|
||||
respOkEmpty(r);
|
||||
return client.postThen(
|
||||
'/account/' + user.accountId + '/emails',
|
||||
user.email
|
||||
);
|
||||
})
|
||||
.then(function(r) {
|
||||
respOkEmpty(r);
|
||||
return client.getThen('/account/' + user.accountId + '/emails');
|
||||
})
|
||||
.then(function(r) {
|
||||
respOk(r);
|
||||
let r = await client.putThen('/account/' + user.accountId, user.account);
|
||||
respOkEmpty(r);
|
||||
|
||||
var result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
r = await client.postThen(
|
||||
'/account/' + user.accountId + '/emails',
|
||||
user.email
|
||||
);
|
||||
respOkEmpty(r);
|
||||
|
||||
// Verify first email is email from accounts table
|
||||
assert.equal(
|
||||
result[0].email,
|
||||
user.account.email,
|
||||
'matches account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isPrimary,
|
||||
true,
|
||||
'isPrimary is true on account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isVerified,
|
||||
!!user.account.emailVerified,
|
||||
'matches account emailVerified'
|
||||
);
|
||||
r = await client.getThen('/account/' + user.accountId + '/emails');
|
||||
respOk(r);
|
||||
let result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
|
||||
// Verify second email is from emails table
|
||||
assert.equal(
|
||||
result[1].email,
|
||||
secondEmailRecord.email,
|
||||
'matches secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isVerified,
|
||||
false,
|
||||
'matches secondEmail isVerified'
|
||||
);
|
||||
// Verify first email is the primary email
|
||||
assert.equal(
|
||||
result[0].email,
|
||||
user.account.email,
|
||||
'matches account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isPrimary,
|
||||
true,
|
||||
'isPrimary is true on account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isVerified,
|
||||
!!user.account.emailVerified,
|
||||
'matches account emailVerified'
|
||||
);
|
||||
|
||||
var emailCodeHex = secondEmailRecord.emailCode.toString('hex');
|
||||
return client.postThen(
|
||||
'/account/' + user.accountId + '/verifyEmail/' + emailCodeHex
|
||||
);
|
||||
})
|
||||
.then(function(r) {
|
||||
respOkEmpty(r);
|
||||
return client.getThen('/account/' + user.accountId + '/emails');
|
||||
})
|
||||
.then(function(r) {
|
||||
respOk(r);
|
||||
// Verify second email is the secondary email
|
||||
assert.equal(
|
||||
result[1].email,
|
||||
secondEmailRecord.email,
|
||||
'matches secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isVerified,
|
||||
false,
|
||||
'matches secondEmail isVerified'
|
||||
);
|
||||
|
||||
var result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
assert.equal(
|
||||
result[1].email,
|
||||
secondEmailRecord.email,
|
||||
'matches secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isVerified,
|
||||
true,
|
||||
'matches secondEmail isVerified'
|
||||
);
|
||||
var emailCodeHex = secondEmailRecord.emailCode.toString('hex');
|
||||
r = await client.postThen(
|
||||
'/account/' + user.accountId + '/verifyEmail/' + emailCodeHex
|
||||
);
|
||||
respOkEmpty(r);
|
||||
|
||||
thirdEmailRecord = fake.newUserDataHex().email;
|
||||
return client.postThen(
|
||||
'/account/' + user.accountId + '/emails',
|
||||
thirdEmailRecord
|
||||
);
|
||||
})
|
||||
.then(function(r) {
|
||||
respOkEmpty(r);
|
||||
return client.getThen('/account/' + user.accountId + '/emails');
|
||||
})
|
||||
.then(function(r) {
|
||||
respOk(r);
|
||||
r = await client.getThen('/account/' + user.accountId + '/emails');
|
||||
respOk(r);
|
||||
|
||||
var result = r.obj;
|
||||
assert.lengthOf(result, 3);
|
||||
assert.equal(
|
||||
result[2].email,
|
||||
thirdEmailRecord.email,
|
||||
'matches thirdEmailRecord email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[2].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on thirdEmailRecord email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[2].isVerified,
|
||||
false,
|
||||
'matches secondEmail thirdEmailRecord'
|
||||
);
|
||||
result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
assert.equal(
|
||||
result[1].email,
|
||||
secondEmailRecord.email,
|
||||
'matches secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on secondEmail email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[1].isVerified,
|
||||
true,
|
||||
'matches secondEmail isVerified'
|
||||
);
|
||||
|
||||
return client.delThen(
|
||||
'/account/' +
|
||||
user.accountId +
|
||||
'/emails/' +
|
||||
emailToHex(secondEmailRecord.email)
|
||||
);
|
||||
})
|
||||
.then(function(r) {
|
||||
respOkEmpty(r);
|
||||
return client.getThen('/account/' + user.accountId + '/emails');
|
||||
})
|
||||
.then(function(r) {
|
||||
respOk(r);
|
||||
const thirdEmailRecord = fake.newUserDataHex().email;
|
||||
r = await client.postThen(
|
||||
'/account/' + user.accountId + '/emails',
|
||||
thirdEmailRecord
|
||||
);
|
||||
respOkEmpty(r);
|
||||
|
||||
var result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
assert.equal(
|
||||
result[0].email,
|
||||
user.account.email,
|
||||
'matches account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isPrimary,
|
||||
true,
|
||||
'isPrimary is true on account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isVerified,
|
||||
!!user.account.emailVerified,
|
||||
'matches account emailVerified'
|
||||
);
|
||||
r = await client.getThen('/account/' + user.accountId + '/emails');
|
||||
respOk(r);
|
||||
|
||||
// Attempt to get a specific secondary email
|
||||
return client.getThen('/email/' + emailToHex(thirdEmailRecord.email));
|
||||
})
|
||||
.then(function(r) {
|
||||
respOk(r);
|
||||
result = r.obj;
|
||||
assert.lengthOf(result, 3);
|
||||
// Secondary emails are not returned in a deterministic order; normalize.
|
||||
if (result[2].email !== thirdEmailRecord.email) {
|
||||
assert.equal(
|
||||
result[2].email,
|
||||
secondEmailRecord.email,
|
||||
'second email record was returned third'
|
||||
);
|
||||
[result[1], result[2]] = [result[2], result[1]];
|
||||
}
|
||||
|
||||
var result = r.obj;
|
||||
assert.equal(result.email, thirdEmailRecord.email, 'matches email');
|
||||
assert.equal(
|
||||
!!result.isPrimary,
|
||||
false,
|
||||
'isPrimary is false on email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result.isVerified,
|
||||
!!thirdEmailRecord.emailVerified,
|
||||
'matches emailVerified'
|
||||
);
|
||||
});
|
||||
assert.equal(
|
||||
result[2].email,
|
||||
thirdEmailRecord.email,
|
||||
'matches thirdEmailRecord email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[2].isPrimary,
|
||||
false,
|
||||
'isPrimary is false on thirdEmailRecord email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[2].isVerified,
|
||||
false,
|
||||
'matches secondEmail thirdEmailRecord'
|
||||
);
|
||||
|
||||
r = await client.delThen(
|
||||
'/account/' +
|
||||
user.accountId +
|
||||
'/emails/' +
|
||||
emailToHex(secondEmailRecord.email)
|
||||
);
|
||||
respOkEmpty(r);
|
||||
|
||||
r = await client.getThen('/account/' + user.accountId + '/emails');
|
||||
respOk(r);
|
||||
|
||||
result = r.obj;
|
||||
assert.lengthOf(result, 2);
|
||||
assert.equal(
|
||||
result[0].email,
|
||||
user.account.email,
|
||||
'matches account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isPrimary,
|
||||
true,
|
||||
'isPrimary is true on account email'
|
||||
);
|
||||
assert.equal(
|
||||
!!result[0].isVerified,
|
||||
!!user.account.emailVerified,
|
||||
'matches account emailVerified'
|
||||
);
|
||||
|
||||
r = await client.getThen('/email/' + emailToHex(thirdEmailRecord.email));
|
||||
respOk(r);
|
||||
|
||||
result = r.obj;
|
||||
assert.equal(result.email, thirdEmailRecord.email, 'matches email');
|
||||
assert.equal(!!result.isPrimary, false, 'isPrimary is false on email');
|
||||
assert.equal(
|
||||
!!result.isVerified,
|
||||
!!thirdEmailRecord.emailVerified,
|
||||
'matches emailVerified'
|
||||
);
|
||||
});
|
||||
|
||||
it('add account, check password, retrieve it, delete it', () => {
|
||||
|
|
|
@ -97,7 +97,7 @@ module.exports = function(log, error) {
|
|||
return P.reject(error.duplicate());
|
||||
}
|
||||
|
||||
accounts[uid.toString('hex')] = data;
|
||||
accounts[uid.toString('hex')] = extend({}, data);
|
||||
uidByNormalizedEmail[data.normalizedEmail] = uid;
|
||||
|
||||
emails[data.normalizedEmail] = {
|
||||
|
@ -964,9 +964,18 @@ module.exports = function(log, error) {
|
|||
account.verifyHash = data.verifyHash;
|
||||
account.authSalt = data.authSalt;
|
||||
account.wrapWrapKb = data.wrapWrapKb;
|
||||
account.verifierSetAt = data.verifierSetAt;
|
||||
account.verifierVersion = data.verifierVersion;
|
||||
account.profileChangedAt = data.verifierSetAt;
|
||||
// The `keysChangedAt` column was added in a migration, so its default value
|
||||
// is NULL meaning "we don't know". Now that we do know whether or not the keys
|
||||
// are being changed, ensure it gets set to some concrete non-NULL value.
|
||||
if (data.keysHaveChanged) {
|
||||
account.keysChangedAt = data.verifierSetAt;
|
||||
} else {
|
||||
account.keysChangedAt =
|
||||
account.keysChangedAt || account.verifierSetAt || account.createdAt;
|
||||
}
|
||||
account.verifierSetAt = data.verifierSetAt;
|
||||
account.devices = {};
|
||||
return [];
|
||||
});
|
||||
|
|
|
@ -841,9 +841,10 @@ module.exports = function(log, error) {
|
|||
//
|
||||
// Step : 2
|
||||
// Update : accounts
|
||||
// Set : verifyHash = $2, authSalt = $3, wrapWrapKb = $4, verifierSetAt = $5, verifierVersion = $6
|
||||
// Set : verifyHash = $2, authSalt = $3, wrapWrapKb = $4, verifierSetAt = $5, verifierVersion = $6,
|
||||
// keysHaveChanged = $7
|
||||
// Where : uid = $1
|
||||
var RESET_ACCOUNT = 'CALL resetAccount_14(?, ?, ?, ?, ?, ?)';
|
||||
var RESET_ACCOUNT = 'CALL resetAccount_15(?, ?, ?, ?, ?, ?, ?)';
|
||||
|
||||
MySql.prototype.resetAccount = function(uid, data) {
|
||||
return this.write(RESET_ACCOUNT, [
|
||||
|
@ -853,6 +854,7 @@ module.exports = function(log, error) {
|
|||
data.wrapWrapKb,
|
||||
data.verifierSetAt,
|
||||
data.verifierVersion,
|
||||
!!data.keysHaveChanged,
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
// The expected patch level of the database. Update if you add a new
|
||||
// patch in the ./schema/ directory.
|
||||
|
||||
module.exports.level = 105;
|
||||
module.exports.level = 106;
|
||||
|
|
|
@ -55,4 +55,5 @@ BEGIN
|
|||
|
||||
COMMIT;
|
||||
END;
|
||||
|
||||
UPDATE dbMetadata SET value = '105' WHERE name = 'schema-patch-level';
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
SET NAMES utf8mb4 COLLATE utf8mb4_bin;
|
||||
|
||||
CALL assertPatchLevel('105');
|
||||
|
||||
CREATE PROCEDURE `resetAccount_15` (
|
||||
IN `uidArg` BINARY(16),
|
||||
IN `verifyHashArg` BINARY(32),
|
||||
IN `authSaltArg` BINARY(32),
|
||||
IN `wrapWrapKbArg` BINARY(32),
|
||||
IN `verifierSetAtArg` BIGINT UNSIGNED,
|
||||
IN `verifierVersionArg` TINYINT UNSIGNED,
|
||||
IN `keysHaveChangedArg` BOOLEAN
|
||||
)
|
||||
BEGIN
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
DELETE FROM sessionTokens WHERE uid = uidArg;
|
||||
DELETE FROM keyFetchTokens WHERE uid = uidArg;
|
||||
DELETE FROM accountResetTokens WHERE uid = uidArg;
|
||||
DELETE FROM passwordChangeTokens WHERE uid = uidArg;
|
||||
DELETE FROM passwordForgotTokens WHERE uid = uidArg;
|
||||
DELETE FROM recoveryKeys WHERE uid = uidArg;
|
||||
DELETE devices, deviceCommands FROM devices LEFT JOIN deviceCommands
|
||||
ON (deviceCommands.uid = devices.uid AND deviceCommands.deviceId = devices.id)
|
||||
WHERE devices.uid = uidArg; DELETE FROM unverifiedTokens WHERE uid = uidArg;
|
||||
UPDATE accounts
|
||||
SET
|
||||
verifyHash = verifyHashArg,
|
||||
authSalt = authSaltArg,
|
||||
wrapWrapKb = wrapWrapKbArg,
|
||||
verifierVersion = verifierVersionArg,
|
||||
profileChangedAt = verifierSetAtArg,
|
||||
-- The `keysChangedAt` column was added in a migration, so its default value
|
||||
-- is NULL meaning "we don't know". Now that we do know whether or not the keys
|
||||
-- are being changed, ensure it gets set to some concrete non-NULL value.
|
||||
keysChangedAt = IF(keysHaveChangedArg, verifierSetAtArg, COALESCE(keysChangedAt, verifierSetAt, createdAt)),
|
||||
verifierSetAt = verifierSetAtArg
|
||||
WHERE uid = uidArg;
|
||||
|
||||
COMMIT;
|
||||
END;
|
||||
|
||||
UPDATE dbMetadata SET value = '106' WHERE name = 'schema-patch-level';
|
|
@ -0,0 +1,5 @@
|
|||
-- SET NAMES utf8mb4 COLLATE utf8mb4_bin;
|
||||
|
||||
-- DROP PROCEDURE `resetAccount_15`;
|
||||
|
||||
-- UPDATE dbMetadata SET value = '105' WHERE name = 'schema-patch-level';
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-auth-db-mysql",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-auth-db-mysql",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "MySQL backend for Firefox Accounts",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
## 1.150.1
|
||||
|
||||
### New features
|
||||
|
||||
* keys: Explicitly track timestamp of last key rotation. (f8dbdfad9)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* metrics: Restore high volume oauth events from amplitude logging (ea3f285e5)
|
||||
* metrics: restore high volume oauth events from amplitude logging. part 2 (0118e4db3)
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### New features
|
||||
|
|
|
@ -30,21 +30,6 @@ const EVENTS = {
|
|||
|
||||
const FUZZY_EVENTS = new Map([]);
|
||||
|
||||
function sane(event) {
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
const props = event.event_properties;
|
||||
const excluded =
|
||||
(props.service === 'fennec-stage' &&
|
||||
props.oauth_client_id === '3332a18d142636cb') ||
|
||||
(props.service === 'firefox-desktop' &&
|
||||
props.oauth_client_id === '5882386c6d801776') ||
|
||||
(props.service === 'firefox-ios' &&
|
||||
props.oauth_client_id === '1b1a3e44c54fbb58');
|
||||
return !excluded;
|
||||
}
|
||||
|
||||
module.exports = (log, config) => {
|
||||
if (!log || !config.oauthServer.clientIdToServiceNames) {
|
||||
throw new TypeError('Missing argument');
|
||||
|
@ -79,7 +64,7 @@ module.exports = (log, config) => {
|
|||
eventData
|
||||
);
|
||||
|
||||
if (sane(amplitudeEvent)) {
|
||||
if (amplitudeEvent) {
|
||||
log.info('amplitudeEvent', amplitudeEvent);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1176,15 +1176,18 @@ module.exports = (
|
|||
|
||||
async function resetAccountData() {
|
||||
const authSalt = await random.hex(32);
|
||||
let keysHaveChanged;
|
||||
password = new Password(authPW, authSalt, config.verifierVersion);
|
||||
verifyHash = await password.verifyHash();
|
||||
if (recoveryKeyId) {
|
||||
// We have the previous kB, just re-wrap it with the new password.
|
||||
wrapWrapKb = await password.wrap(wrapKb);
|
||||
keysHaveChanged = false;
|
||||
} else {
|
||||
// We need to regenerate kB and wrap it with the new password.
|
||||
wrapWrapKb = await random.hex(32);
|
||||
wrapKb = await password.unwrap(wrapWrapKb);
|
||||
keysHaveChanged = true;
|
||||
}
|
||||
// db.resetAccount() deletes all the devices saved in the account,
|
||||
// so grab the list to notify before we call it.
|
||||
|
@ -1195,6 +1198,7 @@ module.exports = (
|
|||
verifyHash,
|
||||
wrapWrapKb,
|
||||
verifierVersion: password.version,
|
||||
keysHaveChanged,
|
||||
});
|
||||
await db.resetAccountTokens(accountResetToken.uid);
|
||||
// Notify various interested parties about this password reset.
|
||||
|
|
|
@ -242,6 +242,7 @@ module.exports = function(
|
|||
authSalt: authSalt,
|
||||
wrapWrapKb: wrapWrapKb,
|
||||
verifierVersion: password.version,
|
||||
keysHaveChanged: false,
|
||||
});
|
||||
})
|
||||
.then(result => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-auth-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-auth-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Firefox Accounts, an identity provider for Mozilla cloud services",
|
||||
"bin": {
|
||||
"fxa-auth": "./bin/key_server.js"
|
||||
|
|
|
@ -412,11 +412,7 @@ describe('/oauth/ routes', function() {
|
|||
scope: OAUTH_SCOPE_OLD_SYNC,
|
||||
}))[OAUTH_SCOPE_OLD_SYNC];
|
||||
|
||||
// Since we're not actually tracking a separate key-rotation timestamp yet,
|
||||
// we report that the keys might have changed even on a password change.
|
||||
// In future this will be:
|
||||
// assert.equal(keyData1.keyRotationTimestamp, keyData2.keyRotationTimestamp);
|
||||
assert.ok(keyData1.keyRotationTimestamp < keyData2.keyRotationTimestamp);
|
||||
assert.equal(keyData1.keyRotationTimestamp, keyData2.keyRotationTimestamp);
|
||||
|
||||
await client.forgotPassword();
|
||||
const code = await server.mailbox.waitForCode(email);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
'use strict';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const jwtool = require('fxa-jwtool');
|
||||
const Client = require('../client')();
|
||||
const config = require('../../config').getProperties();
|
||||
const TestServer = require('../test_server');
|
||||
|
@ -339,6 +340,45 @@ describe('remote password change', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('password change does not update keysChangedAt', async () => {
|
||||
const email = server.uniqueEmail();
|
||||
const password = 'allyourbasearebelongtous';
|
||||
const newPassword = 'foobar';
|
||||
const duration = 1000 * 60 * 60 * 24; // 24 hours
|
||||
const publicKey = {
|
||||
algorithm: 'RS',
|
||||
n:
|
||||
'4759385967235610503571494339196749614544606692567785790953934768202714280652973091341316862993582789079872007974809511698859885077002492642203267408776123',
|
||||
e: '65537',
|
||||
};
|
||||
|
||||
let client = await Client.createAndVerify(
|
||||
config.publicUrl,
|
||||
email,
|
||||
password,
|
||||
server.mailbox
|
||||
);
|
||||
|
||||
const cert1 = jwtool.unverify(await client.sign(publicKey, duration))
|
||||
.payload;
|
||||
|
||||
await client.changePassword(newPassword);
|
||||
await server.mailbox.waitForEmail(email);
|
||||
|
||||
client = await Client.loginAndVerify(
|
||||
config.publicUrl,
|
||||
email,
|
||||
newPassword,
|
||||
server.mailbox
|
||||
);
|
||||
|
||||
const cert2 = jwtool.unverify(await client.sign(publicKey, duration))
|
||||
.payload;
|
||||
assert.equal(cert1['fxa-uid'], cert2['fxa-uid']);
|
||||
assert.ok(cert1['fxa-generation'] < cert2['fxa-generation']);
|
||||
assert.equal(cert1['fxa-keysChangedAt'], cert2['fxa-keysChangedAt']);
|
||||
});
|
||||
|
||||
it('wrong password on change start', () => {
|
||||
const email = server.uniqueEmail();
|
||||
const password = 'allyourbasearebelongtous';
|
||||
|
|
|
@ -185,12 +185,7 @@ describe('remote recovery keys', function() {
|
|||
|
||||
assert.equal(cert1['fxa-uid'], cert2['fxa-uid']);
|
||||
assert.ok(cert1['fxa-generation'] < cert2['fxa-generation']);
|
||||
|
||||
// Since we're not actually tracking a separate key-rotation timestamp yet,
|
||||
// we report that the keys might have changed even on a password change.
|
||||
// In future this will be:
|
||||
// assert.equal(cert1['fxa-keysChangedAt'], cert2['fxa-keysChangedAt']);
|
||||
assert.ok(cert1['fxa-keysChangedAt'] < cert2['fxa-keysChangedAt']);
|
||||
assert.equal(cert1['fxa-keysChangedAt'], cert2['fxa-keysChangedAt']);
|
||||
});
|
||||
|
||||
it('should delete recovery key', () => {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### New features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-content-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-content-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Firefox Accounts Content Server",
|
||||
"scripts": {
|
||||
"build-production": "NODE_ENV=production grunt build",
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### Refactorings
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-customs-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-customs-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Firefox Accounts Customs Server",
|
||||
"author": "Mozilla (https://mozilla.org/)",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-email-event-proxy",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-email-event-proxy",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Proxies events from Sendgrid to FxA SQS queues",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### Refactorings
|
||||
|
|
|
@ -689,7 +689,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fxa_email_service"
|
||||
version = "1.150.0"
|
||||
version = "1.150.1"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "fxa_email_service"
|
||||
version = "1.150.0"
|
||||
version = "1.150.1"
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change history
|
||||
|
||||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### New features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-event-broker",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-event-broker",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Firefox Accounts Event Broker",
|
||||
"scripts": {
|
||||
"build": "./node_modules/typescript/bin/tsc",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change history
|
||||
|
||||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
No changes.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-geodb",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-geodb",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"private": false,
|
||||
"description": "Firefox Accounts GeoDB Repo for Geolocation based services",
|
||||
"main": "lib/fxa-geodb.js",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change history
|
||||
|
||||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### New features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-payments-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-payments-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Firefox Accounts Payments Service",
|
||||
"scripts": {
|
||||
"lint": "npm-run-all --parallel lint:*",
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### Refactorings
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-profile-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-profile-server",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"private": true,
|
||||
"description": "Firefox Accounts Profile service.",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change history
|
||||
|
||||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### New features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-shared",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-shared",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Shared module for FxA repositories",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change history
|
||||
|
||||
## 1.150.1
|
||||
|
||||
No changes.
|
||||
|
||||
## 1.150.0
|
||||
|
||||
### Bug fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-support-panel",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-support-panel",
|
||||
"version": "1.150.0",
|
||||
"version": "1.150.1",
|
||||
"description": "Small app to help customer support access FxA details",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
|
|
Загрузка…
Ссылка в новой задаче