Skip to content

Commit 6d8317a

Browse files
authored
Merge pull request #93 from nibble-4bits/refactor-18
Refactor 18
2 parents 7d769bc + 5993770 commit 6d8317a

File tree

17 files changed

+2279
-1422
lines changed

17 files changed

+2279
-1422
lines changed

.github/workflows/pr-run-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
- uses: actions/checkout@v3
1010
- uses: actions/setup-node@v3
1111
with:
12-
node-version: '16'
12+
node-version: '18'
1313
- name: Install dependencies
1414
run: npm ci
1515
- name: Run tests

.github/workflows/prepare-for-release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/checkout@v3
1515
- uses: actions/setup-node@v3
1616
with:
17-
node-version: '16'
17+
node-version: '18'
1818
registry-url: 'https://registry.npmjs.org'
1919
- name: Install dependencies
2020
run: npm ci

.github/workflows/publish-package.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/checkout@v3
1515
- uses: actions/setup-node@v3
1616
with:
17-
node-version: '16'
17+
node-version: '18'
1818
registry-url: 'https://registry.npmjs.org'
1919
- name: Install dependencies
2020
run: npm ci

__tests__/intrinsicFunctions/StatesHash.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ describe('States.Hash intrinsic function', () => {
7575
expect(funcCallWrapper).toThrow(StatesRuntimeError);
7676
});
7777

