📄 Upgrade knex to avoid CVE-2019-10757

Change-type: patch
Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
Cameron Diver 2020-04-14 10:56:49 +01:00
parent 5f0d69d275
commit a43d71d1ac
7 changed files with 179 additions and 217 deletions

196
package-lock.json generated
View File

@ -361,16 +361,6 @@
"integrity": "sha512-KZfv4ea6bEbdQhfwpxtDuTPO2mHAAXMQqPOZyS4MgNyCymKoLHp0FVzzYq3H2zCeIotN4h1453TahLCCm8rf2w==",
"dev": true
},
"@types/knex": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/@types/knex/-/knex-0.15.2.tgz",
"integrity": "sha512-mw8OT8v+FK0SsgDdmio2XSkEM/yLD7ybFtiqW7I65EDTlr2aZtG+p9FhryErpNJDJ2FEXgQhe3JVBG0Gh7YbvQ==",
"dev": true,
"requires": {
"@types/bluebird": "*",
"@types/node": "*"
}
},
"@types/lockfile": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/lockfile/-/lockfile-1.0.1.tgz",
@ -2441,6 +2431,12 @@
"simple-swizzle": "^0.2.2"
}
},
"colorette": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz",
"integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==",
"dev": true
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
@ -4023,6 +4019,12 @@
}
}
},
"esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"dev": true
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@ -5134,32 +5136,21 @@
}
},
"findup-sync": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
"integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
"integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
"dev": true,
"requires": {
"detect-file": "^1.0.0",
"is-glob": "^3.1.0",
"is-glob": "^4.0.0",
"micromatch": "^3.0.4",
"resolve-dir": "^1.0.1"
},
"dependencies": {
"is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
"dev": true,
"requires": {
"is-extglob": "^2.1.0"
}
}
}
},
"fined": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz",
"integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
"integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
"dev": true,
"requires": {
"expand-tilde": "^2.0.2",
@ -5406,6 +5397,12 @@
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
},
"getopts": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz",
"integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==",
"dev": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@ -6374,9 +6371,9 @@
}
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.0.0.tgz",
"integrity": "sha512-e0/LknJ8wpMMhTiWcjivB+ESwIuvHnBSlBbmP/pSb8CQJldoj1p2qv7xGZ/+BtbTziYRFSz8OsvdbiX45LtYQA==",
"dev": true
},
"invariant": {
@ -6958,72 +6955,60 @@
}
},
"knex": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/knex/-/knex-0.15.2.tgz",
"integrity": "sha1-YFm4dIlgX0zIdZmm0qnSZXCek0A=",
"version": "0.20.13",
"resolved": "https://registry.npmjs.org/knex/-/knex-0.20.13.tgz",
"integrity": "sha512-YVl//Te0G5suc+d9KyeI6WuhtgVlxu6HXYQB+WqrccFkSZAbHqlqZlUMogYG3UoVq69c3kiFbbxgUNkrO0PVfg==",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"bluebird": "^3.5.1",
"chalk": "2.3.2",
"commander": "^2.16.0",
"debug": "3.1.0",
"inherits": "~2.0.3",
"interpret": "^1.1.0",
"liftoff": "2.5.0",
"lodash": "^4.17.10",
"minimist": "1.2.0",
"colorette": "1.1.0",
"commander": "^4.1.1",
"debug": "4.1.1",
"esm": "^3.2.25",
"getopts": "2.2.5",
"inherits": "~2.0.4",
"interpret": "^2.0.0",
"liftoff": "3.1.0",
"lodash": "^4.17.15",
"mkdirp": "^0.5.1",
"pg-connection-string": "2.0.0",
"tarn": "^1.1.4",
"tildify": "1.2.0",
"uuid": "^3.3.2",
"v8flags": "^3.1.1"
"pg-connection-string": "2.1.0",
"tarn": "^2.0.0",
"tildify": "2.0.0",
"uuid": "^7.0.1",
"v8flags": "^3.1.3"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.3.2",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
"ms": "^2.1.1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
"dev": true
}
}
},
@ -7074,13 +7059,13 @@
}
},
"liftoff": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
"integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
"integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
"dev": true,
"requires": {
"extend": "^3.0.0",
"findup-sync": "^2.0.0",
"findup-sync": "^3.0.0",
"fined": "^1.0.1",
"flagged-respawn": "^1.0.0",
"is-plain-object": "^2.0.4",
@ -8944,9 +8929,9 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pg-connection-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.0.0.tgz",
"integrity": "sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.1.0.tgz",
"integrity": "sha512-bhlV7Eq09JrRIvo1eKngpwuqKtJnNhZdpdOlvrPrA4dxqXPjxSrbNrfnIDmTpwMyRszrcV4kU5ZA4mMsQUrjdg==",
"dev": true
},
"picomatch": {
@ -10676,9 +10661,9 @@
}
},
"tarn": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.4.tgz",
"integrity": "sha512-j4samMCQCP5+6Il9/cxCqBd3x4vvlLeVdoyGex0KixPKl4F8LpNbDSC6NDhjianZgUngElRr9UI1ryZqJDhwGg==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-2.0.0.tgz",
"integrity": "sha512-7rNMCZd3s9bhQh47ksAQd92ADFcJUjjbyOvyFjNLwTPpGieFHMC84S+LOzw0fx1uh6hnDz/19r8CPMnIjJlMMA==",
"dev": true
},
"term-size": {
@ -11025,13 +11010,10 @@
}
},
"tildify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz",
"integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=",
"dev": true,
"requires": {
"os-homedir": "^1.0.0"
}
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
"dev": true
},
"time-stamp": {
"version": "1.1.0",
@ -11699,9 +11681,9 @@
"dev": true
},
"v8flags": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz",
"integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
"integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==",
"dev": true,
"requires": {
"homedir-polyfill": "^1.0.1"

View File

@ -47,7 +47,6 @@
"@types/dockerode": "^2.5.25",
"@types/event-stream": "^3.3.34",
"@types/express": "^4.17.3",
"@types/knex": "^0.15.2",
"@types/lockfile": "^1.0.1",
"@types/lodash": "^4.14.149",
"@types/memoizee": "^0.4.3",
@ -92,7 +91,7 @@
"io-ts-reporters": "^1.0.0",
"istanbul": "^0.4.5",
"json-mask": "^0.3.9",
"knex": "^0.15.2",
"knex": "^0.20.13",
"lint-staged": "^10.0.8",
"livepush": "^3.3.0",
"lockfile": "^1.0.4",

View File

@ -362,7 +362,7 @@ export class Images extends (EventEmitter as new () => ImageEventEmitter) {
this.db
.models('image')
.select('dockerImageId')
.map((img: Image) => img.dockerImageId),
.then(vals => vals.map((img: Image) => img.dockerImageId)),
]);
const supervisorRepos = [supervisorImageInfo.imageName];

