Spaces:
Running
Running
Merge pull request #115 from anurag008w/codex/fix-bugs-in-start.sh,-health-server.js,-env-builder.js,-env-y8p5pn
Browse files- health-server.js +13 -7
- multi-provider-key-rotator.cjs +7 -0
- start.sh +1 -11
health-server.js
CHANGED
|
@@ -22,12 +22,13 @@ const JUPYTER_HOST = "127.0.0.1";
|
|
| 22 |
const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
|
| 23 |
const GATEWAY_TOKEN = (process.env.GATEWAY_TOKEN || "").trim();
|
| 24 |
const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
|
| 25 |
-
//
|
|
|
|
| 26 |
// HUGGINGCLAW_JUPYTER_ENABLED=true is the explicit user override and always wins.
|
| 27 |
const JUPYTER_ENABLED =
|
| 28 |
/^(true|1|yes|on)$/i.test(String(process.env.HUGGINGCLAW_JUPYTER_ENABLED || "").trim()) ||
|
| 29 |
(
|
| 30 |
-
|
| 31 |
!/^(false|0|no|off)$/i.test(String(process.env.HUGGINGCLAW_JUPYTER_ENABLED || "").trim())
|
| 32 |
);
|
| 33 |
const startTime = Date.now();
|
|
@@ -252,9 +253,14 @@ function parseCookies(req) {
|
|
| 252 |
|
| 253 |
// Constant-time comparison β prevent timing attacks on token check
|
| 254 |
function safeEqual(a, b) {
|
| 255 |
-
if (typeof a !== "string" || typeof b !== "string"
|
| 256 |
-
|
| 257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
return d === 0;
|
| 259 |
}
|
| 260 |
|
|
@@ -668,7 +674,7 @@ const server = http.createServer(async (req, res) => {
|
|
| 668 |
const body = await readBody(req);
|
| 669 |
const token = decodeURIComponent((body.match(/(?:^|&)token=([^&]*)/) || [])[1] || "").replace(/\+/g, " ");
|
| 670 |
if (safeEqual(token, GATEWAY_TOKEN)) {
|
| 671 |
-
const cookie = `hc_env_auth=${encodeURIComponent(GATEWAY_TOKEN)}; Path=/; HttpOnly; SameSite=
|
| 672 |
res.writeHead(302, { Location: "/env-builder", "Set-Cookie": cookie, "Cache-Control": "no-store" });
|
| 673 |
return res.end();
|
| 674 |
}
|
|
@@ -680,7 +686,7 @@ const server = http.createServer(async (req, res) => {
|
|
| 680 |
}
|
| 681 |
|
| 682 |
if (pathname === "/env-builder/logout") {
|
| 683 |
-
res.writeHead(302, { Location: "/env-builder", "Set-Cookie": "hc_env_auth=; Path=/; HttpOnly; Max-Age=0", "Cache-Control": "no-store" });
|
| 684 |
return res.end();
|
| 685 |
}
|
| 686 |
|
|
|
|
| 22 |
const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
|
| 23 |
const GATEWAY_TOKEN = (process.env.GATEWAY_TOKEN || "").trim();
|
| 24 |
const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
|
| 25 |
+
// Explicit HUGGINGCLAW_JUPYTER_ENABLED=true enables Jupyter.
|
| 26 |
+
// Otherwise DEV_MODE=true enables it unless HUGGINGCLAW_JUPYTER_ENABLED is explicitly false.
|
| 27 |
// HUGGINGCLAW_JUPYTER_ENABLED=true is the explicit user override and always wins.
|
| 28 |
const JUPYTER_ENABLED =
|
| 29 |
/^(true|1|yes|on)$/i.test(String(process.env.HUGGINGCLAW_JUPYTER_ENABLED || "").trim()) ||
|
| 30 |
(
|
| 31 |
+
isTrue(process.env.DEV_MODE) &&
|
| 32 |
!/^(false|0|no|off)$/i.test(String(process.env.HUGGINGCLAW_JUPYTER_ENABLED || "").trim())
|
| 33 |
);
|
| 34 |
const startTime = Date.now();
|
|
|
|
| 253 |
|
| 254 |
// Constant-time comparison β prevent timing attacks on token check
|
| 255 |
function safeEqual(a, b) {
|
| 256 |
+
if (typeof a !== "string" || typeof b !== "string") return false;
|
| 257 |
+
// Pad both to the same length so the loop always takes constant time,
|
| 258 |
+
// preventing token length from being leaked via early-return timing.
|
| 259 |
+
const len = Math.max(a.length, b.length, 1);
|
| 260 |
+
const pa = a.padEnd(len, "\0");
|
| 261 |
+
const pb = b.padEnd(len, "\0");
|
| 262 |
+
let d = a.length === b.length ? 0 : 1; // length mismatch β always fail
|
| 263 |
+
for (let i = 0; i < len; i++) d |= pa.charCodeAt(i) ^ pb.charCodeAt(i);
|
| 264 |
return d === 0;
|
| 265 |
}
|
| 266 |
|
|
|
|
| 674 |
const body = await readBody(req);
|
| 675 |
const token = decodeURIComponent((body.match(/(?:^|&)token=([^&]*)/) || [])[1] || "").replace(/\+/g, " ");
|
| 676 |
if (safeEqual(token, GATEWAY_TOKEN)) {
|
| 677 |
+
const cookie = `hc_env_auth=${encodeURIComponent(GATEWAY_TOKEN)}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=86400`;
|
| 678 |
res.writeHead(302, { Location: "/env-builder", "Set-Cookie": cookie, "Cache-Control": "no-store" });
|
| 679 |
return res.end();
|
| 680 |
}
|
|
|
|
| 686 |
}
|
| 687 |
|
| 688 |
if (pathname === "/env-builder/logout") {
|
| 689 |
+
res.writeHead(302, { Location: "/env-builder", "Set-Cookie": "hc_env_auth=; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=0", "Cache-Control": "no-store" });
|
| 690 |
return res.end();
|
| 691 |
}
|
| 692 |
|
multi-provider-key-rotator.cjs
CHANGED
|
@@ -86,6 +86,13 @@ const PROVIDERS = [
|
|
| 86 |
envPlural: 'ZAI_API_KEYS',
|
| 87 |
envSingular:'ZAI_API_KEY',
|
| 88 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
{
|
| 90 |
name: 'moonshot',
|
| 91 |
hostname: /(?:^|\.)api\.moonshot\.cn$/i,
|
|
|
|
| 86 |
envPlural: 'ZAI_API_KEYS',
|
| 87 |
envSingular:'ZAI_API_KEY',
|
| 88 |
},
|
| 89 |
+
{
|
| 90 |
+
name: 'kimi-coding',
|
| 91 |
+
// kimi-coding routes through api.moonshot.cn; dedicated entry so KIMI_API_KEYS pool is used
|
| 92 |
+
hostname: /(?:^|\.)api\.moonshot\.cn$/i,
|
| 93 |
+
envPlural: 'KIMI_API_KEYS',
|
| 94 |
+
envSingular:'KIMI_API_KEY',
|
| 95 |
+
},
|
| 96 |
{
|
| 97 |
name: 'moonshot',
|
| 98 |
hostname: /(?:^|\.)api\.moonshot\.cn$/i,
|
start.sh
CHANGED
|
@@ -203,7 +203,7 @@ case "$LLM_PROVIDER" in
|
|
| 203 |
byteplus|byteplus-plan) export BYTEPLUS_API_KEY="$LLM_API_KEY" ;;
|
| 204 |
qianfan) export QIANFAN_API_KEY="$LLM_API_KEY" ;;
|
| 205 |
# ββ Western Providers ββ
|
| 206 |
-
mistral
|
| 207 |
xai|x-ai) export XAI_API_KEY="$LLM_API_KEY" ;;
|
| 208 |
nvidia) export NVIDIA_API_KEY="$LLM_API_KEY" ;;
|
| 209 |
cohere) export COHERE_API_KEY="$LLM_API_KEY" ;;
|
|
@@ -1772,16 +1772,6 @@ while true; do
|
|
| 1772 |
# 11. Start WhatsApp Guardian after the gateway is accepting connections
|
| 1773 |
start_guardian_once
|
| 1774 |
|
| 1775 |
-
# ββ Silence D-Bus errors for headless Chromium ββ
|
| 1776 |
-
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
| 1777 |
-
if command -v dbus-launch >/dev/null 2>&1; then
|
| 1778 |
-
eval "$(dbus-launch --sh-syntax 2>/dev/null)" || true
|
| 1779 |
-
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-disabled:}"
|
| 1780 |
-
else
|
| 1781 |
-
export DBUS_SESSION_BUS_ADDRESS="disabled:"
|
| 1782 |
-
fi
|
| 1783 |
-
fi
|
| 1784 |
-
|
| 1785 |
# 11.5 Warm up the managed browser so first browser actions have a live tab
|
| 1786 |
warmup_browser
|
| 1787 |
|
|
|
|
| 203 |
byteplus|byteplus-plan) export BYTEPLUS_API_KEY="$LLM_API_KEY" ;;
|
| 204 |
qianfan) export QIANFAN_API_KEY="$LLM_API_KEY" ;;
|
| 205 |
# ββ Western Providers ββ
|
| 206 |
+
mistral) export MISTRAL_API_KEY="$LLM_API_KEY" ;;
|
| 207 |
xai|x-ai) export XAI_API_KEY="$LLM_API_KEY" ;;
|
| 208 |
nvidia) export NVIDIA_API_KEY="$LLM_API_KEY" ;;
|
| 209 |
cohere) export COHERE_API_KEY="$LLM_API_KEY" ;;
|
|
|
|
| 1772 |
# 11. Start WhatsApp Guardian after the gateway is accepting connections
|
| 1773 |
start_guardian_once
|
| 1774 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1775 |
# 11.5 Warm up the managed browser so first browser actions have a live tab
|
| 1776 |
warmup_browser
|
| 1777 |
|