From ee05a3aac5ba9b05489b4161969e8d39a6e03db7 Mon Sep 17 00:00:00 2001 From: tianma-if Date: Fri, 31 Jul 2026 22:45:25 +0800 Subject: [PATCH] fix: support desktop member management auth --- apps/api/src/index.ts | 6 +-- packages/shared/src/i18n/en-US.ts | 2 +- packages/shared/src/i18n/zh-CN.ts | 2 +- tests/user-management-auth.test.ts | 76 ++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 tests/user-management-auth.test.ts diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 81d3233c..c0c3a054 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -769,7 +769,7 @@ app.post("/api/v1/auth/change-password", zValidator("json", ChangePasswordSchema }); app.get("/api/v1/users", async (c) => { - const auth = await authenticateSession(c, true); + const auth = await authenticateRequest(c, true); if (!auth) return unauthorized(c, "Authentication required."); c.set("auth", auth); const denied = requireOwner(c); @@ -787,7 +787,7 @@ app.get("/api/v1/users", async (c) => { }); app.post("/api/v1/users", zValidator("json", UserCreateSchema), async (c) => { - const auth = await authenticateSession(c, true); + const auth = await authenticateRequest(c, true); if (!auth) return unauthorized(c, "Authentication required."); c.set("auth", auth); const denied = requireOwner(c); @@ -824,7 +824,7 @@ app.post("/api/v1/users", zValidator("json", UserCreateSchema), async (c) => { }); app.patch("/api/v1/users/:id", zValidator("json", UserUpdateSchema), async (c) => { - const auth = await authenticateSession(c, true); + const auth = await authenticateRequest(c, true); if (!auth) return unauthorized(c, "Authentication required."); c.set("auth", auth); const denied = requireOwner(c); diff --git a/packages/shared/src/i18n/en-US.ts b/packages/shared/src/i18n/en-US.ts index 73f1ea8a..82f5d2b0 100644 --- a/packages/shared/src/i18n/en-US.ts +++ b/packages/shared/src/i18n/en-US.ts @@ -775,7 +775,7 @@ export const enUS = { subtitle: "AI Agent powered migration that preserves notebook stack hierarchy", }, evernoteImport: { - title: "Import Evernote, Notion, and Memos", + title: "Import Evernote, flomo, Notion, and Memos", guide: "View migration guide", openGuideAria: "Open the Evernote migration guide in a new tab", description: "Migrate notes from third-party platforms with recommended MCP and AI Agent batch import.", diff --git a/packages/shared/src/i18n/zh-CN.ts b/packages/shared/src/i18n/zh-CN.ts index 38e31dd6..1a4d780f 100644 --- a/packages/shared/src/i18n/zh-CN.ts +++ b/packages/shared/src/i18n/zh-CN.ts @@ -775,7 +775,7 @@ export const zhCN = { subtitle: "AI Agent 驱动一键迁移,无损保留笔记本组结构", }, evernoteImport: { - title: "导入印象笔记、Notion、Memos", + title: "导入印象笔记、flomo、Notion、Memos", guide: "查看迁移指南", openGuideAria: "在新标签页打开印象笔记迁移指南", description: "支持从第三方平台快速迁移笔记,推荐使用 MCP 与 AI Agent 批量导入。", diff --git a/tests/user-management-auth.test.ts b/tests/user-management-auth.test.ts new file mode 100644 index 00000000..76cec645 --- /dev/null +++ b/tests/user-management-auth.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, test } from "bun:test"; +import worker from "../apps/api/src/index"; + +const executionContext = { + passThroughOnException() {}, + waitUntil() {}, + props: {}, +} as unknown as ExecutionContext; + +const owner = { + id: "usr_owner", + user_id: "usr_owner", + username: "owner", + display_name: "Owner", + password_hash: "unused", + is_disabled: 0, + last_login_at: "2026-07-31T00:00:00.000Z", + created_at: "2026-07-01T00:00:00.000Z", + expires_at: "2027-07-31T00:00:00.000Z", + role: "owner", +}; + +const createDatabase = () => ({ + prepare(sql: string) { + return { + bind() { + return this; + }, + async first() { + if (sql.includes("FROM sessions s")) return owner; + if (sql.includes("FROM workspace_members WHERE user_id")) { + return { workspace_id: "ws_owner", role: "owner" }; + } + if (sql.includes("SELECT id FROM users")) return { id: owner.id }; + return null; + }, + async all() { + if (sql.includes("FROM users u") && sql.includes("INNER JOIN workspace_members")) { + return { results: [owner] }; + } + return { results: [] }; + }, + async run() { + return { success: true }; + }, + }; + }, +}) as unknown as D1Database; + +describe("member management authentication", () => { + test("accepts an owner session supplied as a desktop Bearer token", async () => { + const response = await worker.fetch( + new Request("https://edgeever.test/api/v1/users", { + headers: { Authorization: "Bearer desktop-session-token" }, + }), + { DB: createDatabase() } as never, + executionContext, + ); + + const body = await response.json(); + expect({ status: response.status, body }).toEqual({ + status: 200, + body: { + users: [{ + id: owner.id, + username: owner.username, + displayName: owner.display_name, + role: owner.role, + isDisabled: false, + lastLoginAt: owner.last_login_at, + createdAt: owner.created_at, + }], + }, + }); + }); +});