View File

@ -123,11 +123,11 @@ export class Config extends (EventEmitter as new () => ConfigEventEmitter) {
}) as Bluebird<{ [key in T]: SchemaReturn<key> }>;
}
public set<T extends SchemaTypeKey>(
public async set<T extends SchemaTypeKey>(
keyValues: ConfigMap<T>,
trx?: Transaction,
): Bluebird<void> {
const setValuesInTransaction = (tx: Transaction) => {
): Promise<void> {
const setValuesInTransaction = async (tx: Transaction) => {
const configJsonVals: Dictionary<unknown> = {};
const dbVals: Dictionary<unknown> = {};
@ -150,77 +150,67 @@ export class Config extends (EventEmitter as new () => ConfigEventEmitter) {
});
const dbKeys = _.keys(dbVals) as T[];
return this.getMany(dbKeys, tx)
.then(oldValues => {
return Bluebird.map(dbKeys, (key: T) => {
const value = dbVals[key];
const oldValues = await this.getMany(dbKeys, tx);
await Bluebird.map(dbKeys, async (key: T) => {
const value = dbVals[key];
// if we have anything other than a string, it must be converted to
// a string before being stored in the db
const strValue = Config.valueToString(value, key);
// if we have anything other than a string, it must be converted to
// a string before being stored in the db
const strValue = Config.valueToString(value, key);
if (oldValues[key] !== value) {
return this.db.upsertModel(
'config',
{ key, value: strValue },
{ key },
tx,
);
}
});
})
.then(() => {
if (!_.isEmpty(configJsonVals)) {
return this.configJsonBackend.set(
configJsonVals as {
[key in Schema.SchemaKey]: unknown;
},
);
}
});
if (oldValues[key] !== value) {
await this.db.upsertModel(
'config',
{ key, value: strValue },
{ key },
tx,
);
}
});
if (!_.isEmpty(configJsonVals)) {
await this.configJsonBackend.set(
configJsonVals as {
[name in Schema.SchemaKey]: unknown;
},
);
}
};
return Bluebird.try(() => {
// Firstly validate and coerce all of the types as
// they are being set
keyValues = this.validateConfigMap(keyValues);
// Firstly validate and coerce all of the types as
// they are being set
keyValues = this.validateConfigMap(keyValues);
if (trx != null) {
return setValuesInTransaction(trx).return();
} else {
return this.db
.transaction((tx: Transaction) => setValuesInTransaction(tx))
.return();
}
}).then(() => {
this.emit('change', keyValues as ConfigMap<SchemaTypeKey>);
});
if (trx != null) {
await setValuesInTransaction(trx);
} else {
await this.db.transaction((tx: Transaction) =>
setValuesInTransaction(tx),
);
}
this.emit('change', keyValues as ConfigMap<SchemaTypeKey>);
}
public remove<T extends Schema.SchemaKey>(key: T): Bluebird<void> {
return Bluebird.try(() => {
if (Schema.schema[key] == null || !Schema.schema[key].mutable) {
throw new Error(
`Attempt to delete non-existent or immutable key ${key}`,
);
}
if (Schema.schema[key].source === 'config.json') {
return this.configJsonBackend.remove(key);
} else if (Schema.schema[key].source === 'db') {
return this.db
.models('config')
.del()
.where({ key });
} else {
throw new Error(
`Unknown or unsupported config backend: ${Schema.schema[key].source}`,
);
}
});
public async remove<T extends Schema.SchemaKey>(key: T): Promise<void> {
if (Schema.schema[key] == null || !Schema.schema[key].mutable) {
throw new Error(`Attempt to delete non-existent or immutable key ${key}`);
}
if (Schema.schema[key].source === 'config.json') {
return this.configJsonBackend.remove(key);
} else if (Schema.schema[key].source === 'db') {
await this.db
.models('config')
.del()
.where({ key });
} else {
throw new Error(
`Unknown or unsupported config backend: ${Schema.schema[key].source}`,
);
}
}
public regenerateRegistrationFields(): Bluebird<void> {
return this.set({
public async regenerateRegistrationFields(): Promise<void> {
await this.set({
uuid: this.newUniqueKey(),
deviceApiKey: this.newUniqueKey(),
});

View File

@ -1,4 +1,3 @@
import * as Bluebird from 'bluebird';
import * as Knex from 'knex';
import * as path from 'path';
@ -27,42 +26,38 @@ export class DB {
});
}
public init(): Bluebird<void> {
return this.knex('knex_migrations_lock')
.update({ is_locked: 0 })
.catch(() => {
return;
})
.then(() => {
return this.knex.migrate.latest({
directory: path.join(__dirname, 'migrations'),
});
});
public async init(): Promise<void> {
try {
await this.knex('knex_migrations_lock').update({ is_locked: 0 });
} catch {
/* ignore */
}
return this.knex.migrate.latest({
directory: path.join(__dirname, 'migrations'),
});
}
public models(modelName: string): Knex.QueryBuilder {
return this.knex(modelName);
}
public upsertModel(
public async upsertModel(
modelName: string,
obj: any,
id: Dictionary<unknown>,
trx?: Knex.Transaction,
): Bluebird<any> {
): Promise<any> {
const knex = trx || this.knex;
return knex(modelName)
const n = await knex(modelName)
.update(obj)
.where(id)
.then((n: number) => {
if (n === 0) {
return knex(modelName).insert(obj);
}
});
.where(id);
if (n === 0) {
return knex(modelName).insert(obj);
}
}
public transaction(cb: DBTransactionCallback): Bluebird<Knex.Transaction> {
public transaction(cb: DBTransactionCallback): Promise<Knex.Transaction> {
return this.knex.transaction(cb);
}
}

View File

@ -510,16 +510,17 @@ export class Proxyvisor {
if (this.actionExecutors[step.action] == null) {
throw new Error(`Invalid proxyvisor action ${step.action}`);
}
return this.actionExecutors[step.action](step);
});
}
getCurrentStates() {
return Promise.join(
this.db
.models('dependentApp')
.select()
.map(this.normaliseDependentAppFromDB),
Promise.map(
this.db.models('dependentApp').select(),
this.normaliseDependentAppFromDB,
),
this.db.models('dependentDevice').select(),
function(apps, devicesFromDB) {
const devices = _.map(devicesFromDB, function(device) {
@ -693,14 +694,14 @@ export class Proxyvisor {
getTarget() {
return Promise.props({
apps: this.db
.models('dependentAppTarget')
.select()
.map(this.normaliseDependentAppFromDB),
devices: this.db
.models('dependentDeviceTarget')
.select()
.map(this.normaliseDependentDeviceTargetFromDB),
apps: Promise.map(
this.db.models('dependentAppTarget').select(),
this.normaliseDependentAppFromDB,
),
devices: Promise.map(
this.db.models('dependentDeviceTarget').select(),
this.normaliseDependentDeviceTargetFromDB,
),
});
}

View File

@ -1,4 +1,3 @@
import * as Bluebird from 'bluebird';
import * as _ from 'lodash';
import { fs } from 'mz';
@ -16,14 +15,14 @@ import constants = require('../src/lib/constants');
describe('Config', () => {
let db: DB;
let conf: Config;
let initialization: Bluebird<unknown>;
before(() => {
before(async () => {
prepare();
db = new DB();
conf = new Config({ db });
initialization = db.init().then(() => conf.init());
await db.init();
await conf.init();
});
it('uses the correct config.json path', async () => {
@ -39,10 +38,6 @@ describe('Config', () => {
);
});
it('initializes correctly', () => {
return expect(initialization).to.be.fulfilled;
});
it('reads and exposes values from the config.json', async () => {
const id = await conf.get('applicationId');
return expect(id).to.equal(78373);