auto-save 2026-05-11 17:44 (~3)
This commit is contained in:
@@ -1,12 +1,5 @@
|
|||||||
{
|
{
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
|
||||||
"files_changed": 1,
|
|
||||||
"hash": "6f92814",
|
|
||||||
"message": "auto-save 2026-05-10 08:56 (~1)",
|
|
||||||
"ts": "2026-05-10T08:56:46+08:00",
|
|
||||||
"type": "commit"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"files_changed": 1,
|
"files_changed": 1,
|
||||||
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-10 08:56 (~1)",
|
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-10 08:56 (~1)",
|
||||||
@@ -3265,6 +3258,13 @@
|
|||||||
"type": "session-heartbeat",
|
"type": "session-heartbeat",
|
||||||
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 3 项未提交变更 · 最近提交:auto-save 2026-05-11 17:33 (~1)",
|
"message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 3 项未提交变更 · 最近提交:auto-save 2026-05-11 17:33 (~1)",
|
||||||
"files_changed": 3
|
"files_changed": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-11T17:39:04+08:00",
|
||||||
|
"type": "commit",
|
||||||
|
"message": "auto-save 2026-05-11 17:39 (~4)",
|
||||||
|
"hash": "0ec86e8",
|
||||||
|
"files_changed": 4
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1114,16 +1114,28 @@ def handle_ui_config_post(headers: dict[str, str], body: dict[str, Any]) -> tupl
|
|||||||
return 200, {"code": 0, "msg": "ok", "config": config}
|
return 200, {"code": 0, "msg": "ok", "config": config}
|
||||||
|
|
||||||
|
|
||||||
|
def admin_allowed_origins(headers: dict[str, str]) -> set[str]:
|
||||||
|
origins = _csv_set(_env("HERMES_ADMIN_ORIGINS", "https://hermes.kang-kang.com"))
|
||||||
|
host = (headers.get("x-forwarded-host") or headers.get("host") or "").split(",", 1)[0].strip()
|
||||||
|
proto = (headers.get("x-forwarded-proto") or "").split(",", 1)[0].strip()
|
||||||
|
if host:
|
||||||
|
origins.add(f"{proto or 'https'}://{host}")
|
||||||
|
origins.add(f"http://{host}")
|
||||||
|
return origins
|
||||||
|
|
||||||
|
|
||||||
def is_admin_request(headers: dict[str, str]) -> tuple[bool, int, str]:
|
def is_admin_request(headers: dict[str, str]) -> tuple[bool, int, str]:
|
||||||
cookie = headers.get("cookie", "")
|
cookie = headers.get("cookie", "")
|
||||||
if "hermes_auth=ok" not in cookie:
|
if "hermes_auth=ok" not in cookie:
|
||||||
return False, 401, "login required"
|
return False, 401, "login required"
|
||||||
origin = headers.get("origin", "")
|
origin = headers.get("origin", "")
|
||||||
referer = headers.get("referer", "")
|
referer = headers.get("referer", "")
|
||||||
allowed = "https://hermes.kang-kang.com"
|
allowed = admin_allowed_origins(headers)
|
||||||
if origin and origin != allowed:
|
if origin and origin not in allowed:
|
||||||
return False, 403, "invalid origin"
|
return False, 403, "invalid origin"
|
||||||
if not origin and referer and not referer.startswith(allowed + "/"):
|
if not origin and referer and not any(
|
||||||
|
referer.startswith(item.rstrip("/") + "/") for item in allowed
|
||||||
|
):
|
||||||
return False, 403, "invalid referer"
|
return False, 403, "invalid referer"
|
||||||
return True, 200, "ok"
|
return True, 200, "ok"
|
||||||
|
|
||||||
|
|||||||
17
src/app.js
17
src/app.js
@@ -678,7 +678,10 @@ async function refreshFeishuApps() {
|
|||||||
_feishuAppsLoading = true;
|
_feishuAppsLoading = true;
|
||||||
box.innerHTML = '<div class="settings-help">正在读取飞书桥接服务...</div>';
|
box.innerHTML = '<div class="settings-help">正在读取飞书桥接服务...</div>';
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/feishu/apps", { cache: "no-store" });
|
const res = await apiFetch("/feishu/apps", {
|
||||||
|
credentials: "same-origin",
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const apps = Array.isArray(data.apps) ? data.apps : [];
|
const apps = Array.isArray(data.apps) ? data.apps : [];
|
||||||
@@ -732,7 +735,7 @@ async function deleteFeishuApp(encodedAppId) {
|
|||||||
const ok = confirm(`删除飞书机器人 ${appId}?\n\n删除后这个 App ID 的回调地址会立刻失效,Secret / Token 也会从服务器环境文件移除。`);
|
const ok = confirm(`删除飞书机器人 ${appId}?\n\n删除后这个 App ID 的回调地址会立刻失效,Secret / Token 也会从服务器环境文件移除。`);
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/feishu/apps/" + encodeURIComponent(appId), {
|
const res = await apiFetch("/feishu/apps/" + encodeURIComponent(appId), {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
});
|
});
|
||||||
@@ -768,7 +771,7 @@ async function saveFeishuApp(event) {
|
|||||||
submit.textContent = "正在保存...";
|
submit.textContent = "正在保存...";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/feishu/apps", {
|
const res = await apiFetch("/feishu/apps", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -899,7 +902,7 @@ async function refreshHermesConfig(force = false) {
|
|||||||
_hermesConfigLoading = true;
|
_hermesConfigLoading = true;
|
||||||
setHermesConfigStatuses("正在读取线上配置...");
|
setHermesConfigStatuses("正在读取线上配置...");
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/feishu/hermes-config", {
|
const res = await apiFetch("/feishu/hermes-config", {
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
});
|
});
|
||||||
@@ -956,7 +959,7 @@ function snapshotModelOrFields() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function postHermesRuntimeConfig(payload) {
|
async function postHermesRuntimeConfig(payload) {
|
||||||
const res = await fetch("/feishu/hermes-config", {
|
const res = await apiFetch("/feishu/hermes-config", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -1014,7 +1017,7 @@ function applySharedAgents(agents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUiConfig() {
|
async function fetchUiConfig() {
|
||||||
const res = await fetch(UI_CONFIG_ENDPOINT, {
|
const res = await apiFetch(UI_CONFIG_ENDPOINT, {
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
});
|
});
|
||||||
@@ -1029,7 +1032,7 @@ async function saveSharedConfig(options = {}) {
|
|||||||
modelProfiles: normalizeModelProfiles(state.modelProfiles),
|
modelProfiles: normalizeModelProfiles(state.modelProfiles),
|
||||||
agents: agentsForSharedConfig(),
|
agents: agentsForSharedConfig(),
|
||||||
};
|
};
|
||||||
const res = await fetch(UI_CONFIG_ENDPOINT, {
|
const res = await apiFetch(UI_CONFIG_ENDPOINT, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
|
|||||||
Reference in New Issue
Block a user