zengate 1.0.0 → 1.0.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/package.json +1 -1
- package/src/server/middleware.js +21 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zengate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Keyless OpenAI-compatible API (Chat Completions + Responses) for OpenCode's free Zen models, served through the real OpenCode CLI.",
|
|
5
5
|
"homepage": "https://github.com/developingchet/zengate#readme",
|
|
6
6
|
"repository": {
|
package/src/server/middleware.js
CHANGED
|
@@ -3,17 +3,25 @@ import { ApiError, sendError } from './errors.js';
|
|
|
3
3
|
|
|
4
4
|
const PUBLIC_PATHS = new Set(['/health', '/ready']);
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const BEARER = 'bearer';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Constant-time comparison of the key bytes. Only the length can differ in
|
|
10
|
+
* timing, and key lengths are not secret (generated keys have a fixed format).
|
|
11
|
+
*/
|
|
12
|
+
function safeEqual(presented, expected) {
|
|
13
|
+
const a = Buffer.from(presented);
|
|
14
|
+
const b = Buffer.from(expected);
|
|
15
|
+
return a.length === b.length && crypto.timingSafeEqual(a, b);
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
/** The key from `Authorization: Bearer <key>`, parsed without a backtracking regex. */
|
|
13
19
|
function presentedKey(req) {
|
|
14
|
-
const header = req.headers.authorization
|
|
15
|
-
const
|
|
16
|
-
|
|
20
|
+
const header = typeof req.headers.authorization === 'string' ? req.headers.authorization.trim() : '';
|
|
21
|
+
const scheme = header.slice(0, BEARER.length);
|
|
22
|
+
const separator = header.charAt(BEARER.length);
|
|
23
|
+
if (scheme.toLowerCase() !== BEARER || !/\s/.test(separator)) return '';
|
|
24
|
+
return header.slice(BEARER.length + 1).trim();
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
/**
|
|
@@ -25,9 +33,11 @@ export function authMiddleware({ apiKeys, allowNoAuth, onFailure }) {
|
|
|
25
33
|
req.clientId = 'anonymous';
|
|
26
34
|
if (allowNoAuth || PUBLIC_PATHS.has(req.path) || req.method === 'OPTIONS') return next();
|
|
27
35
|
const key = presentedKey(req);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
const index = key ? apiKeys.findIndex((candidate) => safeEqual(key, candidate)) : -1;
|
|
37
|
+
if (index !== -1) {
|
|
38
|
+
// Names the matched key without deriving anything from it; scopes
|
|
39
|
+
// stored responses to the key that made them.
|
|
40
|
+
req.clientId = `key_${index}`;
|
|
31
41
|
return next();
|
|
32
42
|
}
|
|
33
43
|
onFailure?.();
|