Skip to content

Refactor 18 #93

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

Merged
merged 18 commits into from
May 28, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/pr-run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prepare-for-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
Expand Down
2 changes: 1 addition & 1 deletion __tests__/intrinsicFunctions/StatesHash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('States.Hash intrinsic function', () => {
expect(funcCallWrapper).toThrow(StatesRuntimeError);
});

test('should throw error if passed hashing algorithm is not one of the supported algorithms', () => {
test('should throw error if passed hash algorithm is not one of the supported algorithms', () => {
const func = new StatesHash();
const input = {};
const context = {};
Expand Down
2,805 changes: 1,419 additions & 1,386 deletions package-lock.json

Large diffs are not rendered by default.

27 changes: 13 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,31 @@
"scripts": {
"test": "jest",
"build": "tsup && rm build/main.d.cts",
"build:watch": "tsup --watch",
"prettier": "prettier --check \"src/**/*.ts\"",
"prettier:fix": "prettier --write \"src/**/*.ts\"",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint --fix \"src/**/*.ts\""
},
"devDependencies": {
"@types/crypto-js": "^4.2.1",
"@types/jest": "^29.5.11",
"@types/lodash": "^4.14.202",
"@types/node": "^18.19.3",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.56.0",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.4",
"@types/node": "^18.19.33",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"prettier": "^3.2.4",
"ts-jest": "^29.1.1",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
"prettier": "^3.2.5",
"ts-jest": "^29.1.3",
"tsup": "^8.0.2",
"typescript": "^5.4.5"
},
"dependencies": {
"@aws-sdk/client-lambda": "^3.481.0",
"@aws-sdk/credential-providers": "^3.481.0",
"@aws-sdk/client-lambda": "^3.583.0",
"@aws-sdk/credential-providers": "^3.583.0",
"asl-validator": "^3.8.2",
"commander": "^11.1.0",
"crypto-js": "^4.2.0",
"jsonpath-plus": "^7.2.0",
"lodash": "^4.17.21",
"p-limit": "^3.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/stateMachine/StateExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class StateExecutor {
nextState,
isEndState,
} = await this.stateHandlers[this.stateDefinition.Type](
// @ts-expect-error Indexing `this.stateActions` by non-literal value produces a `never` type for the `this.stateDefinition` parameter of the handler being called
// @ts-expect-error Indexing `this.stateHandlers` by non-literal value produces a `never` type for the `this.stateDefinition` parameter of the handler being called
this.stateDefinition,
rawInput,
processedInput,
Expand Down
24 changes: 10 additions & 14 deletions src/stateMachine/intrinsicFunctions/StatesHash.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import type { IntrinsicFunctionDefinition } from '../../typings/IntrinsicFunctionsImplementation';
import type { HashingAlgorithm } from '../../typings/IntrinsicFunctions';
import type { HashAlgorithm } from '../../typings/IntrinsicFunctions';
import type { JSONValue } from '../../typings/JSONValue';
import { StatesRuntimeError } from '../../error/predefined/StatesRuntimeError';
import { BaseIntrinsicFunction } from './BaseIntrinsicFunction';
import md5 from 'crypto-js/md5.js';
import sha1 from 'crypto-js/sha1.js';
import sha256 from 'crypto-js/sha256.js';
import sha384 from 'crypto-js/sha384.js';
import sha512 from 'crypto-js/sha512.js';
import { md5, sha1, sha256, sha384, sha512 } from '../../util/hash';

class StatesHash extends BaseIntrinsicFunction {
protected readonly funcDefinition: IntrinsicFunctionDefinition;
Expand All @@ -29,32 +25,32 @@ class StatesHash extends BaseIntrinsicFunction {
};
}

protected execute(str: string, algorithm: HashingAlgorithm): JSONValue {
protected execute(str: string, algorithm: HashAlgorithm): JSONValue {
if (str.length > 10000) {
throw new StatesRuntimeError(
`Intrinsic function ${this.funcDefinition.name} cannot hash a string with more than 10,000 characters`
);
}

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

switch (algorithm) {
case 'MD5':
return md5(str).toString();
return md5.getDigest(str);
case 'SHA-1':
return sha1(str).toString();
return sha1.getDigest(str);
case 'SHA-256':
return sha256(str).toString();
return sha256.getDigest(str);
case 'SHA-384':
return sha384(str).toString();
return sha384.getDigest(str);
case 'SHA-512':
return sha512(str).toString();
return sha512.getDigest(str);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/typings/IntrinsicFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ export type IntrinsicFunctionName =
| 'States.StringSplit'
| 'States.UUID';

export type HashingAlgorithm = 'MD5' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
export type HashAlgorithm = 'MD5' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
11 changes: 11 additions & 0 deletions src/util/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MD5 } from './hash/MD5';
import { SHA1 } from './hash/SHA1';
import { SHA256 } from './hash/SHA256';
import { SHA384 } from './hash/SHA384';
import { SHA512 } from './hash/SHA512';

export const md5 = new MD5();
export const sha1 = new SHA1();
export const sha256 = new SHA256();
export const sha384 = new SHA384();
export const sha512 = new SHA512();
125 changes: 125 additions & 0 deletions src/util/hash/BaseHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// TypeScript's DOM library has to be referenced for `TextEncoder` to be recognized as a type
/// <reference lib="dom" />

export abstract class BaseHashAlgorithm {
private textEncoder: TextEncoder;

constructor() {
this.textEncoder = new TextEncoder();
}

getDigest(input: string): string {
const message = this.textEncoder.encode(input);

const paddedMessage = this.padMessage(message);
const hash = this.computeHash(paddedMessage);
const digest = this.hashToString(hash);

return digest;
}

protected abstract padMessage(message: Uint8Array): ArrayBuffer;

protected abstract computeHash(paddedMessage: ArrayBuffer): ArrayBuffer;

protected abstract hashToString(hash: ArrayBuffer): string;

protected rotl(n: number, x: number): number;
protected rotl(n: bigint, x: bigint): bigint;
protected rotl(n: number | bigint, x: number | bigint): number | bigint {
if (typeof n === 'number' && typeof x === 'number') return (x << n) | (x >>> (32 - n));
if (typeof n === 'bigint' && typeof x === 'bigint') return (x << n) | (x >> (64n - n));

throw new Error('Both arguments must be of the same type');
}

protected rotr(n: number, x: number): number;
protected rotr(n: bigint, x: bigint): bigint;
protected rotr(n: number | bigint, x: number | bigint): number | bigint {
if (typeof n === 'number' && typeof x === 'number') return (x >>> n) | (x << (32 - n));
if (typeof n === 'bigint' && typeof x === 'bigint') return (x >> n) | (x << (64n - n));

throw new Error('Both arguments must be of the same type');
}

protected ch(x: number, y: number, z: number): number;
protected ch(x: bigint, y: bigint, z: bigint): bigint;
protected ch(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
if (typeof x === typeof y && typeof y === typeof z) {
// @ts-expect-error TypeScript can't disambiguate between number and bigint
return (x & y) ^ (~x & z);
}

throw new Error('All arguments must be of the same type');
}

protected parity(x: number, y: number, z: number): number;
protected parity(x: bigint, y: bigint, z: bigint): bigint;
protected parity(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
if (typeof x === typeof y && typeof y === typeof z) {
// @ts-expect-error TypeScript can't disambiguate between number and bigint
return x ^ y ^ z;
}

throw new Error('All arguments must be of the same type');
}

protected maj(x: number, y: number, z: number): number;
protected maj(x: bigint, y: bigint, z: bigint): bigint;
protected maj(x: number | bigint, y: number | bigint, z: number | bigint): number | bigint {
if (typeof x === typeof y && typeof y === typeof z) {
// @ts-expect-error TypeScript can't disambiguate between number and bigint
return (x & y) ^ (x & z) ^ (y & z);
}

throw new Error('All arguments must be of the same type');
}

protected bigSigma0(x: number): number;
protected bigSigma0(x: bigint): bigint;
protected bigSigma0(x: number | bigint): number | bigint {
if (typeof x === 'number') {
// number version used by SHA1 and SHA256
return this.rotr(2, x) ^ this.rotr(13, x) ^ this.rotr(22, x);
}

// BigInt version used by SHA384 and SHA512
return this.rotr(28n, x) ^ this.rotr(34n, x) ^ this.rotr(39n, x);
}

protected bigSigma1(x: number): number;
protected bigSigma1(x: bigint): bigint;
protected bigSigma1(x: number | bigint): number | bigint {
if (typeof x === 'number') {
// number version used by SHA1 and SHA256
return this.rotr(6, x) ^ this.rotr(11, x) ^ this.rotr(25, x);
}

// BigInt version used by SHA384 and SHA512
return this.rotr(14n, x) ^ this.rotr(18n, x) ^ this.rotr(41n, x);
}

protected smallSigma0(x: number): number;
protected smallSigma0(x: bigint): bigint;
protected smallSigma0(x: number | bigint): number | bigint {
if (typeof x === 'number') {
// number version used by SHA1 and SHA256
return this.rotr(7, x) ^ this.rotr(18, x) ^ (x >>> 3);
}

// BigInt version used by SHA384 and SHA512
return this.rotr(1n, x) ^ this.rotr(8n, x) ^ (x >> 7n);
}

protected smallSigma1(x: number): number;
protected smallSigma1(x: bigint): bigint;
protected smallSigma1(x: number | bigint): number | bigint {
if (typeof x === 'number') {
// number version used by SHA1 and SHA256
return this.rotr(17, x) ^ this.rotr(19, x) ^ (x >>> 10);
}

// BigInt version used by SHA384 and SHA512
return this.rotr(19n, x) ^ this.rotr(61n, x) ^ (x >> 6n);
}
}
Loading
Loading