Skip to content

Commit

Permalink
Throw error on crypto.createDecipher for node 22
Browse files Browse the repository at this point in the history
  • Loading branch information
ceciliaavila committed Nov 28, 2024
1 parent 628dde8 commit f361b16
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 24 deletions.
5 changes: 4 additions & 1 deletion libraries/botframework-config/src/botConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,10 @@ export class BotConfiguration extends BotConfigurationBase {
}
}
}
} catch {
} catch (legacyErr) {
if (legacyErr.message.includes('Node.js versions')) {
throw legacyErr;
}
throw err;
}
}
Expand Down
29 changes: 24 additions & 5 deletions libraries/botframework-config/src/encrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import crypto from 'crypto';
import { version as nodeVersion } from 'process';

/**
* @private
Expand Down Expand Up @@ -100,10 +101,28 @@ export function decryptString(encryptedValue: string, secret: string): string {
* @param secret
*/
export function legacyDecrypt(encryptedValue: string, secret: string): string {
// LEGACY for pre standardized SHA256 encryption, this uses some undocumented nodejs MD5 hash internally and is deprecated
const decipher: crypto.Decipher = crypto.createDecipher('aes192', secret);
let value: string = decipher.update(encryptedValue, 'hex', 'utf8');
value += decipher.final('utf8');
const UNSUPPORTED_VERSION = '22.0.0';
if (!isNodeCompatible(nodeVersion, UNSUPPORTED_VERSION)) {
throw new Error(`This method is not available for Node.js versions over ${UNSUPPORTED_VERSION}.`);
} else {
// LEGACY for pre standardized SHA256 encryption, this uses some undocumented nodejs MD5 hash internally and is deprecated
const decipher: crypto.Decipher = crypto.createDecipher('aes192', secret);
let value: string = decipher.update(encryptedValue, 'hex', 'utf8');
value += decipher.final('utf8');

return value;
}
}

return value;
/**
* private
*
* @param currentVersion The current version of Node.js.
* @param minVersion The minimum unsupported version.
* @returns true if the current version of Node is lower than the unsupported version.
*/
function isNodeCompatible(currentVersion: string, minVersion: string): boolean {
const [currentMajor] = currentVersion.replace('v', '').split('.').map(Number);
const [minMajor] = minVersion.split('.').map(Number);
return currentMajor < minMajor;
}
51 changes: 33 additions & 18 deletions libraries/botframework-config/tests/loadAndSave.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const testBotPath = require.resolve('./test.bot');
const govTestBotPath = require.resolve('./govTest.bot');
const legacyBotPath = require.resolve('./legacy.bot');
const saveBotPath = testBotPath.replace('test.bot', 'save.bot');
const [nodeVersion] = process.version.replace('v', '').split('.').map(Number);

describe('LoadAndSaveTests', function () {
it('DeserializeBotFile', async function () {
Expand Down Expand Up @@ -89,12 +90,19 @@ describe('LoadAndSaveTests', function () {
const config = await bf.BotConfiguration.load(testBotPath);
await config.saveAs(saveBotPath, secret);

await assert.rejects(
bf.BotConfiguration.load(saveBotPath),
new Error(
'You are attempting to perform an operation which needs access to the secret and --secret is missing'
)
);
if (nodeVersion >= 22) {
await assert.rejects(
bf.BotConfiguration.load(saveBotPath),
new Error('This method is not available for Node.js versions over 22.0.0.'),
);
} else {
await assert.rejects(
bf.BotConfiguration.load(saveBotPath),
new Error(
'You are attempting to perform an operation which needs access to the secret and --secret is missing'
),
);
}
});

it('LoadAndVerifyChannelServiceSync', async function () {
Expand Down Expand Up @@ -354,17 +362,24 @@ describe('LoadAndSaveTests', function () {
});

it('LegacyEncryption', async function () {
let config = await bf.BotConfiguration.load(legacyBotPath, 'password');
assert.equal(config.services[0].appPassword, 'xyzpdq', 'value should be unencrypted');
assert.ok(config.padlock != null, 'padlock should exist');
assert.ok(!config.secretKey, 'secretKey should not exist');

const secret = bf.BotConfiguration.generateKey();
await config.saveAs(saveBotPath, secret);
config = await bf.BotConfiguration.load(saveBotPath, secret);
fs.unlinkSync(saveBotPath);
assert.ok(config.padlock != null, 'padlock should exist');
assert.ok(config.padlock.length > 0, 'padlock should not be empty');
assert.ok(!config.secretKey, 'secretKey should not exist');
if (nodeVersion >= 22) {
await assert.rejects(
bf.BotConfiguration.load(legacyBotPath, 'password'),
new Error('This method is not available for Node.js versions over 22.0.0.'),
);
} else {
let config = await bf.BotConfiguration.load(legacyBotPath, 'password');
assert.equal(config.services[0].appPassword, 'xyzpdq', 'value should be unencrypted');
assert.ok(config.padlock != null, 'padlock should exist');
assert.ok(!config.secretKey, 'secretKey should not exist');

const secret = bf.BotConfiguration.generateKey();
await config.saveAs(saveBotPath, secret);
config = await bf.BotConfiguration.load(saveBotPath, secret);
fs.unlinkSync(saveBotPath);
assert.ok(config.padlock != null, 'padlock should exist');
assert.ok(config.padlock.length > 0, 'padlock should not be empty');
assert.ok(!config.secretKey, 'secretKey should not exist');
}
});
});

0 comments on commit f361b16

Please sign in to comment.