fix: support desktop member management auth
This commit is contained in:
1 parent
9a7eeda78c
commit
ee05a3aac5
4 files changed
+81
-5
No files matched your search
@@ -769,7 +769,7 @@ app.post("/api/v1/auth/change-password", zValidator("json", ChangePasswordSchema
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/v1/users", async (c) => {
|
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.");
|
if (!auth) return unauthorized(c, "Authentication required.");
|
||||||
c.set("auth", auth);
|
c.set("auth", auth);
|
||||||
const denied = requireOwner(c);
|
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) => {
|
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.");
|
if (!auth) return unauthorized(c, "Authentication required.");
|
||||||
c.set("auth", auth);
|
c.set("auth", auth);
|
||||||
const denied = requireOwner(c);
|
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) => {
|
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.");
|
if (!auth) return unauthorized(c, "Authentication required.");
|
||||||
c.set("auth", auth);
|
c.set("auth", auth);
|
||||||
const denied = requireOwner(c);
|
const denied = requireOwner(c);
|
||||||
|
|||||||
@@ -775,7 +775,7 @@ export const enUS = {
|
|||||||
subtitle: "AI Agent powered migration that preserves notebook stack hierarchy",
|
subtitle: "AI Agent powered migration that preserves notebook stack hierarchy",
|
||||||
},
|
},
|
||||||
evernoteImport: {
|
evernoteImport: {
|
||||||
title: "Import Evernote, Notion, and Memos",
|
title: "Import Evernote, flomo, Notion, and Memos",
|
||||||
guide: "View migration guide",
|
guide: "View migration guide",
|
||||||
openGuideAria: "Open the Evernote migration guide in a new tab",
|
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.",
|
description: "Migrate notes from third-party platforms with recommended MCP and AI Agent batch import.",
|
||||||
|
|||||||
@@ -775,7 +775,7 @@ export const zhCN = {
|
|||||||
subtitle: "AI Agent 驱动一键迁移,无损保留笔记本组结构",
|
subtitle: "AI Agent 驱动一键迁移,无损保留笔记本组结构",
|
||||||
},
|
},
|
||||||
evernoteImport: {
|
evernoteImport: {
|
||||||
title: "导入印象笔记、Notion、Memos",
|
title: "导入印象笔记、flomo、Notion、Memos",
|
||||||
guide: "查看迁移指南",
|
guide: "查看迁移指南",
|
||||||
openGuideAria: "在新标签页打开印象笔记迁移指南",
|
openGuideAria: "在新标签页打开印象笔记迁移指南",
|
||||||
description: "支持从第三方平台快速迁移笔记,推荐使用 MCP 与 AI Agent 批量导入。",
|
description: "支持从第三方平台快速迁移笔记,推荐使用 MCP 与 AI Agent 批量导入。",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user