This commit is contained in:
Cheney 2026-08-16 22:21:41 +08:00
parent 9ad61eef3b
commit 789ff22263
2 changed files with 5 additions and 58 deletions

View File

@ -23,11 +23,6 @@ function loadEnv() {
const ENV = loadEnv();
// 运行时可变配置(可通过 /api/settings 修改并持久化)
function parseList(v: string | undefined): string[] {
return (v || "").split(",").map((s) => s.trim()).filter(Boolean);
}
const DEFAULT_WHITELIST = ["d:\\"];
const config = {
BASE_URL: process.env.BASE_URL || ENV.BASE_URL || "https://ark.cn-beijing.volces.com/api/coding/v3",
API_KEY: process.env.API_KEY || ENV.API_KEY || "",
@ -37,14 +32,12 @@ const config = {
PORT: parseInt(process.env.PORT || ENV.PORT || "3000", 10),
LOG_LEVEL: (process.env.LOG_LEVEL || ENV.LOG_LEVEL || "debug").toLowerCase(),
TEMPERATURE: parseFloat(process.env.TEMPERATURE || ENV.TEMPERATURE || "0.3"),
WHITELIST: parseList(process.env.WHITELIST || ENV.WHITELIST).length ? parseList(process.env.WHITELIST || ENV.WHITELIST) : DEFAULT_WHITELIST,
BLACKLIST: parseList(process.env.BLACKLIST || ENV.BLACKLIST),
DUCKDB_EXE: process.env.DUCKDB_EXE || ENV.DUCKDB_EXE || resolve("bin", "duckdb.exe"),
DUCKDB_FILE: process.env.DUCKDB_FILE || ENV.DUCKDB_FILE || resolve("data", "duck.db"),
};
// 持久化配置到 .envWORKSPACE 为内部默认值,不在设置页暴露)
const ENV_KEYS = ["BASE_URL", "API_KEY", "MODEL", "WORKSPACE", "CMD_APPROVE_LEVEL", "PORT", "LOG_LEVEL", "TEMPERATURE", "WHITELIST", "BLACKLIST", "DUCKDB_EXE", "DUCKDB_FILE"] as const;
const ENV_KEYS = ["BASE_URL", "API_KEY", "MODEL", "WORKSPACE", "CMD_APPROVE_LEVEL", "PORT", "LOG_LEVEL", "TEMPERATURE", "DUCKDB_EXE", "DUCKDB_FILE"] as const;
function saveEnv() {
const lines = ENV_KEYS.map((k) => `${k}=${String((config as any)[k])}`);
const header = "# Mini AI Assistant 配置(可由设置页面修改)\n";
@ -95,26 +88,9 @@ import { resolve, normalize, extname, sep, dirname } from "path";
import { read as xlsxRead, write as xlsxWrite, utils } from "xlsx";
import { spawn } from "child_process";
// ---------- 路径安全(白名单 + 黑名单,黑名单优先) ----------
// 判断 target 是否等于 base 或位于 base 的子目录下(跨平台)
function isWithin(base: string, target: string): boolean {
const b = normalize(base).replace(/\\/g, "/").replace(/\/+$/, "");
const t = normalize(target).replace(/\\/g, "/").replace(/\/+$/, "");
return t === b || t.startsWith(b + "/");
}
// 白名单:允许访问的根目录(默认包含 D 盘根目录);工作区始终隐式允许
// 黑名单:禁止访问(优先于白名单);命中黑名单或其子目录则拒绝
function isAllowedPath(p: string): boolean {
const abs = resolve(config.WORKSPACE, normalize(p));
for (const b of config.BLACKLIST) {
if (isWithin(b, abs)) return false;
}
const allowed = [...config.WHITELIST, config.WORKSPACE];
for (const w of allowed) {
if (isWithin(w, abs)) return true;
}
return false;
// ---------- 路径访问(已移除目录权限限制,全部放行) ----------
function isAllowedPath(_p: string): boolean {
return true;
}
// ---------- 危险命令检测 ----------
@ -646,8 +622,6 @@ const server = createServer(async (req, res) => {
CMD_APPROVE_LEVEL: config.CMD_APPROVE_LEVEL,
LOG_LEVEL: config.LOG_LEVEL,
TEMPERATURE: config.TEMPERATURE,
WHITELIST: config.WHITELIST,
BLACKLIST: config.BLACKLIST,
}));
return;
}
@ -666,16 +640,8 @@ const server = createServer(async (req, res) => {
}
if (typeof payload.LOG_LEVEL === "string") config.LOG_LEVEL = payload.LOG_LEVEL.toLowerCase();
if (typeof payload.TEMPERATURE === "number") config.TEMPERATURE = payload.TEMPERATURE;
if (payload.WHITELIST !== undefined) {
const wl = Array.isArray(payload.WHITELIST) ? payload.WHITELIST : String(payload.WHITELIST).split(",");
config.WHITELIST = wl.map((s: string) => String(s).trim()).filter(Boolean);
}
if (payload.BLACKLIST !== undefined) {
const bl = Array.isArray(payload.BLACKLIST) ? payload.BLACKLIST : String(payload.BLACKLIST).split(",");
config.BLACKLIST = bl.map((s: string) => String(s).trim()).filter(Boolean);
}
saveEnv();
log("info", "settings_updated", { CMD_APPROVE_LEVEL: config.CMD_APPROVE_LEVEL, MODEL: config.MODEL, LOG_LEVEL: config.LOG_LEVEL, WHITELIST: config.WHITELIST, BLACKLIST: config.BLACKLIST });
log("info", "settings_updated", { CMD_APPROVE_LEVEL: config.CMD_APPROVE_LEVEL, MODEL: config.MODEL, LOG_LEVEL: config.LOG_LEVEL });
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true }));
return;

