mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 03:42:21 +03:00
fix(api): use shared SOCKS5 flag reader in settings routes (#13646)
Both settings routes use the shared `isSocks5ProxyEnabled()` reader instead of a copied check (identical logic, no behavior change).
Maintainer rework before merge (kept the idea, no default behavior change):
- The source-grep tests were replaced by behavioral tests of both routes across the flag on/off matrix (`GET /api/settings/proxies` reports `socks5Enabled`; `PUT /api/settings/proxy` accepts socks5 or returns 400).
Validated first on the combined board of all 38 PRs of this batch (10 merged as-is, 28 after the maintainer rework) on top of release/v3.8.51 c0f92ec: typecheck:core, check:open-sse-typecheck and check:dashboard-typecheck clean; ESLint clean on every changed file; file-size (rebaselined for the combined growth), complexity, cognitive-complexity, changelog-integrity, docs-counts, docs-sync, migration-numbering and i18n new-key gates green; 735 focused node:test cases with the only batch-caused failure (a flag-count assertion) fixed. Then re-validated alone on the fresh release tip right before this merge: ESLint on the changed files, typecheck:core, check:open-sse-typecheck, the file-size/complexity/changelog gates and this PR's own tests.
Thanks @maxmad64bis!
This commit is contained in:
1
changelog.d/fixes/13646-socks-flag-reader.md
Normal file
1
changelog.d/fixes/13646-socks-flag-reader.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(api):** share the single SOCKS5 flag reader across the settings proxy routes so the dashboard and the dispatcher stay consistent ([#13646](https://github.com/diegosouzapw/OmniRoute/pull/13646)) — thanks @maxmad64bis
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isSocks5ProxyEnabled } from "@omniroute/open-sse/utils/proxyDispatcher";
|
||||
import { listProxies } from "@/lib/db/proxies";
|
||||
import {
|
||||
handleProxyCreate,
|
||||
@@ -42,10 +43,8 @@ export async function GET(request: Request) {
|
||||
// #5890: coarse relay health pulse for the dashboard — how many relay
|
||||
// probes have run, and how many came back alive.
|
||||
relayProbeStats: getRelayProbeStats(),
|
||||
// Default ON (opt-out): only an explicit falsey value disables SOCKS5.
|
||||
socks5Enabled: !["false", "0", "no", "off"].includes(
|
||||
(process.env.ENABLE_SOCKS5_PROXY ?? "").trim().toLowerCase()
|
||||
),
|
||||
// SOCKS5 defaults ON — see isSocks5ProxyEnabled().
|
||||
socks5Enabled: isSocks5ProxyEnabled(),
|
||||
});
|
||||
} catch (error) {
|
||||
return createErrorResponseFromUnknown(error, "Failed to load proxies");
|
||||
|
||||
@@ -6,7 +6,10 @@ import {
|
||||
resolveProxyForConnection,
|
||||
} from "@/lib/db/settings";
|
||||
import { getProxyAssignments, getProxyById } from "@/lib/db/proxies";
|
||||
import { clearDispatcherCache } from "@omniroute/open-sse/utils/proxyDispatcher";
|
||||
import {
|
||||
clearDispatcherCache,
|
||||
isSocks5ProxyEnabled,
|
||||
} from "@omniroute/open-sse/utils/proxyDispatcher";
|
||||
import { updateProxyConfigSchema } from "@/shared/validation/schemas";
|
||||
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
||||
import {
|
||||
@@ -29,21 +32,15 @@ const PROXY_LEVEL_TO_REGISTRY_SCOPE = {
|
||||
key: "account",
|
||||
} as const;
|
||||
|
||||
function isSocks5Enabled() {
|
||||
// Default ON (opt-out): only an explicit falsey value disables SOCKS5.
|
||||
const raw = (process.env.ENABLE_SOCKS5_PROXY ?? "").trim().toLowerCase();
|
||||
return !["false", "0", "no", "off"].includes(raw);
|
||||
}
|
||||
|
||||
function getSupportedProxyTypes() {
|
||||
if (isSocks5Enabled()) {
|
||||
if (isSocks5ProxyEnabled()) {
|
||||
return new Set([...BASE_SUPPORTED_PROXY_TYPES, "socks5"]);
|
||||
}
|
||||
return BASE_SUPPORTED_PROXY_TYPES;
|
||||
}
|
||||
|
||||
function supportedTypesMessage() {
|
||||
return isSocks5Enabled() ? "http, https, or socks5" : "http or https";
|
||||
return isSocks5ProxyEnabled() ? "http, https, or socks5" : "http or https";
|
||||
}
|
||||
|
||||
function createInvalidProxyError(message: string): ApiRouteError {
|
||||
@@ -104,7 +101,7 @@ function normalizeAndValidateProxy(
|
||||
}
|
||||
|
||||
const type = String(proxy.type || "http").toLowerCase() as NonNullable<ProxyConfigInput["type"]>;
|
||||
if (type === "socks5" && !isSocks5Enabled()) {
|
||||
if (type === "socks5" && !isSocks5ProxyEnabled()) {
|
||||
throw createInvalidProxyError(
|
||||
"SOCKS5 proxy is disabled (remove ENABLE_SOCKS5_PROXY=false to enable — it is ON by default)"
|
||||
);
|
||||
|
||||
98
tests/unit/settings-socks-flag-reader.test.ts
Normal file
98
tests/unit/settings-socks-flag-reader.test.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-socks-flag-routes-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "test-secret";
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const { isSocks5ProxyEnabled } = await import("../../open-sse/utils/proxyDispatcher.ts");
|
||||
const proxiesRoute = await import("../../src/app/api/settings/proxies/route.ts");
|
||||
const proxyRoute = await import("../../src/app/api/settings/proxy/route.ts");
|
||||
|
||||
// ENABLE_SOCKS5_PROXY is opt-out: only an explicit falsey value disables SOCKS5.
|
||||
const MATRIX: Array<[string | undefined, boolean]> = [
|
||||
[undefined, true],
|
||||
["", true],
|
||||
["true", true],
|
||||
["1", true],
|
||||
["yes", true],
|
||||
["false", false],
|
||||
["0", false],
|
||||
["no", false],
|
||||
["off", false],
|
||||
[" OFF ", false],
|
||||
["False", false],
|
||||
];
|
||||
|
||||
async function withSocksFlag<T>(value: string | undefined, fn: () => Promise<T> | T): Promise<T> {
|
||||
const previous = process.env.ENABLE_SOCKS5_PROXY;
|
||||
if (value === undefined) delete process.env.ENABLE_SOCKS5_PROXY;
|
||||
else process.env.ENABLE_SOCKS5_PROXY = value;
|
||||
try {
|
||||
return await fn();
|
||||
} finally {
|
||||
if (previous === undefined) delete process.env.ENABLE_SOCKS5_PROXY;
|
||||
else process.env.ENABLE_SOCKS5_PROXY = previous;
|
||||
}
|
||||
}
|
||||
|
||||
function putProxy(body: unknown) {
|
||||
return proxyRoute.PUT(
|
||||
new Request("http://localhost/api/settings/proxy", {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
test.before(() => {
|
||||
delete process.env.INITIAL_PASSWORD;
|
||||
core.resetDbInstance();
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
||||
});
|
||||
|
||||
test("flag reader honors the opt-out matrix (unset defaults ON)", async () => {
|
||||
for (const [value, expected] of MATRIX) {
|
||||
await withSocksFlag(value, () => {
|
||||
assert.equal(isSocks5ProxyEnabled(), expected, `ENABLE_SOCKS5_PROXY=${String(value)}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test("GET /api/settings/proxies reports socks5Enabled exactly as the flag reader", async () => {
|
||||
for (const [value, expected] of MATRIX) {
|
||||
await withSocksFlag(value, async () => {
|
||||
const response = await proxiesRoute.GET(new Request("http://localhost/api/settings/proxies"));
|
||||
assert.equal(response.status, 200);
|
||||
const body = (await response.json()) as { socks5Enabled: boolean };
|
||||
assert.equal(body.socks5Enabled, expected, `ENABLE_SOCKS5_PROXY=${String(value)}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test("PUT /api/settings/proxy accepts or rejects socks5 following the flag", async () => {
|
||||
for (const [value, expected] of MATRIX) {
|
||||
await withSocksFlag(value, async () => {
|
||||
const response = await putProxy({
|
||||
level: "global",
|
||||
proxy: { type: "socks5", host: "127.0.0.1", port: 1080 },
|
||||
});
|
||||
const body = (await response.json()) as { error?: { message?: string } };
|
||||
if (expected) {
|
||||
assert.equal(response.status, 200, `ENABLE_SOCKS5_PROXY=${String(value)}`);
|
||||
} else {
|
||||
assert.equal(response.status, 400, `ENABLE_SOCKS5_PROXY=${String(value)}`);
|
||||
assert.match(body.error?.message ?? "", /SOCKS5 proxy is disabled/);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user