mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
fix(core): Fix data decryption on credentials import (#7560)
Due to a change, during the credentials import command, the core's Credential object is being called through its prototype. This caused the Credential's cipher variable to not be set, thus no cipher service being available during import. This fix catches this edge case and provides a fix.
This commit is contained in:
parent
774d521dbd
commit
b350568505
|
@ -1,5 +1,5 @@
|
||||||
import { flags } from '@oclif/command';
|
import { flags } from '@oclif/command';
|
||||||
import { Credentials } from 'n8n-core';
|
import { Cipher } from 'n8n-core';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
@ -69,6 +69,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
|
|
||||||
let totalImported = 0;
|
let totalImported = 0;
|
||||||
|
|
||||||
|
const cipher = Container.get(Cipher);
|
||||||
await this.initOwnerCredentialRole();
|
await this.initOwnerCredentialRole();
|
||||||
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
|
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
|
||||||
|
|
||||||
|
@ -92,12 +93,10 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
const credential = jsonParse<ICredentialsEncrypted>(
|
const credential = jsonParse<ICredentialsEncrypted>(
|
||||||
fs.readFileSync(file, { encoding: 'utf8' }),
|
fs.readFileSync(file, { encoding: 'utf8' }),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof credential.data === 'object') {
|
if (typeof credential.data === 'object') {
|
||||||
// plain data / decrypted input. Should be encrypted first.
|
// plain data / decrypted input. Should be encrypted first.
|
||||||
Credentials.prototype.setData.call(credential, credential.data);
|
credential.data = cipher.encrypt(credential.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.storeCredential(credential, user);
|
await this.storeCredential(credential, user);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -123,7 +122,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
for (const credential of credentials) {
|
for (const credential of credentials) {
|
||||||
if (typeof credential.data === 'object') {
|
if (typeof credential.data === 'object') {
|
||||||
// plain data / decrypted input. Should be encrypted first.
|
// plain data / decrypted input. Should be encrypted first.
|
||||||
Credentials.prototype.setData.call(credential, credential.data);
|
credential.data = cipher.encrypt(credential.data);
|
||||||
}
|
}
|
||||||
await this.storeCredential(credential, user);
|
await this.storeCredential(credential, user);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +154,10 @@ export class ImportCredentialsCommand extends BaseCommand {
|
||||||
this.ownerCredentialRole = ownerCredentialRole;
|
this.ownerCredentialRole = ownerCredentialRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async storeCredential(credential: object, user: User) {
|
private async storeCredential(credential: Partial<CredentialsEntity>, user: User) {
|
||||||
|
if (!credential.nodesAccess) {
|
||||||
|
credential.nodesAccess = [];
|
||||||
|
}
|
||||||
const result = await this.transactionManager.upsert(CredentialsEntity, credential, ['id']);
|
const result = await this.transactionManager.upsert(CredentialsEntity, credential, ['id']);
|
||||||
await this.transactionManager.upsert(
|
await this.transactionManager.upsert(
|
||||||
SharedCredentials,
|
SharedCredentials,
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import * as Config from '@oclif/config';
|
||||||
|
|
||||||
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
|
import { ImportCredentialsCommand } from '@/commands/import/credentials';
|
||||||
|
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||||
|
import * as testDb from '../shared/testDb';
|
||||||
|
import { mockInstance } from '../shared/utils';
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
mockInstance(InternalHooks);
|
||||||
|
mockInstance(LoadNodesAndCredentials);
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await testDb.truncate(['Credentials']);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await testDb.terminate();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('import:credentials should import a credential', async () => {
|
||||||
|
const config: Config.IConfig = new Config.Config({ root: __dirname });
|
||||||
|
const before = await testDb.getAllCredentials();
|
||||||
|
expect(before.length).toBe(0);
|
||||||
|
const importer = new ImportCredentialsCommand(
|
||||||
|
['--input=./test/integration/commands/importCredentials/credentials.json'],
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
||||||
|
throw new Error('process.exit');
|
||||||
|
});
|
||||||
|
|
||||||
|
await importer.init();
|
||||||
|
try {
|
||||||
|
await importer.run();
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.message).toBe('process.exit');
|
||||||
|
}
|
||||||
|
const after = await testDb.getAllCredentials();
|
||||||
|
expect(after.length).toBe(1);
|
||||||
|
expect(after[0].name).toBe('cred-aws-test');
|
||||||
|
expect(after[0].id).toBe('123');
|
||||||
|
expect(after[0].nodesAccess).toStrictEqual([]);
|
||||||
|
mockExit.mockRestore();
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"createdAt": "2023-07-10T14:50:49.193Z",
|
||||||
|
"updatedAt": "2023-10-27T13:34:42.917Z",
|
||||||
|
"id": "123",
|
||||||
|
"name": "cred-aws-test",
|
||||||
|
"data": {
|
||||||
|
"region": "eu-west-1",
|
||||||
|
"accessKeyId": "999999999999",
|
||||||
|
"secretAccessKey": "aaaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
"type": "aws",
|
||||||
|
"nodesAccess": ""
|
||||||
|
}
|
||||||
|
]
|
|
@ -181,6 +181,10 @@ export function affixRoleToSaveCredential(role: Role) {
|
||||||
saveCredential(credentialPayload, { user, role });
|
saveCredential(credentialPayload, { user, role });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAllCredentials() {
|
||||||
|
return Db.collections.Credentials.find();
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// user creation
|
// user creation
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
Loading…
Reference in a new issue