View File

@ -63,19 +63,6 @@
</label>
<p class="hint">控制执行 Shell 命令时是否需要你审批</p>
</section>
<section>
<h4>路径权限可配置多个</h4>
<label class="row">
<span>白名单</span>
<input v-model="form.WHITELIST" placeholder="多个目录用逗号分隔,如 d:\ , c:\tmp" />
</label>
<label class="row">
<span>黑名单</span>
<input v-model="form.BLACKLIST" placeholder="多个目录用逗号分隔,优先于白名单" />
</label>
<p class="hint">白名单内的目录及其子目录允许访问黑名单优先命中即拒绝默认白名单含 <code>d:\</code></p>
</section>
</div>
<div class="footer">
@ -99,8 +86,6 @@ const form = reactive({
CMD_APPROVE_LEVEL: "medium",
LOG_LEVEL: "debug",
TEMPERATURE: 0.3,
WHITELIST: "",
BLACKLIST: "",
});
const saving = ref(false);
const msg = ref("");
@ -141,8 +126,6 @@ onMounted(async () => {
form.CMD_APPROVE_LEVEL = d.CMD_APPROVE_LEVEL || "medium";
form.LOG_LEVEL = d.LOG_LEVEL || "debug";
form.TEMPERATURE = typeof d.TEMPERATURE === "number" ? d.TEMPERATURE : 0.3;
form.WHITELIST = Array.isArray(d.WHITELIST) ? d.WHITELIST.join(", ") : (d.WHITELIST || "d:\\");
form.BLACKLIST = Array.isArray(d.BLACKLIST) ? d.BLACKLIST.join(", ") : (d.BLACKLIST || "");
// API_KEY
} catch {
msg.value = "加载设置失败";
@ -164,8 +147,6 @@ async function save() {
CMD_APPROVE_LEVEL: form.CMD_APPROVE_LEVEL,
LOG_LEVEL: form.LOG_LEVEL,
TEMPERATURE: form.TEMPERATURE,
WHITELIST: form.WHITELIST,
BLACKLIST: form.BLACKLIST,
}),
});
const d = await r.json();