fix(security): PR 审查整改 - setWindowOpenHandler 域名白名单 / openWebsite 协议校验 / 批量云端安装并发控制

- electron/main/index.ts: setWindowOpenHandler 增加 ALLOWED_EXTERNAL_HOSTS 域名后缀白名单,仅可信 https 域名可 shell.openExternal(阻断项2)
- AppDetailModal.vue: openWebsite 增加 http/https 协议校验 + noopener,noreferrer(改进项5)
- useAccountSync.ts: installCloudItems 改为分批(BATCH_SIZE=3) + Promise.allSettled 错误收集(改进项2)
- 审查误报/未改动项已贴代码实证:阻断1 v-html 已用 textContent 转义;改进3 resolveCloudInstallCandidate 已有降级匹配链;改进4 单窗口无 HMR 不重复注册;改进1 暂停/恢复主进程无 handler 维持 TODO
This commit is contained in:
xiyidaiwa
2026-08-13 22:38:26 +08:00
parent 72d107c9de
commit cdd94c650d
4 changed files with 47 additions and 10 deletions
+9 -2
View File
@@ -644,8 +644,15 @@ const closeMetaModal = () => {
};
const openWebsite = (url: string) => {
if (url) {
window.open(url, "_blank");
if (!url) return;
try {
const parsed = new URL(url);
// 仅允许 http/https 协议,杜绝 javascript:/data: 等危险协议
if (parsed.protocol === "https:" || parsed.protocol === "http:") {
window.open(url, "_blank", "noopener,noreferrer");
}
} catch {
// 无效 URL,不打开
}
};
+18 -5
View File
@@ -319,11 +319,24 @@ const openRestoreFromAccount = async (): Promise<void> => {
}
};
const installCloudItems = (items: SyncedAppListItem[]): void => {
for (const item of items) {
const app = resolveCloudInstallCandidate(item, apps.value);
if (!app) continue;
void onDetailInstall(app);
// 批量云端安装:分批触发(每批 3 个),收集每个安装的结果并反馈失败项。
// onDetailInstall 内部本身已串行排队,这里仅限制"同时发起"的并发,避免一次注入大量任务。
const installCloudItems = async (items: SyncedAppListItem[]): Promise<void> => {
const BATCH_SIZE = 3;
let failedCount = 0;
for (let i = 0; i < items.length; i += BATCH_SIZE) {
const batch = items.slice(i, i + BATCH_SIZE);
const results = await Promise.allSettled(
batch.map(async (item) => {
const app = resolveCloudInstallCandidate(item, apps.value);
if (!app) return;
await onDetailInstall(app);
}),
);
failedCount += results.filter((r) => r.status === "rejected").length;
}
if (failedCount > 0) {
console.error(`批量云端安装中有 ${failedCount} 项失败`);
}
showRestoreModal.value = false;
};