diff --git a/packages/nodes-base/credentials/Snowflake.credentials.ts b/packages/nodes-base/credentials/Snowflake.credentials.ts index 0ba9afb1ec..c4b0168e2f 100644 --- a/packages/nodes-base/credentials/Snowflake.credentials.ts +++ b/packages/nodes-base/credentials/Snowflake.credentials.ts @@ -52,11 +52,6 @@ export class Snowflake implements ICredentialType { name: 'username', type: 'string', default: '', - displayOptions: { - show: { - authentication: ['password'], - }, - }, }, { displayName: 'Password', @@ -87,7 +82,19 @@ export class Snowflake implements ICredentialType { authentication: ['keyPair'], }, }, - description: 'Private PEM key for Key-pair authentication with Snowflake', + description: + 'Private PEM key for Key-pair authentication with Snowflake, follow guide here', + }, + { + displayName: 'Passphrase', + name: 'passphrase', + type: 'string', + default: '', + description: + 'If the private key is encrypted, you must provide the passphrase used to encrypt it', + typeOptions: { + password: true, + }, }, { displayName: 'Schema', diff --git a/packages/nodes-base/nodes/Snowflake/GenericFunctions.ts b/packages/nodes-base/nodes/Snowflake/GenericFunctions.ts index 58c2828e31..6d5d9b2b4f 100644 --- a/packages/nodes-base/nodes/Snowflake/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Snowflake/GenericFunctions.ts @@ -1,6 +1,9 @@ +import { createPrivateKey } from 'crypto'; import pick from 'lodash/pick'; import type snowflake from 'snowflake-sdk'; +import { formatPrivateKey } from '@utils/utilities'; + const commonConnectionFields = [ 'account', 'database', @@ -22,15 +25,35 @@ export type SnowflakeCredential = Pick< } | { authentication: 'keyPair'; + username: string; privateKey: string; + passphrase?: string; } ); +const extractPrivateKey = (credential: { privateKey: string; passphrase?: string }) => { + const key = formatPrivateKey(credential.privateKey as string); + + if (!credential.passphrase) return key; + + const privateKeyObject = createPrivateKey({ + key, + format: 'pem', + passphrase: credential.passphrase as string, + }); + + return privateKeyObject.export({ + format: 'pem', + type: 'pkcs8', + }) as string; +}; + export const getConnectionOptions = (credential: SnowflakeCredential) => { const connectionOptions: snowflake.ConnectionOptions = pick(credential, commonConnectionFields); if (credential.authentication === 'keyPair') { connectionOptions.authenticator = 'SNOWFLAKE_JWT'; - connectionOptions.privateKey = credential.privateKey; + connectionOptions.username = credential.username; + connectionOptions.privateKey = extractPrivateKey(credential); } else { connectionOptions.username = credential.username; connectionOptions.password = credential.password; diff --git a/packages/nodes-base/nodes/Snowflake/__tests__/GenericFunctions.test.ts b/packages/nodes-base/nodes/Snowflake/__tests__/GenericFunctions.test.ts index 13577d3852..a9af18094c 100644 --- a/packages/nodes-base/nodes/Snowflake/__tests__/GenericFunctions.test.ts +++ b/packages/nodes-base/nodes/Snowflake/__tests__/GenericFunctions.test.ts @@ -1,5 +1,9 @@ +import crypto from 'crypto'; + import { getConnectionOptions } from '../GenericFunctions'; +jest.mock('crypto'); + describe('getConnectionOptions', () => { const commonOptions = { account: 'test-account', @@ -29,12 +33,43 @@ describe('getConnectionOptions', () => { it('with private key for keyPair authentication', () => { const result = getConnectionOptions({ ...commonOptions, + username: 'test-username', authentication: 'keyPair', privateKey: 'test-private-key', }); expect(result).toEqual({ ...commonOptions, + username: 'test-username', + authenticator: 'SNOWFLAKE_JWT', + privateKey: 'test-private-key', + }); + }); + + it('with private key for keyPair authentication and passphrase', () => { + const createPrivateKeySpy = jest.spyOn(crypto, 'createPrivateKey').mockImplementation( + () => + ({ + export: () => 'test-private-key', + }) as unknown as crypto.KeyObject, + ); + const result = getConnectionOptions({ + ...commonOptions, + username: 'test-username', + authentication: 'keyPair', + privateKey: 'encrypted-private-key', + passphrase: 'test-passphrase', + }); + + expect(createPrivateKeySpy).toHaveBeenCalledWith({ + key: 'encrypted-private-key', + format: 'pem', + passphrase: 'test-passphrase', + }); + + expect(result).toEqual({ + ...commonOptions, + username: 'test-username', authenticator: 'SNOWFLAKE_JWT', privateKey: 'test-private-key', });