From e3ca2a5941944b521adf52cc849617f57a7cf2bc Mon Sep 17 00:00:00 2001 From: Daniel Regeci <536331+ovx@users.noreply.github.com> Date: Tue, 26 Mar 2024 15:10:16 +0100 Subject: [PATCH] 0.1.2 --- cjs/dist/helpers.d.ts | 6 ++++++ cjs/dist/helpers.js | 39 +++++++++++++++++++++++++++++++++++++++ cjs/dist/index.d.ts | 3 +++ cjs/dist/index.js | 36 ++++++++++++++++++++++++++++++++++++ cjs/dist/types.d.ts | 22 ++++++++++++++++++++++ cjs/dist/types.js | 2 ++ cjs/package.json | 3 +++ dist/helpers.js | 4 ++-- lib/helpers.ts | 4 ++-- package-lock.json | 4 ++-- package.json | 9 ++++++--- tsconfig.cjs.json | 8 ++++++++ 12 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 cjs/dist/helpers.d.ts create mode 100644 cjs/dist/helpers.js create mode 100644 cjs/dist/index.d.ts create mode 100644 cjs/dist/index.js create mode 100644 cjs/dist/types.d.ts create mode 100644 cjs/dist/types.js create mode 100644 cjs/package.json create mode 100644 tsconfig.cjs.json diff --git a/cjs/dist/helpers.d.ts b/cjs/dist/helpers.d.ts new file mode 100644 index 0000000..9bea651 --- /dev/null +++ b/cjs/dist/helpers.d.ts @@ -0,0 +1,6 @@ +import type { Algorithm } from './types.js'; +export declare function ab2hex(ab: ArrayBuffer | Uint8Array): string; +export declare function hash(algorithm: Algorithm, str: string): Promise; +export declare function hmac(algorithm: Algorithm, str: string, secret: string): Promise; +export declare function randomBytes(length: number): Uint8Array; +export declare function randomInt(max: number): number; diff --git a/cjs/dist/helpers.js b/cjs/dist/helpers.js new file mode 100644 index 0000000..3ce18e1 --- /dev/null +++ b/cjs/dist/helpers.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.randomInt = exports.randomBytes = exports.hmac = exports.hash = exports.ab2hex = void 0; +const encoder = new TextEncoder(); +if (!('crypto' in globalThis)) { + // eslint-disable-next-line @typescript-eslint/no-var-requires + globalThis.crypto = require('node:crypto').webcrypto; +} +function ab2hex(ab) { + return [...new Uint8Array(ab)] + .map((x) => x.toString(16).padStart(2, '0')) + .join(''); +} +exports.ab2hex = ab2hex; +async function hash(algorithm, str) { + return ab2hex(await crypto.subtle.digest(algorithm.toUpperCase(), encoder.encode(str))); +} +exports.hash = hash; +async function hmac(algorithm, str, secret) { + const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { + name: 'HMAC', + hash: algorithm, + }, false, ['sign', 'verify']); + return ab2hex(await crypto.subtle.sign('HMAC', key, encoder.encode(str))); +} +exports.hmac = hmac; +function randomBytes(length) { + const ab = new Uint8Array(length); + crypto.getRandomValues(ab); + return ab; +} +exports.randomBytes = randomBytes; +function randomInt(max) { + const ab = new Uint32Array(1); + crypto.getRandomValues(ab); + const randomNumber = ab[0] / (0xffffffff + 1); + return Math.floor(randomNumber * max + 1); +} +exports.randomInt = randomInt; diff --git a/cjs/dist/index.d.ts b/cjs/dist/index.d.ts new file mode 100644 index 0000000..d78ee6f --- /dev/null +++ b/cjs/dist/index.d.ts @@ -0,0 +1,3 @@ +import type { Challenge, ChallengeOptions, Payload } from './types.js'; +export declare function createChallenge(options: ChallengeOptions): Promise; +export declare function verifySolution(payload: string | Payload, hmacKey: string): Promise; diff --git a/cjs/dist/index.js b/cjs/dist/index.js new file mode 100644 index 0000000..ce71e47 --- /dev/null +++ b/cjs/dist/index.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.verifySolution = exports.createChallenge = void 0; +const helpers_js_1 = require("./helpers.js"); +const DEFAULT_MAX_NUMBER = 1e6; +const DEFAULT_SALT_LEN = 12; +const DEFAULT_ALG = 'SHA-256'; +async function createChallenge(options) { + const algorithm = options.algorithm || DEFAULT_ALG; + const maxNumber = options.maxNumber || DEFAULT_MAX_NUMBER; + const saltLength = options.saltLength || DEFAULT_SALT_LEN; + const salt = options.salt || (0, helpers_js_1.ab2hex)((0, helpers_js_1.randomBytes)(saltLength)); + const number = options.number === void 0 ? (0, helpers_js_1.randomInt)(maxNumber) : options.number; + const challenge = await (0, helpers_js_1.hash)(algorithm, salt + number); + return { + algorithm, + challenge, + salt, + signature: await (0, helpers_js_1.hmac)(algorithm, challenge, options.hmacKey), + }; +} +exports.createChallenge = createChallenge; +async function verifySolution(payload, hmacKey) { + if (typeof payload === 'string') { + payload = JSON.parse(atob(payload)); + } + const check = await createChallenge({ + algorithm: payload.algorithm, + hmacKey, + number: payload.number, + salt: payload.salt, + }); + return (check.challenge === payload.challenge && + check.signature === payload.signature); +} +exports.verifySolution = verifySolution; diff --git a/cjs/dist/types.d.ts b/cjs/dist/types.d.ts new file mode 100644 index 0000000..3c9cba4 --- /dev/null +++ b/cjs/dist/types.d.ts @@ -0,0 +1,22 @@ +export type Algorithm = 'SHA-1' | 'SHA-256' | 'SHA-512'; +export interface Challenge { + algorithm: Algorithm; + challenge: string; + salt: string; + signature: string; +} +export interface ChallengeOptions { + algorithm?: Algorithm; + hmacKey: string; + maxNumber?: number; + number?: number; + salt?: string; + saltLength?: number; +} +export interface Payload { + algorithm: Algorithm; + challenge: string; + number: number; + salt: string; + signature: string; +} diff --git a/cjs/dist/types.js b/cjs/dist/types.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/cjs/dist/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/cjs/package.json b/cjs/package.json new file mode 100644 index 0000000..6a0d2ef --- /dev/null +++ b/cjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} \ No newline at end of file diff --git a/dist/helpers.js b/dist/helpers.js index a76d27d..bd2f842 100644 --- a/dist/helpers.js +++ b/dist/helpers.js @@ -1,7 +1,7 @@ const encoder = new TextEncoder(); if (!('crypto' in globalThis)) { - // @ts-ignore - globalThis.crypto = (await import('node:crypto')).webcrypto; + // eslint-disable-next-line @typescript-eslint/no-var-requires + globalThis.crypto = require('node:crypto').webcrypto; } export function ab2hex(ab) { return [...new Uint8Array(ab)] diff --git a/lib/helpers.ts b/lib/helpers.ts index 8e35da7..2807099 100644 --- a/lib/helpers.ts +++ b/lib/helpers.ts @@ -3,8 +3,8 @@ import type { Algorithm } from './types.js'; const encoder = new TextEncoder(); if (!('crypto' in globalThis)) { - // @ts-ignore - globalThis.crypto = (await import('node:crypto')).webcrypto; + // eslint-disable-next-line @typescript-eslint/no-var-requires + globalThis.crypto = require('node:crypto').webcrypto; } export function ab2hex(ab: ArrayBuffer | Uint8Array) { diff --git a/package-lock.json b/package-lock.json index 5ec4fbe..64dfc13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "altcha-lib", - "version": "0.0.1", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "altcha-lib", - "version": "0.0.1", + "version": "0.1.1", "license": "MIT", "devDependencies": { "@types/node": "^20.9.0", diff --git a/package.json b/package.json index 2b08223..143f26c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "altcha-lib", - "version": "0.1.1", + "version": "0.1.2", "description": "A library for creating and verifying ALTCHA challenges for Node.js, Bun and Deno.", "author": "Daniel Regeci", "license": "MIT", @@ -15,7 +15,7 @@ "types": "./dist/index.d.ts", "type": "module", "scripts": { - "build": "rimraf dist && tsc -p tsconfig.build.json", + "build": "rimraf dist && rimraf cjs/dist && tsc -b tsconfig.build.json tsconfig.cjs.json", "denoify": "rimraf deno_dist && denoify && find deno_dist/. -type f -exec sed -i '' -e 's/node:node:/node:/g' {} +", "eslint": "eslint ./lib/**/*", "format": "prettier --write './(lib|tests)/**/*'", @@ -23,12 +23,15 @@ "test:deno": "deno test tests/deno.ts" }, "files": [ + "cjs", "dist" ], "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js" + "import": "./dist/index.js", + "require": "./cjs/dist/index.js", + "default": "./dist/index.js" }, "./types": { "types": "./dist/types.d.ts", diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 0000000..2933d59 --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "outDir": "./cjs/dist", + "module": "commonjs", + "target": "ES2021" + } + } \ No newline at end of file