diff --git a/src/app/service/service_worker/external_access/controller.test.ts b/src/app/service/service_worker/external_access/controller.test.ts index 267cdaba6..ca22731ad 100644 --- a/src/app/service/service_worker/external_access/controller.test.ts +++ b/src/app/service/service_worker/external_access/controller.test.ts @@ -92,6 +92,34 @@ describe("ExternalAccessController(外部接入 · 扁平信任)", () => { expect(connectClient.connect).toHaveBeenCalledWith({ url: DEFAULT_URL, auth: { mode: "session", key: "abc123" } }); }); + describe("隐身(split)进程", () => { + // split 模式下隐身进程与普通进程共用 chrome.storage.local 里的密钥和脚本,它再连一次只会与普通进程互相顶替(sctl#14)。 + const extension = chrome.extension as unknown as { inIncognitoContext: boolean }; + + beforeEach(() => { + extension.inIncognitoContext = true; + }); + + afterEach(() => { + extension.inIncognitoContext = false; + }); + + it("已启用且已接入时启动也不拨号,状态保持 disabled", async () => { + systemConfig.setExternalAccessEnabled(true); + const controller = await initEnrolled("abc123", "cid"); + expect(connectClient.connect).not.toHaveBeenCalled(); + expect(controller.getStatus().status).toBe("disabled"); + }); + + it("enroll(code) 不以配对模式拨号", async () => { + const controller = makeController(); + await controller.initialize(); + await controller.enroll("PAIR-CODE"); + expect(connectClient.connect).not.toHaveBeenCalled(); + expect(controller.getStatus().status).toBe("disabled"); + }); + }); + it("enroll(code) 以配对模式拨号", async () => { const controller = makeController(); await controller.initialize(); diff --git a/src/app/service/service_worker/external_access/controller.ts b/src/app/service/service_worker/external_access/controller.ts index 96661ff2a..250afc9a0 100644 --- a/src/app/service/service_worker/external_access/controller.ts +++ b/src/app/service/service_worker/external_access/controller.ts @@ -55,6 +55,10 @@ export class ExternalAccessController { this.group.on("paired", (payload: { key: string }) => this.onEnrolled(payload.key)); this.group.on("disconnected", () => this.onDisconnected()); + // split 模式下隐身进程与普通进程共用 chrome.storage.local 里的密钥和脚本,由普通进程代表这份安装连接 sctl; + // 隐身进程再连只会与普通进程互相顶替(sctl#14)。 + if (chrome.extension.inIncognitoContext) return; + this.systemConfig.addListener("external_access_enabled", (enabled) => { if (enabled) { void this.connect(); @@ -90,6 +94,7 @@ export class ExternalAccessController { // pairing mode with C; on success the daemon ships a fresh long-term key K, which offscreen // decrypts and relays back via `onEnrolled`. async enroll(code: string): Promise { + if (chrome.extension.inIncognitoContext) return; this.active = true; this.setStatus("connecting"); const url = await this.systemConfig.getExternalAccessUrl();