完善桌面端回归与安全边界复审
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DESKTOP_SERVER_URL_KEY } from "./desktopServerConfig";
|
||||
import {
|
||||
clearSessionToken,
|
||||
getSessionToken,
|
||||
initializeSecureSessionStorage,
|
||||
LEGACY_TOKEN_KEY,
|
||||
resetSecureSessionStorageForTests,
|
||||
setSessionToken,
|
||||
} from "./secureSessionStorage";
|
||||
@@ -91,6 +93,22 @@ describe("secure session storage", () => {
|
||||
expect(invokeMock).toHaveBeenCalledWith("credential_get", { serverOrigin: SERVER_ORIGIN });
|
||||
});
|
||||
|
||||
it("migrates legacy browser tokens into the desktop credential store", async () => {
|
||||
const token = createJwt(Date.now() + DESKTOP_SESSION_MAX_AGE_MS);
|
||||
localStorage.setItem(LEGACY_TOKEN_KEY, token);
|
||||
|
||||
await initializeSecureSessionStorage();
|
||||
|
||||
expect(localStorage.getItem(LEGACY_TOKEN_KEY)).toBeNull();
|
||||
expect(getSessionToken()).toBe(token);
|
||||
expect(invokeMock).toHaveBeenCalledWith("credential_set", {
|
||||
serverOrigin: SERVER_ORIGIN,
|
||||
token: expect.any(String),
|
||||
});
|
||||
const stored = JSON.parse(invokeMock.mock.calls[0][1].token);
|
||||
expect(stored).toMatchObject({ version: 1, token });
|
||||
});
|
||||
|
||||
it("deletes an expired desktop secure session record on startup", async () => {
|
||||
const token = createJwt(Date.now() + DESKTOP_SESSION_MAX_AGE_MS);
|
||||
invokeMock.mockImplementation(async (command: string) => {
|
||||
@@ -111,6 +129,61 @@ describe("secure session storage", () => {
|
||||
expect(invokeMock).toHaveBeenCalledWith("credential_delete", { serverOrigin: SERVER_ORIGIN });
|
||||
});
|
||||
|
||||
it("enforces the local 30 day desktop session ceiling even when the token expires later", async () => {
|
||||
const token = createJwt(Date.now() + DESKTOP_SESSION_MAX_AGE_MS * 2);
|
||||
invokeMock.mockImplementation(async (command: string) => {
|
||||
if (command === "credential_get") {
|
||||
return JSON.stringify({
|
||||
version: 1,
|
||||
token,
|
||||
storedAt: Date.now() - DESKTOP_SESSION_MAX_AGE_MS - 1_000,
|
||||
expiresAt: Date.now() + DESKTOP_SESSION_MAX_AGE_MS,
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await initializeSecureSessionStorage();
|
||||
|
||||
expect(getSessionToken()).toBeNull();
|
||||
expect(invokeMock).toHaveBeenCalledWith("credential_delete", { serverOrigin: SERVER_ORIGIN });
|
||||
});
|
||||
|
||||
it("does not read credentials before a desktop server URL is configured", async () => {
|
||||
localStorage.removeItem(DESKTOP_SERVER_URL_KEY);
|
||||
|
||||
await initializeSecureSessionStorage();
|
||||
|
||||
expect(getSessionToken()).toBeNull();
|
||||
expect(invokeMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears the previous server credential after a desktop server switch", async () => {
|
||||
const previousServerOrigin = "https://old.ctms.example.com/";
|
||||
const nextServerOrigin = "https://new.ctms.example.com/";
|
||||
const token = createJwt(Date.now() + DESKTOP_SESSION_MAX_AGE_MS);
|
||||
localStorage.setItem(DESKTOP_SERVER_URL_KEY, previousServerOrigin);
|
||||
invokeMock.mockImplementation(async (command: string) => {
|
||||
if (command === "credential_get") {
|
||||
return JSON.stringify({
|
||||
version: 1,
|
||||
token,
|
||||
storedAt: Date.now(),
|
||||
expiresAt: Date.now() + DESKTOP_SESSION_MAX_AGE_MS,
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await initializeSecureSessionStorage();
|
||||
localStorage.setItem(DESKTOP_SERVER_URL_KEY, nextServerOrigin);
|
||||
await clearSessionToken();
|
||||
|
||||
expect(getSessionToken()).toBeNull();
|
||||
expect(invokeMock).toHaveBeenCalledWith("credential_delete", { serverOrigin: previousServerOrigin });
|
||||
expect(invokeMock).not.toHaveBeenCalledWith("credential_delete", { serverOrigin: nextServerOrigin });
|
||||
});
|
||||
|
||||
it("rewrites a legacy raw desktop token into a secure session record", async () => {
|
||||
const token = createJwt(Date.now() + DESKTOP_SESSION_MAX_AGE_MS);
|
||||
invokeMock.mockImplementation(async (command: string) => {
|
||||
|
||||
Reference in New Issue
Block a user