Browse Source

feat: introduce new secret key env for credential encryption

pull/9499/head
Pranav C 2 months ago
parent
commit
a72ef36310
  1. 33
      packages/nocodb/src/models/Integration.ts
  2. 35
      packages/nocodb/src/models/Source.ts
  3. 51
      packages/nocodb/src/utils/encryptDecrypt.ts
  4. 1
      packages/nocodb/src/utils/index.ts
  5. 4
      packages/nocodb/src/utils/nc-config/NcConfig.ts

33
packages/nocodb/src/models/Integration.ts

@ -11,7 +11,11 @@ import {
prepareForDb,
stringifyMetaProp,
} from '~/utils/modelUtils';
import { partialExtract } from '~/utils';
import {
decryptPropIfRequired,
encryptPropIfRequired,
partialExtract,
} from '~/utils';
import { PagedResponseImpl } from '~/helpers/PagedResponse';
export default class Integration implements IntegrationType {
@ -56,10 +60,9 @@ export default class Integration implements IntegrationType {
'is_private',
]);
// insertObj.config = CryptoJS.AES.encrypt(
// JSON.stringify(insertObj.config),
// Noco.getConfig()?.auth?.jwt?.secret,
// ).toString();
insertObj.config = await encryptPropIfRequired({
data: insertObj,
});
if ('meta' in insertObj) {
insertObj.meta = stringifyMetaProp(insertObj);
@ -123,12 +126,11 @@ export default class Integration implements IntegrationType {
'is_private',
]);
// if (updateObj.config) {
// updateObj.config = CryptoJS.AES.encrypt(
// JSON.stringify(integration.config),
// Noco.getConfig()?.auth?.jwt?.secret,
// ).toString();
// }
if (updateObj.config) {
updateObj.config = await encryptPropIfRequired({
data: updateObj,
});
}
// type property is undefined even if not provided
if (!updateObj.type) {
@ -335,12 +337,9 @@ export default class Integration implements IntegrationType {
}
public getConfig(): any {
const config = JSON.parse(
CryptoJS.AES.decrypt(
this.config,
Noco.getConfig()?.auth?.jwt?.secret,
).toString(CryptoJS.enc.Utf8),
);
const config = decryptPropIfRequired({
data: this,
});
return config;
}

35
packages/nocodb/src/models/Source.ts

@ -26,6 +26,12 @@ import { JobsRedis } from '~/modules/jobs/redis/jobs-redis';
import { InstanceCommands } from '~/interface/Jobs';
import { deepMerge, partialExtract } from '~/utils';
import View from '~/models/View';
import {
decryptPropIfRequired,
deepMerge,
encryptPropIfRequired,
partialExtract,
} from '~/utils';
export default class Source implements SourceType {
id?: string;
@ -83,10 +89,9 @@ export default class Source implements SourceType {
'fk_integration_id',
]);
insertObj.config = CryptoJS.AES.encrypt(
JSON.stringify(source.config),
Noco.getConfig()?.auth?.jwt?.secret,
).toString();
insertObj.config = await encryptPropIfRequired({
data: insertObj,
});
if ('meta' in insertObj) {
insertObj.meta = stringifyMetaProp(insertObj);
@ -147,10 +152,9 @@ export default class Source implements SourceType {
]);
if (updateObj.config) {
updateObj.config = CryptoJS.AES.encrypt(
JSON.stringify(source.config),
Noco.getConfig()?.auth?.jwt?.secret,
).toString();
updateObj.config = await encryptPropIfRequired({
data: updateObj,
});
}
// type property is undefined even if not provided
@ -330,10 +334,9 @@ export default class Source implements SourceType {
}
const config = JSON.parse(
CryptoJS.AES.decrypt(
this.config,
Noco.getConfig()?.auth?.jwt?.secret,
).toString(CryptoJS.enc.Utf8),
decryptPropIfRequired({
data: this,
}),
);
if (skipIntegrationConfig) {
@ -345,10 +348,10 @@ export default class Source implements SourceType {
}
const integrationConfig = JSON.parse(
CryptoJS.AES.decrypt(
this.integration_config,
Noco.getConfig()?.auth?.jwt?.secret,
).toString(CryptoJS.enc.Utf8),
decryptPropIfRequired({
data: this,
prop: 'integration_config',
}),
);
// merge integration config with source config
// override integration config with source config if exists

51
packages/nocodb/src/utils/encryptDecrypt.ts

@ -0,0 +1,51 @@
import CryptoJS from 'crypto-js';
import Noco from '~/Noco';
export const encryptPropIfRequired = ({
data,
prop = 'config',
key = Noco.getConfig()?.credentialSecret,
}: {
data: Record<string, any>;
prop?: string;
key?: string;
}) => {
if (!data || data[prop] === null || data[prop] === undefined) {
return;
}
if (!key) {
return data[prop];
}
return CryptoJS.AES.encrypt(
JSON.stringify(data[prop]),
Noco.getConfig()?.credentialSecret,
).toString();
};
export const decryptPropIfRequired = ({
data,
prop = 'config',
key = Noco.getConfig()?.credentialSecret,
}: {
data: Record<string, any>;
prop?: string;
key?: string;
}) => {
if (!data || data[prop] === null || data[prop] === undefined) {
return;
}
if (!key) {
return data[prop];
}
try {
return JSON.parse(
CryptoJS.AES.decrypt(data[prop], key).toString(CryptoJS.enc.Utf8),
);
} catch (e) {
return data[prop];
}
};

1
packages/nocodb/src/utils/index.ts

@ -5,5 +5,6 @@ export * from './circularReplacer';
export * from './nocoExecute';
export { Tele as T } from './tele';
export * from './packageVersion';
export * from './encryptDecrypt';
export const isEE = false;

4
packages/nocodb/src/utils/nc-config/NcConfig.ts

@ -44,6 +44,7 @@ export class NcConfig {
env: string;
workingEnv: string;
baseType: string;
credentialSecret?: string;
private constructor() {}
@ -59,6 +60,7 @@ export class NcConfig {
worker?: boolean;
dashboardPath?: string;
publicUrl?: string;
credentialSecret?: string;
}): Promise<NcConfig> {
const { meta, secret, port, worker, tryMode, publicUrl, dashboardPath } =
param;
@ -69,6 +71,7 @@ export class NcConfig {
jwt: {
secret: secret,
},
credentialSecret: param.credentialSecret
};
ncConfig.port = +(port ?? 8080);
@ -148,6 +151,7 @@ export class NcConfig {
worker: !!process.env.NC_WORKER,
dashboardPath: process.env.NC_DASHBOARD_URL ?? '/dashboard',
publicUrl: process.env.NC_PUBLIC_URL,
credentialSecret: process.env.NC_KEY_CREDENTIAL_ENCRYPT,
});
}

Loading…
Cancel
Save