kxco-post-quantum 1.7.8 → 1.7.9

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.9
4
+
5
+ verifyDelivery reads each header only as a string. A header that arrives as an
6
+ array, as some frameworks deliver a repeated header, counts as missing, so the
7
+ result reports the failed check where an array signature header used to throw.
8
+
3
9
  ## 1.7.8
4
10
 
5
11
  verifyDelivery accepts an X-KXCO-Timestamp header only as decimal digits.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxco-post-quantum",
3
- "version": "1.7.8",
3
+ "version": "1.7.9",
4
4
  "description": "NIST post-quantum cryptography for Node.js and browsers: ML-DSA, ML-KEM and SLH-DSA (FIPS 203, 204, 205). 1,793 NIST ACVP vectors passed, 0 failed. OpenSSL 3.5 native on Node 24+, the CNSA 2.0 parameter sets, reproducible builds with provenance.",
5
5
  "keywords": [
6
6
  "post-quantum",
package/src/webhook.d.ts CHANGED
@@ -89,8 +89,11 @@ export interface SignDeliveryHeaders {
89
89
  export function signDelivery(args: SignDeliveryArgs): SignDeliveryHeaders
90
90
 
91
91
  export interface VerifyDeliveryArgs {
92
- /** HTTP headers with LOWERCASE keys */
93
- headers: Record<string, string | undefined>
92
+ /**
93
+ * HTTP headers with LOWERCASE keys. Each KXCO header is read only as a
94
+ * string; a header that arrives as an array counts as missing.
95
+ */
96
+ headers: Record<string, string | string[] | undefined>
94
97
  /** The EXACT request body bytes as received */
95
98
  rawBody: string | Buffer
96
99
  /** Optional: enable HMAC verification by providing the shared secret */
package/src/webhook.js CHANGED
@@ -41,6 +41,9 @@ function constTimeEqualStrings(a, b) {
41
41
  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i)
42
42
  return diff === 0
43
43
  }
44
+ function headerString(value) {
45
+ return typeof value === 'string' ? value : undefined
46
+ }
44
47
 
45
48
  /**
46
49
  * Build the canonical signed envelope: timestamp + "." + raw body string.
@@ -113,10 +116,13 @@ export function signDelivery({ rawBody, hmacSecret, pqSecretKey, pqKid, event, d
113
116
  * Verify a webhook delivery on the receiving side.
114
117
  */
115
118
  export function verifyDelivery({ headers, rawBody, hmacSecret, pqPublicKey, pinnedKid, windowSeconds = 300 }) {
116
- const ts = headers['x-kxco-timestamp']
117
- const sigHmac = headers['x-kxco-signature']
118
- const sigPq = headers['x-kxco-pq-signature']
119
- const kid = headers['x-kxco-pq-kid']
119
+ // Each header is read only as a string. Some frameworks hand a repeated
120
+ // header over as an array; that counts as missing rather than being coerced,
121
+ // so a header of any other type fails its check instead of throwing.
122
+ const ts = headerString(headers['x-kxco-timestamp'])
123
+ const sigHmac = headerString(headers['x-kxco-signature'])
124
+ const sigPq = headerString(headers['x-kxco-pq-signature'])
125
+ const kid = headerString(headers['x-kxco-pq-kid'])
120
126
 
121
127
  // Both signatures cover the header exactly as it arrives, so it is read
122
128
  // only as the decimal digits it is specified to be. parseInt alone would