78-
test('should throw error if passed hashing algorithm is not one of the supported algorithms', () => {
78+
test('should throw error if passed hash algorithm is not one of the supported algorithms', () => {
7979
const func = new StatesHash();
8080
const input = {};
8181
const context = {};

package-lock.json

+1,419-1,386
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+13-14
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,31 @@
4646
"scripts": {
4747
"test": "jest",
4848
"build": "tsup && rm build/main.d.cts",
49+
"build:watch": "tsup --watch",
4950
"prettier": "prettier --check \"src/**/*.ts\"",
5051
"prettier:fix": "prettier --write \"src/**/*.ts\"",
5152
"lint": "eslint \"src/**/*.ts\"",
5253
"lint:fix": "eslint --fix \"src/**/*.ts\""
5354
},
5455
"devDependencies": {
55-
"@types/crypto-js": "^4.2.1",
56-
"@types/jest": "^29.5.11",
57-
"@types/lodash": "^4.14.202",
58-
"@types/node": "^18.19.3",
59-
"@typescript-eslint/eslint-plugin": "^6.20.0",
60-
"@typescript-eslint/parser": "^6.20.0",
61-
"eslint": "^8.56.0",
56+
"@types/jest": "^29.5.12",
57+
"@types/lodash": "^4.17.4",
58+
"@types/node": "^18.19.33",
59+
"@typescript-eslint/eslint-plugin": "^6.21.0",
60+
"@typescript-eslint/parser": "^6.21.0",
61+
"eslint": "^8.57.0",
6262
"eslint-config-prettier": "^9.1.0",
6363
"eslint-plugin-prettier": "^5.1.3",
64-
"prettier": "^3.2.4",
65-
"ts-jest": "^29.1.1",
66-
"tsup": "^8.0.1",
67-
"typescript": "^5.3.3"
64+
"prettier": "^3.2.5",
65+
"ts-jest": "^29.1.3",
66+
"tsup": "^8.0.2",
67+
"typescript": "^5.4.5"
6868
},
6969
"dependencies": {
70-
"@aws-sdk/client-lambda": "^3.481.0",
71-
"@aws-sdk/credential-providers": "^3.481.0",
70+
"@aws-sdk/client-lambda": "^3.583.0",
71+
"@aws-sdk/credential-providers": "^3.583.0",
7272
"asl-validator": "^3.8.2",
7373
"commander": "^11.1.0",
74-
"crypto-js": "^4.2.0",
7574
"jsonpath-plus": "^7.2.0",
7675
"lodash": "^4.17.21",
7776
"p-limit": "^3.1.0",

src/stateMachine/StateExecutor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export class StateExecutor {
121121
nextState,
122122
isEndState,
123123
} = await this.stateHandlers[this.stateDefinition.Type](
124-
// @ts-expect-error Indexing `this.stateActions` by non-literal value produces a `never` type for the `this.stateDefinition` parameter of the handler being called
124+
// @ts-expect-error Indexing `this.stateHandlers` by non-literal value produces a `never` type for the `this.stateDefinition` parameter of the handler being called
125125
this.stateDefinition,
126126
rawInput,
127127
processedInput,

src/stateMachine/intrinsicFunctions/StatesHash.ts

+10-14
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import type { IntrinsicFunctionDefinition } from '../../typings/IntrinsicFunctionsImplementation';
2-
import type { HashingAlgorithm } from '../../typings/IntrinsicFunctions';
2+
import type { HashAlgorithm } from '../../typings/IntrinsicFunctions';
33
import type { JSONValue } from '../../typings/JSONValue';
44
import { StatesRuntimeError } from '../../error/predefined/StatesRuntimeError';
55
import { BaseIntrinsicFunction } from './BaseIntrinsicFunction';
6-
import md5 from 'crypto-js/md5.js';
7-
import sha1 from 'crypto-js/sha1.js';
8-
import sha256 from 'crypto-js/sha256.js';
9-
import sha384 from 'crypto-js/sha384.js';
10-
import sha512 from 'crypto-js/sha512.js';
6+
import { md5, sha1, sha256, sha384, sha512 } from '../../util/hash';
117

128
class StatesHash extends BaseIntrinsicFunction {
139
protected readonly funcDefinition: IntrinsicFunctionDefinition;
@@ -29,32 +25,32 @@ class StatesHash extends BaseIntrinsicFunction {
2925
};
3026
}
3127

32-
protected execute(str: string, algorithm: HashingAlgorithm): JSONValue {
28+
protected execute(str: string, algorithm: HashAlgorithm): JSONValue {
3329
if (str.length > 10000) {
3430
throw new StatesRuntimeError(
3531
`Intrinsic function ${this.funcDefinition.name} cannot hash a string with more than 10,000 characters`
3632
);
3733
}
3834

39-
const algorithms: HashingAlgorithm[] = ['MD5', 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];
35+
const algorithms: HashAlgorithm[] = ['MD5', 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];
4036
const supportedAlgorithms = algorithms.join(', ');
4137
if (!algorithms.includes(algorithm)) {
4238
throw new StatesRuntimeError(
43-
`Unsupported hashing algorithm provided to intrinsic function ${this.funcDefinition.name}. The supported algorithms are: ${supportedAlgorithms}`
39+
`Unsupported hash algorithm '${algorithm}' provided to intrinsic function ${this.funcDefinition.name}. The supported algorithms are: ${supportedAlgorithms}`
4440
);
4541
}
4642

4743
switch (algorithm) {
4844
case 'MD5':
49-
return md5(str).toString();
45+
return md5.getDigest(str);
5046
case 'SHA-1':
51-
return sha1(str).toString();
47+
return sha1.getDigest(str);
5248
case 'SHA-256':
53-
return sha256(str).toString();
49+
return sha256.getDigest(str);
5450
case 'SHA-384':
55-
return sha384(str).toString();
51+
return sha384.getDigest(str);
5652
case 'SHA-512':
57-
return sha512(str).toString();
53+
return sha512.getDigest(str);
5854
}
5955
}
6056
}

src/typings/IntrinsicFunctions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export type IntrinsicFunctionName =
1818
| 'States.StringSplit'
1919
| 'States.UUID';
2020

21-
export type HashingAlgorithm = 'MD5' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
21+
export type HashAlgorithm = 'MD5' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';

src/util/hash.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { MD5 } from './hash/MD5';
2+
import { SHA1 } from './hash/SHA1';
3+
import { SHA256 } from './hash/SHA256';
4+
import { SHA384 } from './hash/SHA384';
5+
import { SHA512 } from './hash/SHA512';
6+
7+
export const md5 = new MD5();
8+
export const sha1 = new SHA1();
9+
export const sha256 = new SHA256();
10+
export const sha384 = new SHA384();
11+
export const sha512 = new SHA512();

src/util/hash/BaseHash.ts

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// TypeScript's DOM library has to be referenced for `TextEncoder` to be recognized as a type
2+
/// <reference lib="dom" />
3+
4+
export abstract class BaseHashAlgorithm {
5+
private textEncoder: TextEncoder;
6+
7+
constructor() {
8+
this.textEncoder = new TextEncoder();
9+
}
10+
11+
getDigest(input: string): string {
12+
const message = this.textEncoder.encode(input);
13+
14+
const paddedMessage = this.padMessage(message);
15+
const hash = this.computeHash(paddedMessage);
16+
const digest = this.hashToString(hash);
17+
18+
return digest;
19+
}
20+
21+
protected abstract padMessage(message: Uint8Array): ArrayBuffer;
22+
23+
protected abstract computeHash(paddedMessage: ArrayBuffer): ArrayBuffer;
24+
25+
protected abstract hashToString(hash: ArrayBuffer): string;
26+
27+
protected rotl(n: number, x: number): number;
28+
protected rotl(n: bigint, x: bigint): bigint;
29+
protected rotl(n: number | bigint, x: number | bigint): number | bigint {
30+
if (typeof n === 'number' && typeof x === 'number') return (x << n) | (x >>> (32 - n));
31+
if (typeof n === 'bigint' && typeof x === 'bigint') return (x << n) | (x >> (64n - n));
32+
33+
throw new Error('Both arguments must be of the same type');
34+
}
35+
36+
protected rotr(n: number, x: number): number;
37+
protected rotr(n: bigint, x: bigint): bigint;
38+
protected rotr(n: number | bigint, x: number | bigint): number | bigint {
39+
if (typeof n === 'number' && typeof x === 'number') return (x >>> n) | (x << (32 - n));
40+
if (typeof n === 'bigint' && typeof x === 'bigint') return (x >> n) | (x << (64n - n));
41+
42+
throw new Error('Both arguments must be of the same type');
43+
}
44+
45+
protected ch(x: number, y: number, z: number): number;
46+
protected ch(x: bigint, y: bigint, z: bigint): bigint;
47+
protected ch(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
48+
if (typeof x === typeof y && typeof y === typeof z) {
49+
// @ts-expect-error TypeScript can't disambiguate between number and bigint
50+
return (x & y) ^ (~x & z);
51+
}
52+
53+
throw new Error('All arguments must be of the same type');
54+
}
55+
56+
protected parity(x: number, y: number, z: number): number;
57+
protected parity(x: bigint, y: bigint, z: bigint): bigint;
58+
protected parity(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
59+
if (typeof x === typeof y && typeof y === typeof z) {
60+
// @ts-expect-error TypeScript can't disambiguate between number and bigint
61+
return x ^ y ^ z;
62+
}
63+
64+
throw new Error('All arguments must be of the same type');
65+
}
66+
67+
protected maj(x: number, y: number, z: number): number;
68+
protected maj(x: bigint, y: bigint, z: bigint): bigint;
69+
protected maj(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
70+
if (typeof x === typeof y && typeof y === typeof z) {
71+
// @ts-expect-error TypeScript can't disambiguate between number and bigint
72+
return (x & y) ^ (x & z) ^ (y & z);
73+
}
74+
75+
throw new Error('All arguments must be of the same type');
76+
}
77+
78+
protected bigSigma0(x: number): number;
79+
protected bigSigma0(x: bigint): bigint;
80+
protected bigSigma0(x: number | bigint): number | bigint {
81+
if (typeof x === 'number') {
82+
// number version used by SHA1 and SHA256
83+
return this.rotr(2, x) ^ this.rotr(13, x) ^ this.rotr(22, x);
84+
}
85+
86+
// BigInt version used by SHA384 and SHA512
87+
return this.rotr(28n, x) ^ this.rotr(34n, x) ^ this.rotr(39n, x);
88+
}
89+
90+
protected bigSigma1(x: number): number;
91+
protected bigSigma1(x: bigint): bigint;
92+
protected bigSigma1(x: number | bigint): number | bigint {
93+
if (typeof x === 'number') {
94+
// number version used by SHA1 and SHA256
95+
return this.rotr(6, x) ^ this.rotr(11, x) ^ this.rotr(25, x);
96+
}
97+
98+
// BigInt version used by SHA384 and SHA512
99+
return this.rotr(14n, x) ^ this.rotr(18n, x) ^ this.rotr(41n, x);
100+
}
101+
102+
protected smallSigma0(x: number): number;
103+
protected smallSigma0(x: bigint): bigint;
104+
protected smallSigma0(x: number | bigint): number | bigint {
105+
if (typeof x === 'number') {
106+
// number version used by SHA1 and SHA256
107+
return this.rotr(7, x) ^ this.rotr(18, x) ^ (x >>> 3);
108+
}
109+
110+
// BigInt version used by SHA384 and SHA512
111+
return this.rotr(1n, x) ^ this.rotr(8n, x) ^ (x >> 7n);
112+
}
113+
114+
protected smallSigma1(x: number): number;
115+
protected smallSigma1(x: bigint): bigint;
116+
protected smallSigma1(x: number | bigint): number | bigint {
117+
if (typeof x === 'number') {
118+
// number version used by SHA1 and SHA256
119+
return this.rotr(17, x) ^ this.rotr(19, x) ^ (x >>> 10);
120+
}
121+
122+
// BigInt version used by SHA384 and SHA512
123+
return this.rotr(19n, x) ^ this.rotr(61n, x) ^ (x >> 6n);
124+
}
125+
}

0 commit comments

Comments
 (0)