client-certificate-auth 1.3.0 → 1.3.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.
Files changed (2) hide show
  1. package/lib/helpers.js +18 -7
  2. package/package.json +1 -1
package/lib/helpers.js CHANGED
@@ -9,6 +9,17 @@
9
9
  * @typedef {(cert: PeerCertificate, req?: import('http').IncomingMessage) => boolean | Promise<boolean>} ValidationCallback
10
10
  */
11
11
 
12
+ /**
13
+ * Normalize a certificate DN field value to an array.
14
+ * Node.js returns string for single-valued and string[] for multi-valued DN attributes.
15
+ * @param {string | string[] | undefined} value
16
+ * @returns {string[]}
17
+ */
18
+ function toArray(value) {
19
+ if (value === undefined || value === null) {return [];}
20
+ return Array.isArray(value) ? value : [value];
21
+ }
22
+
12
23
  /**
13
24
  * Create a validation callback that allows certificates with matching Common Names.
14
25
  *
@@ -20,7 +31,7 @@
20
31
  */
21
32
  export function allowCN(names) {
22
33
  const allowed = new Set(names);
23
- return (cert) => allowed.has(cert.subject?.CN);
34
+ return (cert) => toArray(cert.subject?.CN).some((cn) => allowed.has(cn));
24
35
  }
25
36
 
26
37
  /**
@@ -76,7 +87,7 @@ export function allowIssuer(match) {
76
87
  const entries = Object.entries(match);
77
88
  return (cert) => {
78
89
  if (!cert.issuer) {return false;}
79
- return entries.every(([key, value]) => cert.issuer[key] === value);
90
+ return entries.every(([key, value]) => toArray(cert.issuer[key]).includes(value));
80
91
  };
81
92
  }
82
93
 
@@ -94,7 +105,7 @@ export function allowSubject(match) {
94
105
  const entries = Object.entries(match);
95
106
  return (cert) => {
96
107
  if (!cert.subject) {return false;}
97
- return entries.every(([key, value]) => cert.subject[key] === value);
108
+ return entries.every(([key, value]) => toArray(cert.subject[key]).includes(value));
98
109
  };
99
110
  }
100
111
 
@@ -109,7 +120,7 @@ export function allowSubject(match) {
109
120
  */
110
121
  export function allowOU(ous) {
111
122
  const allowed = new Set(ous);
112
- return (cert) => allowed.has(cert.subject?.OU);
123
+ return (cert) => toArray(cert.subject?.OU).some((ou) => allowed.has(ou));
113
124
  }
114
125
 
115
126
  /**
@@ -123,7 +134,7 @@ export function allowOU(ous) {
123
134
  */
124
135
  export function allowOrganization(orgs) {
125
136
  const allowed = new Set(orgs);
126
- return (cert) => allowed.has(cert.subject?.O);
137
+ return (cert) => toArray(cert.subject?.O).some((o) => allowed.has(o));
127
138
  }
128
139
 
129
140
  /**
@@ -196,9 +207,9 @@ export function allowEmail(emails) {
196
207
  const allowed = new Set(emails.map((e) => e.toLowerCase()));
197
208
 
198
209
  return (cert) => {
199
- // Check subject.emailAddress
210
+ // Check subject.emailAddress (may be string or string[] for multi-valued)
200
211
  if (cert.subject?.emailAddress) {
201
- if (allowed.has(cert.subject.emailAddress.toLowerCase())) {
212
+ if (toArray(cert.subject.emailAddress).some((e) => allowed.has(e.toLowerCase()))) {
202
213
  return true;
203
214
  }
204
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "client-certificate-auth",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Express/Connect middleware for mTLS client certificate authentication with reverse proxy support (AWS ALB, Envoy, Cloudflare, Traefik)",
5
5
  "homepage": "https://github.com/tgies/client-certificate-auth",
6
6
  "bugs": {