From cce162553498cacfcfd443f964149917521a7e92 Mon Sep 17 00:00:00 2001 From: musistudio Date: Tue, 12 Aug 2025 21:41:42 +0800 Subject: [PATCH] fix windows/linux get system uuid error --- src/cli.ts | 18 +----- src/middleware/auth.ts | 84 +++++++++++----------------- src/server.ts | 46 +++------------ src/utils/index.ts | 4 -- src/utils/systemUUID.ts | 77 ------------------------- ui/src/components/ConfigProvider.tsx | 14 ----- ui/src/lib/api.ts | 16 ------ 7 files changed, 43 insertions(+), 216 deletions(-) delete mode 100644 src/utils/systemUUID.ts diff --git a/src/cli.ts b/src/cli.ts index bcbabee..2aa30d1 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -215,22 +215,10 @@ async function main() { // Get service info and open UI const serviceInfo = await getServiceInfo(); - - // Generate temporary API key based on system UUID - let tempApiKey = ""; - try { - const { getTempAPIKey } = require("./utils"); - tempApiKey = await getTempAPIKey(); - } catch (error: any) { - console.warn("Warning: Failed to generate temporary API key:", error.message); - console.warn("Continuing without temporary API key..."); - } - + // Add temporary API key as URL parameter if successfully generated - const uiUrl = tempApiKey - ? `${serviceInfo.endpoint}/ui/?tempApiKey=${tempApiKey}` - : `${serviceInfo.endpoint}/ui/`; - + const uiUrl = `${serviceInfo.endpoint}/ui/`; + console.log(`Opening UI at ${uiUrl}`); // Open URL in browser based on platform diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index b2681e7..8e9de55 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -1,40 +1,29 @@ import { FastifyRequest, FastifyReply } from "fastify"; -import { getTempAPIKey } from "../utils/systemUUID"; export const apiKeyAuth = (config: any) => async (req: FastifyRequest, reply: FastifyReply, done: () => void) => { - // Check for temp API key in query parameters or headers - let tempApiKey = null; - if (req.query && (req.query as any).tempApiKey) { - tempApiKey = (req.query as any).tempApiKey; - } else if (req.headers['x-temp-api-key']) { - tempApiKey = req.headers['x-temp-api-key'] as string; - } - - // If temp API key is provided, validate it - if (tempApiKey) { - try { - const expectedTempKey = await getTempAPIKey(); - - // If temp key matches, grant temporary full access - if (tempApiKey === expectedTempKey) { - (req as any).accessLevel = "full"; - (req as any).isTempAccess = true; - return done(); - } - } catch (error) { - // If there's an error generating temp key, continue with normal auth - console.warn("Failed to verify temporary API key:", error); - } - } - // Public endpoints that don't require authentication if (["/", "/health"].includes(req.url) || req.url.startsWith("/ui")) { return done(); } const apiKey = config.APIKEY; + if (!apiKey) { + // If no API key is set, enable CORS for local + const allowedOrigins = [ + `http://127.0.0.1:${config.PORT || 3456}`, + `http://localhost:${config.PORT || 3456}`, + ]; + if (req.headers.origin && allowedOrigins.includes(req.headers.origin)) { + reply.status(403).send("CORS not allowed for this origin"); + return; + } else { + reply.header('Access-Control-Allow-Origin', `http://127.0.0.1:${config.PORT || 3456}`); + reply.header('Access-Control-Allow-Origin', `http://localhost:${config.PORT || 3456}`); + } + return done(); + } const isConfigEndpoint = req.url.startsWith("/api/config"); const isRestartEndpoint = req.url === "/api/restart"; @@ -42,56 +31,47 @@ export const apiKeyAuth = if (isConfigEndpoint || isRestartEndpoint) { // Attach access level to request for later use (req as any).accessLevel = "restricted"; - + // If no API key is set in config, allow restricted access if (!apiKey) { (req as any).accessLevel = "restricted"; return done(); } - - // Check for temporary access via query parameter (for UI) - if ((req as any).isTempAccess) { - return done(); - } - + // If API key is set, check authentication - const authHeaderValue = req.headers.authorization || req.headers["x-api-key"]; - const authKey: string = Array.isArray(authHeaderValue) ? authHeaderValue[0] : authHeaderValue || ""; - + const authHeaderValue = + req.headers.authorization || req.headers["x-api-key"]; + const authKey: string = Array.isArray(authHeaderValue) + ? authHeaderValue[0] + : authHeaderValue || ""; + if (!authKey) { (req as any).accessLevel = "restricted"; return done(); } - + let token = ""; if (authKey.startsWith("Bearer")) { token = authKey.split(" ")[1]; } else { token = authKey; } - + if (token !== apiKey) { (req as any).accessLevel = "restricted"; return done(); } - + // Full access for authenticated users (req as any).accessLevel = "full"; return done(); } - // For other non-config endpoints, use existing logic - if (!apiKey) { - return done(); - } - - // Check for temporary access via query parameter (for UI) - if ((req as any).isTempAccess) { - return done(); - } - - const authHeaderValue = req.headers.authorization || req.headers["x-api-key"]; - const authKey: string = Array.isArray(authHeaderValue) ? authHeaderValue[0] : authHeaderValue || ""; + const authHeaderValue = + req.headers.authorization || req.headers["x-api-key"]; + const authKey: string = Array.isArray(authHeaderValue) + ? authHeaderValue[0] + : authHeaderValue || ""; if (!authKey) { reply.status(401).send("APIKEY is missing"); return; @@ -102,7 +82,7 @@ export const apiKeyAuth = } else { token = authKey; } - + if (token !== apiKey) { reply.status(401).send("Invalid API key"); return; diff --git a/src/server.ts b/src/server.ts index ead0f6e..989bc6c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,8 +1,6 @@ import Server from "@musistudio/llms"; -import { readConfigFile, writeConfigFile } from "./utils"; -import { CONFIG_FILE } from "./constants"; +import { readConfigFile, writeConfigFile, backupConfigFile } from "./utils"; import { join } from "path"; -import { readFileSync } from "fs"; import fastifyStatic from "@fastify/static"; export const createServer = (config: any): Server => { @@ -10,16 +8,6 @@ export const createServer = (config: any): Server => { // Add endpoint to read config.json with access control server.app.get("/api/config", async (req, reply) => { - // Get access level from request (set by auth middleware) - const accessLevel = (req as any).accessLevel || "restricted"; - - // If restricted access, return 401 - if (accessLevel === "restricted") { - reply.status(401).send("API key required to access configuration"); - return; - } - - // For full access (including temp API key), return complete config return await readConfigFile(); }); @@ -37,38 +25,17 @@ export const createServer = (config: any): Server => { // Add endpoint to save config.json with access control server.app.post("/api/config", async (req, reply) => { - // Only allow full access users to save config - const accessLevel = (req as any).accessLevel || "restricted"; - if (accessLevel !== "full") { - reply.status(403).send("Full access required to modify configuration"); - return; - } - const newConfig = req.body; - + // Backup existing config file if it exists - const { backupConfigFile } = await import("./utils"); const backupPath = await backupConfigFile(); if (backupPath) { console.log(`Backed up existing configuration file to ${backupPath}`); } - + await writeConfigFile(newConfig); return { success: true, message: "Config saved successfully" }; }); - - // Add endpoint for testing full access without modifying config - server.app.post("/api/config/test", async (req, reply) => { - // Only allow full access users to test config access - const accessLevel = (req as any).accessLevel || "restricted"; - if (accessLevel !== "full") { - reply.status(403).send("Full access required to test configuration access"); - return; - } - - // Return success without modifying anything - return { success: true, message: "Access granted" }; - }); // Add endpoint to restart the service with access control server.app.post("/api/restart", async (req, reply) => { @@ -78,13 +45,16 @@ export const createServer = (config: any): Server => { reply.status(403).send("Full access required to restart service"); return; } - + reply.send({ success: true, message: "Service restart initiated" }); // Restart the service after a short delay to allow response to be sent setTimeout(() => { const { spawn } = require("child_process"); - spawn(process.execPath, [process.argv[1], "restart"], { detached: true, stdio: "ignore" }); + spawn(process.execPath, [process.argv[1], "restart"], { + detached: true, + stdio: "ignore", + }); }, 1000); }); diff --git a/src/utils/index.ts b/src/utils/index.ts index 5d153ab..6470210 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -8,7 +8,6 @@ import { HOME_DIR, PLUGINS_DIR, } from "../constants"; -import { getSystemUUID, generateTempAPIKey, getTempAPIKey } from "./systemUUID"; import { cleanupLogFiles } from "./logCleanup"; const ensureDir = async (dir_path: string) => { @@ -139,8 +138,5 @@ export const initConfig = async () => { return config; }; -// 导出系统UUID相关函数 -export { getSystemUUID, generateTempAPIKey, getTempAPIKey }; - // 导出日志清理函数 export { cleanupLogFiles }; diff --git a/src/utils/systemUUID.ts b/src/utils/systemUUID.ts deleted file mode 100644 index df19ffd..0000000 --- a/src/utils/systemUUID.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { execSync } from "child_process"; -import { createHash } from "crypto"; -import os from "os"; - -/** - * 跨平台获取系统UUID - * @returns 系统UUID字符串 - */ -export async function getSystemUUID(): Promise { - const platform = os.platform(); - - try { - let uuid: string; - - switch (platform) { - case "win32": // Windows - uuid = execSync("wmic csproduct get UUID", { encoding: "utf8" }) - .split("\n")[1] - .trim(); - break; - - case "darwin": // macOS - uuid = execSync( - "system_profiler SPHardwareDataType | grep 'Hardware UUID'", - { encoding: "utf8" } - ) - .split(":")[1] - .trim(); - break; - - case "linux": // Linux - // 尝试使用 dmidecode (需要 root 权限) - try { - uuid = execSync("dmidecode -s system-uuid", { encoding: "utf8" }).trim(); - } catch (dmidecodeError) { - // 如果 dmidecode 失败,尝试读取 sysfs (不需要 root 权限,但可能没有权限) - try { - uuid = execSync("cat /sys/class/dmi/id/product_uuid", { encoding: "utf8" }).trim(); - } catch (sysfsError) { - throw new Error("无法在Linux系统上获取系统UUID,可能需要root权限"); - } - } - break; - - default: - throw new Error(`不支持的操作系统: ${platform}`); - } - - return uuid; - } catch (error) { - throw new Error(`获取系统UUID失败: ${error instanceof Error ? error.message : String(error)}`); - } -} - -/** - * 基于系统UUID生成固定的临时API密钥 - * @param systemUUID 系统UUID - * @returns 生成的API密钥 - */ -export function generateTempAPIKey(systemUUID: string): string { - // 使用SHA-256哈希算法确保一致性 - const hash = createHash("sha256"); - hash.update(systemUUID); - // 添加盐值以增加安全性 - hash.update("claude-code-router-temp-key-salt"); - // 生成32字符的十六进制字符串 - return hash.digest("hex").substring(0, 32); -} - -/** - * 获取临时API密钥(完整的便利函数) - * @returns 临时API密钥 - */ -export async function getTempAPIKey(): Promise { - const uuid = await getSystemUUID(); - return generateTempAPIKey(uuid); -} \ No newline at end of file diff --git a/ui/src/components/ConfigProvider.tsx b/ui/src/components/ConfigProvider.tsx index 85e2a96..aae4d34 100644 --- a/ui/src/components/ConfigProvider.tsx +++ b/ui/src/components/ConfigProvider.tsx @@ -128,20 +128,6 @@ export function ConfigProvider({ children }: ConfigProviderProps) { fetchConfig(); }, [hasFetched, apiKey]); - // Check if user has full access - useEffect(() => { - const checkAccess = async () => { - if (config) { - const hasFullAccess = await api.checkFullAccess(); - // Store access level in a global state or context if needed - // For now, we'll just log it - console.log('User has full access:', hasFullAccess); - } - }; - - checkAccess(); - }, [config]); - return ( {children} diff --git a/ui/src/lib/api.ts b/ui/src/lib/api.ts index ae7f7eb..918bc61 100644 --- a/ui/src/lib/api.ts +++ b/ui/src/lib/api.ts @@ -140,22 +140,6 @@ class ApiClient { return this.post('/config', config); } - // Check if user has full access - async checkFullAccess(): Promise { - try { - // Try to access test endpoint (won't actually modify anything) - // This will return 403 if user doesn't have full access - await this.post('/config/test', { test: true }); - return true; - } catch (error: any) { - if (error.message && error.message.includes('403')) { - return false; - } - // For other errors, assume user has access (to avoid blocking legitimate users) - return true; - } - } - // Get providers async getProviders(): Promise { return this.get('/api/providers');