From d3600a9d52b996d899d6cf44c249d0c1bea0169f Mon Sep 17 00:00:00 2001 From: tianma-if Date: Wed, 9 Sep 2026 20:59:34 +0800 Subject: [PATCH] fix(plugins): skip community trust dialog for official plugins Official marketplace plugins already show the official auto-update badge, but the first-enable confirmation still used community-plugin copy. Skip that confirmation for publisher EdgeEver plugins; community plugins still get the one-time warning. --- .../settings/PluginManagerCard.test.mjs | 5 +++ .../components/settings/PluginManagerCard.tsx | 5 ++- .../web/src/lib/plugins/plugin-trust.test.mjs | 39 ++++++++++++++++--- apps/web/src/lib/plugins/plugin-trust.ts | 4 +- docs/plugin-development.md | 2 +- docs/plugin-development.zh-CN.md | 2 +- 6 files changed, 48 insertions(+), 9 deletions(-) diff --git a/apps/web/src/components/settings/PluginManagerCard.test.mjs b/apps/web/src/components/settings/PluginManagerCard.test.mjs index 0aaa7d21..35057855 100644 --- a/apps/web/src/components/settings/PluginManagerCard.test.mjs +++ b/apps/web/src/components/settings/PluginManagerCard.test.mjs @@ -40,4 +40,9 @@ describe("unified plugin catalog cards", () => { expect(catalogCard).not.toContain("marketplace.installed"); expect(source).not.toContain("border-emerald-100"); }); + + test("does not treat official marketplace plugins as community plugins in the trust dialog", () => { + expect(source).toContain("getPluginCatalogSourceKey(catalogItem) === \"official\""); + expect(source).toContain("isOfficial:"); + }); }); diff --git a/apps/web/src/components/settings/PluginManagerCard.tsx b/apps/web/src/components/settings/PluginManagerCard.tsx index c09423c1..7c8f13be 100644 --- a/apps/web/src/components/settings/PluginManagerCard.tsx +++ b/apps/web/src/components/settings/PluginManagerCard.tsx @@ -15,7 +15,7 @@ import { GitHubMark } from "@/components/GitHubRepositoryLink"; import { applyPluginUpdate, checkPluginUpdates, type PluginUpdateInfo } from "@/lib/plugins/plugin-updates"; import { PluginUpdateDialog } from "@/components/plugins/PluginUpdateDialog"; import { PluginSettingsSection } from "@/components/plugins/PluginSettingsSection"; -import { buildPluginCatalogItems } from "@/lib/plugins/plugin-catalog"; +import { buildPluginCatalogItems, getPluginCatalogSourceKey } from "@/lib/plugins/plugin-catalog"; import { getPluginDetailPage, getPluginDetailPath, hasPluginSettings, type PluginDetailPage } from "@/lib/plugins/plugin-navigation"; import type { ScheduledTask } from "@edgeever/shared"; import { api, getOrCreateClientDeviceId } from "@/lib/api"; @@ -391,10 +391,13 @@ export const PluginManagerCard = ({ }; const toggleExtension = (extension: InstalledExtension, enabled: boolean) => { + const catalogItem = catalogItems.find((item) => item.id === extension.manifest.id) + ?? { id: extension.manifest.id, extension }; if (shouldRequestPluginTrustAcknowledgement({ acknowledged: hasAcknowledgedPluginTrustWarning(), enabled, extensionType: extension.manifest.type, + isOfficial: getPluginCatalogSourceKey(catalogItem) === "official", })) { setPendingTrustPluginId(extension.manifest.id); return; diff --git a/apps/web/src/lib/plugins/plugin-trust.test.mjs b/apps/web/src/lib/plugins/plugin-trust.test.mjs index 36f87f8b..866cb961 100644 --- a/apps/web/src/lib/plugins/plugin-trust.test.mjs +++ b/apps/web/src/lib/plugins/plugin-trust.test.mjs @@ -34,10 +34,39 @@ describe("plugin trust acknowledgement", () => { expect(() => acknowledgePluginTrustWarning(storage)).not.toThrow(); }); - test("asks only before the first client-plugin enable", () => { - expect(shouldRequestPluginTrustAcknowledgement({ acknowledged: false, enabled: true, extensionType: "plugin" })).toBe(true); - expect(shouldRequestPluginTrustAcknowledgement({ acknowledged: true, enabled: true, extensionType: "plugin" })).toBe(false); - expect(shouldRequestPluginTrustAcknowledgement({ acknowledged: false, enabled: false, extensionType: "plugin" })).toBe(false); - expect(shouldRequestPluginTrustAcknowledgement({ acknowledged: false, enabled: true, extensionType: "theme" })).toBe(false); + test("asks only before the first community client-plugin enable", () => { + expect(shouldRequestPluginTrustAcknowledgement({ + acknowledged: false, + enabled: true, + extensionType: "plugin", + isOfficial: false, + })).toBe(true); + expect(shouldRequestPluginTrustAcknowledgement({ + acknowledged: true, + enabled: true, + extensionType: "plugin", + isOfficial: false, + })).toBe(false); + expect(shouldRequestPluginTrustAcknowledgement({ + acknowledged: false, + enabled: false, + extensionType: "plugin", + isOfficial: false, + })).toBe(false); + expect(shouldRequestPluginTrustAcknowledgement({ + acknowledged: false, + enabled: true, + extensionType: "theme", + isOfficial: false, + })).toBe(false); + }); + + test("does not treat official plugins as community plugins", () => { + expect(shouldRequestPluginTrustAcknowledgement({ + acknowledged: false, + enabled: true, + extensionType: "plugin", + isOfficial: true, + })).toBe(false); }); }); diff --git a/apps/web/src/lib/plugins/plugin-trust.ts b/apps/web/src/lib/plugins/plugin-trust.ts index abf8e019..5a9e2aa7 100644 --- a/apps/web/src/lib/plugins/plugin-trust.ts +++ b/apps/web/src/lib/plugins/plugin-trust.ts @@ -41,8 +41,10 @@ export const shouldRequestPluginTrustAcknowledgement = ({ acknowledged, enabled, extensionType, + isOfficial, }: { acknowledged: boolean; enabled: boolean; extensionType: "plugin" | "theme"; -}) => enabled && extensionType === "plugin" && !acknowledged; + isOfficial: boolean; +}) => enabled && extensionType === "plugin" && !acknowledged && !isOfficial; diff --git a/docs/plugin-development.md b/docs/plugin-development.md index 7abdea32..4599eafe 100644 --- a/docs/plugin-development.md +++ b/docs/plugin-development.md @@ -8,7 +8,7 @@ Theme packages contain only a validated manifest and documented design tokens. T Client plugins use an Obsidian-style trusted-code model. Enabling a plugin trusts it with the full EdgeEver plugin context; declared capabilities are optional descriptive metadata and do not gate API calls. The plugin module runs in the client JavaScript environment, so users must install plugins only from developers they trust. -The first time a user enables a client plugin on a device, EdgeEver presents a community-plugin trust confirmation. Once acknowledged, it is not shown for every plugin. Theme packages do not trigger the confirmation because they cannot execute JavaScript. +The first time a user enables a community client plugin on a device, EdgeEver presents a community-plugin trust confirmation. Once acknowledged, it is not shown for every plugin. Official plugins (publisher EdgeEver) do not trigger the confirmation. Theme packages also do not trigger it because they cannot execute JavaScript. Plugins never receive EdgeEver's repository, IndexedDB database, Cloudflare bindings, or internal React state through the public API. diff --git a/docs/plugin-development.zh-CN.md b/docs/plugin-development.zh-CN.md index c6e518b7..b5b165e9 100644 --- a/docs/plugin-development.zh-CN.md +++ b/docs/plugin-development.zh-CN.md @@ -8,7 +8,7 @@ EdgeEver P0 扩展 API 支持受信任的客户端插件和无代码主题包。 客户端插件采用类似 Obsidian 的受信任代码模型。启用插件即代表信任它使用完整的 EdgeEver 插件上下文;能力声明只是可选的描述性元数据,不限制 API 调用。插件模块运行在客户端 JavaScript 环境中,因此用户只能安装来自可信开发者的插件。 -用户在一台设备上首次启用客户端插件时,EdgeEver 会显示一次社区插件信任确认;确认后不会对每个插件重复提示。主题包不能执行 JavaScript,因此不会触发该确认。 +用户在一台设备上首次启用社区客户端插件时,EdgeEver 会显示一次社区插件信任确认;确认后不会对每个插件重复提示。官方插件(发布者为 EdgeEver)不会触发该确认。主题包不能执行 JavaScript,因此也不会触发该确认。 公开 API 不会向插件暴露 EdgeEver Repository、IndexedDB 数据库、Cloudflare Binding 或 React 内部状态。