@exortek/apikey 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @exortek/apikey
2
2
 
3
+ ## 1.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - e53ae64: Fix polynomial-ReDoS (quadratic regex backtracking) surfaced by CodeQL, plus small code-quality fixes.
8
+ Bundled `@exortek/shared` utilities (base32, base64, duration) are inlined into the packages listed above, so each
9
+ ships the fix.
10
+
11
+ - Replace `/=+$/` trailing-padding strips (base32 / base64 decode, OTP provisioning URI) with linear scans —
12
+ `"=".repeat(n) + "x"` was O(n²).
13
+ - Rework the duration parser regex so surrounding whitespace can no longer cause O(n²) matching (trim first, single
14
+ interior `\s*`).
15
+ - Strip trailing spaces/dots in filename sanitisation with a linear scan — upload filenames are attacker-controlled.
16
+ - Cap email length before the regex in magic-link.
17
+ - Thread the JWT decode label into error messages (removes dead arguments and gives failures which segment broke).
18
+ - Drop a duplicate character in a UA browser-detection regex character class.
19
+
20
+ DoS-hardening and hygiene only — no API or behavioural change for valid input.
21
+
3
22
  ## 1.1.0
4
23
 
5
24
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -65,7 +65,11 @@ const UNIT_MS = Object.freeze({
65
65
  years: 31_536_000_000,
66
66
  });
67
67
 
68
- const DURATION_RE = /^\s*(-?\d+(?:\.\d+)?)\s*([a-z]+)?\s*$/i;
68
+ // Note: no leading/trailing `\s*` — the caller trims first. Two `\s*` runs
69
+ // around the optional unit (`\s*([a-z]+)?\s*`) made this O(n^2) on hostile
70
+ // input like `"1" + " ".repeat(n) + "!"`; trimming plus a single interior
71
+ // `\s*` keeps matching linear.
72
+ const DURATION_RE = /^(-?\d+(?:\.\d+)?)\s*([a-z]+)?$/i;
69
73
 
70
74
  const SUPPORTED_UNITS = 'ms, s, m, h, d, w, y (and long/plural forms)';
71
75
 
@@ -95,7 +99,7 @@ function parseDuration(input) {
95
99
  throw new TypeError(`parseDuration: expected string or number; got ${typeof input}`);
96
100
  }
97
101
 
98
- const match = DURATION_RE.exec(input);
102
+ const match = DURATION_RE.exec(input.trim());
99
103
  if (!match) {
100
104
  throw new Error(
101
105
  `parseDuration: could not parse ${JSON.stringify(input)}. Examples: 900 (ms), '15m', '2h', '7d', '500ms', '30s'.`,
package/dist/index.mjs CHANGED
@@ -63,7 +63,11 @@ const UNIT_MS = Object.freeze({
63
63
  years: 31_536_000_000,
64
64
  });
65
65
 
66
- const DURATION_RE = /^\s*(-?\d+(?:\.\d+)?)\s*([a-z]+)?\s*$/i;
66
+ // Note: no leading/trailing `\s*` — the caller trims first. Two `\s*` runs
67
+ // around the optional unit (`\s*([a-z]+)?\s*`) made this O(n^2) on hostile
68
+ // input like `"1" + " ".repeat(n) + "!"`; trimming plus a single interior
69
+ // `\s*` keeps matching linear.
70
+ const DURATION_RE = /^(-?\d+(?:\.\d+)?)\s*([a-z]+)?$/i;
67
71
 
68
72
  const SUPPORTED_UNITS = 'ms, s, m, h, d, w, y (and long/plural forms)';
69
73
 
@@ -93,7 +97,7 @@ function parseDuration(input) {
93
97
  throw new TypeError(`parseDuration: expected string or number; got ${typeof input}`);
94
98
  }
95
99
 
96
- const match = DURATION_RE.exec(input);
100
+ const match = DURATION_RE.exec(input.trim());
97
101
  if (!match) {
98
102
  throw new Error(
99
103
  `parseDuration: could not parse ${JSON.stringify(input)}. Examples: 900 (ms), '15m', '2h', '7d', '500ms', '30s'.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exortek/apikey",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Stripe-style prefixed API keys for Node.js — 3-segment tokens (prefix_id_secret), HMAC-SHA256 storage hash with pepper rotation, scope allowlists with wildcard match, opt-in lastUsedAt tracking, memory + Redis stores, Express + Fastify middleware. Server-only. Zero non-@exortek runtime dependencies.",
5
5
  "type": "module",
6
6
  "sideEffects": false,