From b0628d8fc66ff86bc70d492b00d397c0beca340b Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 15 Oct 2024 16:46:31 +0530 Subject: [PATCH 1/5] feat: add fallback mechanism in upgrader to decrypt Signed-off-by: Pranav C --- .../upgraders/0225002_ncDatasourceDecrypt.ts | 91 ++++++++++++++----- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts index bd991b105d..bb53e2884d 100644 --- a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts +++ b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts @@ -11,20 +11,51 @@ const logger = { }, }; -const decryptConfig = async (encryptedConfig: string, secret: string) => { +const decryptConfigWithFallbackKey = async ({ + encryptedConfig, + secret, + fallbackSecret, + fallbackToNullIfFailed = false, +}: { + encryptedConfig: string; + secret: string; + fallbackSecret?: string; + fallbackToNullIfFailed?: boolean; +}) => { if (!encryptedConfig) return encryptedConfig; - const decryptedVal = CryptoJS.AES.decrypt(encryptedConfig, secret).toString( - CryptoJS.enc.Utf8, - ); - - // validate by parsing JSON try { - JSON.parse(decryptedVal); - } catch { - throw new Error('Config decryption failed'); + const decryptedVal = CryptoJS.AES.decrypt(encryptedConfig, secret).toString( + CryptoJS.enc.Utf8, + ); + + let parsedVal; + + // validate by parsing JSON + try { + parsedVal = JSON.parse(decryptedVal); + } catch { + throw new Error('JSON parse failed'); + } + // if parsed value is null, return null + return parsedVal === null ? null : decryptedVal; + } catch (e) { + if (fallbackSecret) { + logger.log( + 'Falling back to fallback secret since decryption failed with primary secret', + ); + return decryptConfigWithFallbackKey({ + encryptedConfig, + secret: fallbackSecret, + }); + } + + if (fallbackToNullIfFailed) { + return null; + } + + throw e; } - return decryptedVal; }; // decrypt datasource details in source table and integration table @@ -32,13 +63,18 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { logger.log('Starting decryption of sources and integrations'); let encryptionKey = process.env.NC_AUTH_JWT_SECRET; + let fallbackEncryptionKey: string = null; + + const encryptionKeyFromMeta = ( + await ncMeta.metaGet(RootScopes.ROOT, RootScopes.ROOT, MetaTable.STORE, { + key: 'nc_auth_jwt_secret', + }) + )?.value; if (!encryptionKey) { - encryptionKey = ( - await ncMeta.metaGet(RootScopes.ROOT, RootScopes.ROOT, MetaTable.STORE, { - key: 'nc_auth_jwt_secret', - }) - )?.value; + encryptionKey = encryptionKeyFromMeta; + } else { + fallbackEncryptionKey = encryptionKeyFromMeta; } // if encryption key is same as previous, just update is_encrypted flag and return @@ -61,7 +97,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { throw Error('Encryption key not found'); } - // get all external sources + // get all sources const sources = await ncMeta.knexConnection(MetaTable.SOURCES); const passed = []; @@ -70,7 +106,13 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { for (const source of sources) { if (source?.config) { try { - const decrypted = await decryptConfig(source.config, encryptionKey); + const decrypted = await decryptConfigWithFallbackKey({ + encryptedConfig: source.config, + secret: encryptionKey, + fallbackSecret: fallbackEncryptionKey, + // if source is meta, fallback to null if decryption failed as it is not required and the actual value is JSON `null` string + fallbackToNullIfFailed: source.is_meta, + }); await ncMeta .knexConnection(MetaTable.SOURCES) .update({ @@ -78,7 +120,11 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { }) .where('id', source.id); logger.log(`Decrypted source ${source.id}`); - passed.push(true); + + // skip pushing to passed if it is meta source + if (!source.is_meta) { + passed.push(true); + } } catch (e) { logger.error(`Failed to decrypt source ${source.id}`); passed.push(false); @@ -93,10 +139,11 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { for (const integration of integrations) { if (integration?.config) { try { - const decrypted = await decryptConfig( - integration.config, - encryptionKey, - ); + const decrypted = await decryptConfigWithFallbackKey({ + encryptedConfig: integration.config, + secret: encryptionKey, + fallbackSecret: fallbackEncryptionKey, + }); await ncMeta .knexConnection(MetaTable.INTEGRATIONS) .update({ From 2f3d542bb587ad409f46b4812e74e734492b97bb Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 15 Oct 2024 21:16:59 +0530 Subject: [PATCH 2/5] Update packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts index bb53e2884d..0d69bfcfe1 100644 --- a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts +++ b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts @@ -63,7 +63,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { logger.log('Starting decryption of sources and integrations'); let encryptionKey = process.env.NC_AUTH_JWT_SECRET; - let fallbackEncryptionKey: string = null; + let fallbackEncryptionKey: string | null = null; const encryptionKeyFromMeta = ( await ncMeta.metaGet(RootScopes.ROOT, RootScopes.ROOT, MetaTable.STORE, { From 01d6116968ad4059a48c27f1152657bebfae481d Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 15 Oct 2024 21:17:38 +0530 Subject: [PATCH 3/5] Update packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts index 0d69bfcfe1..71cd1ed228 100644 --- a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts +++ b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts @@ -34,8 +34,8 @@ const decryptConfigWithFallbackKey = async ({ // validate by parsing JSON try { parsedVal = JSON.parse(decryptedVal); - } catch { - throw new Error('JSON parse failed'); + } catch (parseError) { + throw new Error(`JSON parse failed: ${parseError.message}`); } // if parsed value is null, return null return parsedVal === null ? null : decryptedVal; From 4775cad80de149e97d4840fad9e88531d809e487 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 15 Oct 2024 21:20:12 +0530 Subject: [PATCH 4/5] refactor: improved error message Signed-off-by: Pranav C --- .../version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts index 71cd1ed228..fb879b5251 100644 --- a/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts +++ b/packages/nocodb/src/version-upgrader/upgraders/0225002_ncDatasourceDecrypt.ts @@ -41,9 +41,7 @@ const decryptConfigWithFallbackKey = async ({ return parsedVal === null ? null : decryptedVal; } catch (e) { if (fallbackSecret) { - logger.log( - 'Falling back to fallback secret since decryption failed with primary secret', - ); + logger.log('Retrying decryption with a fallback mechanism'); return decryptConfigWithFallbackKey({ encryptedConfig, secret: fallbackSecret, From 2356fed1bb0f83498d8281bfd03bed78e76e5761 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 15 Oct 2024 21:22:21 +0530 Subject: [PATCH 5/5] docs: link label correction Signed-off-by: Pranav C --- packages/noco-docs/docs/100.data-sources/050.updating-secret.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/noco-docs/docs/100.data-sources/050.updating-secret.md b/packages/noco-docs/docs/100.data-sources/050.updating-secret.md index 3f348c841b..739bc57abc 100644 --- a/packages/noco-docs/docs/100.data-sources/050.updating-secret.md +++ b/packages/noco-docs/docs/100.data-sources/050.updating-secret.md @@ -37,7 +37,7 @@ To update a secret in NocoDB, you can use the `nc-secret-mgr` package. Follow th Alternatively, you can use the `nc-secret-mgr` executable to update secrets. -1. Download the `nc-secret-mgr` executable from the [NocoDB website](https://github.com/nocodb/nc-secret-mgr/releases/latest). +1. Download the `nc-secret-mgr` executable from the [NocoDB Github](https://github.com/nocodb/nc-secret-mgr/releases/latest). 2. Run the executable using the following command: ```bash