Merge pull request #3334 from mozilla/train-150

Train 150 / 150.1 release
This commit is contained in:
Dave Justice 2019-11-13 08:43:29 -08:00 коммит произвёл GitHub
Родитель 4e4a465ef8 c2884bd884
Коммит f4e0bb52f9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
49 изменённых файлов: 368 добавлений и 214 удалений

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

@ -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';

2
packages/fxa-auth-db-mysql/package-lock.json сгенерированный
Просмотреть файл

@ -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 => {

2
packages/fxa-auth-server/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-content-server/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-customs-server/package-lock.json сгенерированный
Просмотреть файл

@ -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",

2
packages/fxa-email-event-proxy/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-email-service/Cargo.lock сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-event-broker/package-lock.json сгенерированный
Просмотреть файл

@ -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.

2
packages/fxa-geodb/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-payments-server/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-profile-server/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-shared/package-lock.json сгенерированный
Просмотреть файл

@ -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

2
packages/fxa-support-panel/package-lock.json сгенерированный
Просмотреть файл

@ -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"