From cb65c4895db9110c54af306e370b6c00fafd3b76 Mon Sep 17 00:00:00 2001 From: Absy00 Date: Sat, 24 Jan 2026 00:20:40 +0100 Subject: [PATCH 1/6] fix: downgrade @types/node to v24 and lock in dependabot (issue #26) --- .github/dependabot.yml | 2 ++ CHANGELOG.md | 3 +-- package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5c8ba20..e6171cc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,8 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + ignore: + - dependency-name: "@types/node" - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/CHANGELOG.md b/CHANGELOG.md index c30eb4d..55695dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,8 @@ # [2.1.0](https://github.com/filipo11021/nodejs-password-hashing/compare/v2.0.0...v2.1.0) (2026-01-23) - ### Features -* add pepper support to argon2 hashing ([#34](https://github.com/filipo11021/nodejs-password-hashing/issues/34)) ([4d508df](https://github.com/filipo11021/nodejs-password-hashing/commit/4d508dfb97b24f82fb1932f7b0263be42ee357af)) +- add pepper support to argon2 hashing ([#34](https://github.com/filipo11021/nodejs-password-hashing/issues/34)) ([4d508df](https://github.com/filipo11021/nodejs-password-hashing/commit/4d508dfb97b24f82fb1932f7b0263be42ee357af)) # [2.0.0](https://github.com/filipo11021/nodejs-password-hashing/compare/v1.0.2...v2.0.0) (2026-01-21) diff --git a/package.json b/package.json index f1f8a4e..4e22a78 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "devDependencies": { "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "@types/node": "^25.0.10", + "@types/node": "~24.10.9", "@types/phc__format": "^1.0.1", "lefthook": "^2.0.15", "oxlint": "^1.41.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e83bfed..ff0d33d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,8 +25,8 @@ importers: specifier: ^10.0.1 version: 10.0.1(semantic-release@25.0.2(typescript@5.9.3)) '@types/node': - specifier: ^25.0.10 - version: 25.0.10 + specifier: ~24.10.9 + version: 24.10.9 '@types/phc__format': specifier: ^1.0.1 version: 1.0.1 @@ -264,8 +264,8 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} - '@types/node@25.0.10': - resolution: {integrity: sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==} + '@types/node@24.10.9': + resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1700,7 +1700,7 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@types/node@25.0.10': + '@types/node@24.10.9': dependencies: undici-types: 7.16.0 @@ -1708,7 +1708,7 @@ snapshots: '@types/phc__format@1.0.1': dependencies: - '@types/node': 25.0.10 + '@types/node': 24.10.9 agent-base@7.1.4: {} From dda8d1132be21c6d49c73450ff17a469f52cc478 Mon Sep 17 00:00:00 2001 From: Absy00 Date: Sat, 24 Jan 2026 00:24:24 +0100 Subject: [PATCH 2/6] chore: refine dependabot ignore rule for @types/node --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e6171cc..4b4abab 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,8 @@ updates: open-pull-requests-limit: 10 ignore: - dependency-name: "@types/node" + update-types: ["version-update"] + versions: [">= 25.0.0"] - package-ecosystem: "github-actions" directory: "/" schedule: From 91d9a531770b8d0ae146d4ca379e9061fd42ac4c Mon Sep 17 00:00:00 2001 From: Absy00 Date: Sat, 24 Jan 2026 00:27:45 +0100 Subject: [PATCH 3/6] fix: correct invalid update-types and format dependabot.yml --- .github/dependabot.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4b4abab..732c8a9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,7 +7,12 @@ updates: open-pull-requests-limit: 10 ignore: - dependency-name: "@types/node" - update-types: ["version-update"] + update-types: + [ + "version-update:semver-major", + "version-update:semver-minor", + "version-update:semver-patch", + ] versions: [">= 25.0.0"] - package-ecosystem: "github-actions" directory: "/" From be9f31afa6d9275a44fc1314b3110bda45a05280 Mon Sep 17 00:00:00 2001 From: Absy00 Date: Sat, 24 Jan 2026 01:55:46 +0100 Subject: [PATCH 4/6] fix: change Zod validation to exclusive min/max checks (#36) --- src/argon2/argon2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/argon2/argon2.ts b/src/argon2/argon2.ts index ace2336..08d96fc 100644 --- a/src/argon2/argon2.ts +++ b/src/argon2/argon2.ts @@ -11,19 +11,19 @@ import { MAX_UINT24, MAX_UINT32 } from "../utils/numbers.ts"; const optionsSchema = z .object({ - memory: z.number().max(MAX_UINT32), - passes: z.number().min(2).max(MAX_UINT32), - parallelism: z.number().min(1).max(MAX_UINT24), - tagLength: z.number().min(4).max(MAX_UINT32), + memory: z.number().lt(MAX_UINT32), + passes: z.number().gt(1).lt(MAX_UINT32), + parallelism: z.number().gt(1).lt(MAX_UINT24), + tagLength: z.number().gt(4).lt(MAX_UINT32), saltLength: z.number().min(16).max(1024), pepper: z.string().min(1).max(1024).optional(), }) .refine( (params) => { - return params.memory >= 8 * params.parallelism; + return params.memory > 8 * params.parallelism; }, { - message: "memory parameter must be at least 8 * parallelism", + message: "memory parameter must be greater than 8 * parallelism", }, ) .readonly(); From f3da0c5c08646a12b7c3899cfb9a631f56125bc9 Mon Sep 17 00:00:00 2001 From: Absy00 Date: Mon, 26 Jan 2026 01:38:57 +0100 Subject: [PATCH 5/6] fix: revert to inclusive bounds per RFC 9106 --- src/argon2/argon2.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/argon2/argon2.ts b/src/argon2/argon2.ts index 08d96fc..6dd495e 100644 --- a/src/argon2/argon2.ts +++ b/src/argon2/argon2.ts @@ -11,19 +11,20 @@ import { MAX_UINT24, MAX_UINT32 } from "../utils/numbers.ts"; const optionsSchema = z .object({ - memory: z.number().lt(MAX_UINT32), - passes: z.number().gt(1).lt(MAX_UINT32), - parallelism: z.number().gt(1).lt(MAX_UINT24), - tagLength: z.number().gt(4).lt(MAX_UINT32), + memory: z.number().max(MAX_UINT32), + passes: z.number().min(1).max(MAX_UINT32), + parallelism: z.number().min(1).max(MAX_UINT24), + tagLength: z.number().min(4).max(MAX_UINT32), saltLength: z.number().min(16).max(1024), pepper: z.string().min(1).max(1024).optional(), }) .refine( (params) => { - return params.memory > 8 * params.parallelism; + return params.memory >= 8 * params.parallelism; }, { - message: "memory parameter must be greater than 8 * parallelism", + message: + "memory parameter must be greater than or equal to 8 * parallelism", }, ) .readonly(); From 4026dcec6001d715814bc6c50e3e2e15cb84f024 Mon Sep 17 00:00:00 2001 From: Absy00 Date: Mon, 26 Jan 2026 04:28:10 +0100 Subject: [PATCH 6/6] test: add RFC 9106 compliant validation tests for Argon2 parameters --- src/argon2/argon2-validation.test.ts | 149 +++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/argon2/argon2-validation.test.ts diff --git a/src/argon2/argon2-validation.test.ts b/src/argon2/argon2-validation.test.ts new file mode 100644 index 0000000..f7ac380 --- /dev/null +++ b/src/argon2/argon2-validation.test.ts @@ -0,0 +1,149 @@ +import { createArgon2Hashing } from "./argon2.ts"; +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +void describe("Argon2 Parameter Validation - RFC 9106 Compliance", () => { + void describe("parallelism parameter", () => { + void it("should accept parallelism = 1 (minimum per RFC 9106)", () => { + assert.doesNotThrow(() => { + createArgon2Hashing({ + parallelism: 1, + memory: 8, + }); + }, "parallelism = 1 should be valid per RFC 9106"); + }); + + void it("should reject parallelism = 0 (below minimum)", () => { + assert.throws( + () => { + createArgon2Hashing({ + parallelism: 0, + memory: 8, + }); + }, + { + name: "ZodError", + }, + "parallelism must be at least 1", + ); + }); + }); + + void describe("tagLength parameter", () => { + void it("should accept tagLength = 4 (minimum per RFC 9106)", () => { + assert.doesNotThrow(() => { + createArgon2Hashing({ + tagLength: 4, + }); + }, "tagLength = 4 should be valid per RFC 9106"); + }); + + void it("should reject tagLength = 3 (below minimum)", () => { + assert.throws( + () => { + createArgon2Hashing({ + tagLength: 3, + }); + }, + { + name: "ZodError", + }, + "tagLength must be at least 4", + ); + }); + }); + + void describe("memory parameter relative to parallelism", () => { + void it("should accept memory = 8 * parallelism (minimum per RFC 9106)", () => { + assert.doesNotThrow(() => { + createArgon2Hashing({ + parallelism: 2, + memory: 16, // Exactly 8 * 2 + }); + }, "memory = 8 * parallelism should be valid per RFC 9106"); + }); + + void it("should reject memory < 8 * parallelism (below minimum)", () => { + assert.throws( + () => { + createArgon2Hashing({ + parallelism: 2, + memory: 15, // Less than 8 * 2 + }); + }, + { + name: "ZodError", + }, + "memory must be at least 8 * parallelism", + ); + }); + }); + + void describe("passes parameter", () => { + void it("should accept passes = 1 (minimum per RFC 9106)", () => { + assert.doesNotThrow(() => { + createArgon2Hashing({ + passes: 1, + }); + }, "passes = 1 should be valid per RFC 9106"); + }); + + void it("should reject passes = 0 (below minimum)", () => { + assert.throws( + () => { + createArgon2Hashing({ + passes: 0, + }); + }, + { + name: "ZodError", + }, + "passes must be at least 1", + ); + }); + }); + + void describe("edge cases - absolute minimums", () => { + void it("should accept absolute minimum configuration (parallelism=1, memory=8)", () => { + assert.doesNotThrow(() => { + createArgon2Hashing({ + parallelism: 1, + memory: 8, // Exactly 8 * 1 + passes: 1, + tagLength: 4, + }); + }, "absolute minimum configuration should be valid per RFC 9106"); + }); + + void it("should reject memory = 7 when parallelism = 1", () => { + assert.throws( + () => { + createArgon2Hashing({ + parallelism: 1, + memory: 7, + }); + }, + { + name: "ZodError", + }, + "memory = 7 should be rejected when parallelism = 1", + ); + }); + }); + + void describe("edge cases - invalid values", () => { + void it("should reject negative values", () => { + assert.throws( + () => { + createArgon2Hashing({ + passes: -1, + }); + }, + { + name: "ZodError", + }, + "passes must be positive", + ); + }); + }); +});