Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Remove discontinued crypto-js #8104

Merged
merged 4 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/cli/BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

This list shows all the versions which include breaking changes and how to upgrade.

## 1.22.0

### What changed?

Hash algorithm `ripemd160` is dropped from `.hash()` expressions.
`sha3` hash algorithm now returns a valid sha3-512 has, unlike the previous implementation that returned a `Keccak` hash instead.

### When is action necessary?

If you are using `.hash` helpers in expressions with hash algorithm `ripemd160`, you need to switch to one of the other supported algorithms.

## 1.15.0

### What changed?
Expand Down
5 changes: 3 additions & 2 deletions packages/workflow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,28 @@
"dist/**/*"
],
"devDependencies": {
"@types/crypto-js": "^4.1.3",
"@types/deep-equal": "^1.0.1",
"@types/express": "^4.17.6",
"@types/jmespath": "^0.15.0",
"@types/lodash": "^4.14.195",
"@types/luxon": "^3.2.0",
"@types/md5": "^2.3.5",
"@types/xml2js": "^0.4.11"
},
"dependencies": {
"@n8n/tournament": "1.0.2",
"@n8n_io/riot-tmpl": "4.0.0",
"ast-types": "0.15.2",
"callsites": "3.1.0",
"crypto-js": "4.2.0",
"deep-equal": "2.2.0",
"esprima-next": "5.8.4",
"form-data": "4.0.0",
"jmespath": "0.16.0",
"js-base64": "3.7.2",
"jssha": "3.3.1",
"lodash": "4.17.21",
"luxon": "3.3.0",
"md5": "2.3.0",
"recast": "0.21.5",
"title-case": "3.0.3",
"transliteration": "2.3.5",
Expand Down
69 changes: 40 additions & 29 deletions packages/workflow/src/Extensions/StringExtensions.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
// import { createHash } from 'crypto';
import SHA from 'jssha';
import MD5 from 'md5';
import { encode } from 'js-base64';
import { titleCase } from 'title-case';
import type { ExtensionMap } from './Extensions';
import CryptoJS from 'crypto-js';
import { encode } from 'js-base64';
import { transliterate } from 'transliteration';
import { ExpressionExtensionError } from '../errors/expression-extension.error';

const hashFunctions: Record<string, typeof CryptoJS.MD5> = {
md5: CryptoJS.MD5,
sha1: CryptoJS.SHA1,
sha224: CryptoJS.SHA224,
sha256: CryptoJS.SHA256,
sha384: CryptoJS.SHA384,
sha512: CryptoJS.SHA512,
sha3: CryptoJS.SHA3,
ripemd160: CryptoJS.RIPEMD160,
};
export const SupportedHashAlgorithms = [
'md5',
'sha1',
'sha224',
'sha256',
'sha384',
'sha512',
'sha3',
] as const;

// All symbols from https://www.xe.com/symbols/ as for 2022/11/09
const CURRENCY_REGEXP =
Expand Down Expand Up @@ -113,23 +112,35 @@ const URL_REGEXP =
const CHAR_TEST_REGEXP = /\p{L}/u;
const PUNC_TEST_REGEXP = /[!?.]/;

function hash(value: string, extraArgs?: unknown): string {
const [algorithm = 'MD5'] = extraArgs as string[];
if (algorithm.toLowerCase() === 'base64') {
// We're using a library instead of btoa because btoa only
// works on ASCII
return encode(value);
}
const hashFunction = hashFunctions[algorithm.toLowerCase()];
if (!hashFunction) {
throw new ExpressionExtensionError(
`Unknown algorithm ${algorithm}. Available algorithms are: ${Object.keys(hashFunctions)
.map((s) => s.toUpperCase())
.join(', ')}, and Base64.`,
);
function hash(value: string, extraArgs: string[]): string {
const algorithm = extraArgs[0]?.toLowerCase() ?? 'md5';
switch (algorithm) {
case 'base64':
return encode(value);
case 'md5':
return MD5(value);
case 'sha1':
case 'sha224':
case 'sha256':
case 'sha384':
case 'sha512':
case 'sha3':
const variant = (
{
sha1: 'SHA-1',
sha224: 'SHA-224',
sha256: 'SHA-256',
sha384: 'SHA-384',
sha512: 'SHA-512',
sha3: 'SHA3-512',
} as const
)[algorithm];
return new SHA(variant, 'TEXT').update(value).getHash('HEX');
default:
throw new ExpressionExtensionError(
`Unknown algorithm ${algorithm}. Available algorithms are: ${SupportedHashAlgorithms.join()}, and Base64.`,
);
}
return hashFunction(value.toString()).toString();
// return createHash(format).update(value.toString()).digest('hex');
}

function isEmpty(value: string): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/**
* @jest-environment jsdom
*/

import { stringExtensions } from '@/Extensions/StringExtensions';
import { evaluate } from './Helpers';

describe('Data Transformation Functions', () => {
Expand All @@ -15,28 +13,28 @@ describe('Data Transformation Functions', () => {
expect(evaluate('={{"".isEmpty()}}')).toEqual(true);
});

test('.hash() should work correctly on a string', () => {
expect(evaluate('={{ "12345".hash("sha256") }}')).toEqual(
stringExtensions.functions.hash('12345', ['sha256']),
);

expect(evaluate('={{ "12345".hash("sha256") }}')).not.toEqual(
stringExtensions.functions.hash('12345', ['MD5']),
);

expect(evaluate('={{ "12345".hash("MD5") }}')).toEqual(
stringExtensions.functions.hash('12345', ['MD5']),
);

expect(evaluate('={{ "12345".hash("sha256") }}')).toEqual(
'5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5',
);
});

test('.hash() alias should work correctly on a string', () => {
expect(evaluate('={{ "12345".hash("sha256") }}')).toEqual(
'5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5',
);
describe('.hash()', () => {
test.each([
['md5', '827ccb0eea8a706c4c34a16891f84e7b'],
['sha1', '8cb2237d0679ca88db6464eac60da96345513964'],
['sha224', 'a7470858e79c282bc2f6adfd831b132672dfd1224c1e78cbf5bcd057'],
['sha256', '5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5'],
[
'sha384',
'0fa76955abfa9dafd83facca8343a92aa09497f98101086611b0bfa95dbc0dcc661d62e9568a5a032ba81960f3e55d4a',
],
[
'sha512',
'3627909a29c31381a071ec27f7c9ca97726182aed29a7ddd2e54353322cfb30abb9e3a6df2ac2c20fe23436311d678564d0c8d305930575f60e2d3d048184d79',
],
[
'sha3',
'0a2a1719bf3ce682afdbedf3b23857818d526efbe7fcb372b31347c26239a0f916c398b7ad8dd0ee76e8e388604d0b0f925d5e913ad2d3165b9b35b3844cd5e6',
],
])('should work for %p', (hashFn, hashValue) => {
expect(evaluate(`={{ "12345".hash("${hashFn}") }}`)).toEqual(hashValue);
expect(evaluate(`={{ "12345".hash("${hashFn.toLowerCase()}") }}`)).toEqual(hashValue);
});
});

test('.urlDecode should work correctly on a string', () => {
Expand Down
27 changes: 17 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading