feat(challenge modal): remember trusted board websites

This commit is contained in:
Tommaso Casaburi
2026-05-06 19:05:26 +07:00
parent 2ebd9ecc30
commit cb05a8b905
46 changed files with 733 additions and 366 deletions
@@ -0,0 +1,51 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import useTrustedBoardUrlPermissionsStore from '../use-trusted-board-url-permissions-store';
const STORAGE_KEY = 'trusted-board-url-permissions-store';
describe('useTrustedBoardUrlPermissionsStore', () => {
beforeEach(() => {
localStorage.removeItem(STORAGE_KEY);
useTrustedBoardUrlPermissionsStore.setState({ trustedOrigins: {} });
});
it('starts without trusted origins', () => {
expect(useTrustedBoardUrlPermissionsStore.getState().getTrustedOrigins()).toEqual([]);
expect(useTrustedBoardUrlPermissionsStore.getState().isOriginTrusted('https://spamblocker.bitsocial.net')).toBe(false);
});
it('trusts and persists a board challenge origin', () => {
const setItemSpy = vi.spyOn(Storage.prototype, 'setItem');
useTrustedBoardUrlPermissionsStore.getState().trustOrigin('https://spamblocker.bitsocial.net', 'spamblocker.bitsocial.net', null, 1_000);
expect(useTrustedBoardUrlPermissionsStore.getState().isOriginTrusted('https://spamblocker.bitsocial.net', 2_000)).toBe(true);
expect(useTrustedBoardUrlPermissionsStore.getState().getTrustedOrigins(2_000)).toEqual([
{
createdAt: 1_000,
expiresAt: null,
origin: 'https://spamblocker.bitsocial.net',
site: 'spamblocker.bitsocial.net',
},
]);
expect(setItemSpy).toHaveBeenCalledWith(STORAGE_KEY, expect.stringContaining('spamblocker.bitsocial.net'));
setItemSpy.mockRestore();
});
it('revokes a trusted origin', () => {
useTrustedBoardUrlPermissionsStore.getState().trustOrigin('https://spamblocker.bitsocial.net', 'spamblocker.bitsocial.net');
useTrustedBoardUrlPermissionsStore.getState().revokeOrigin('https://spamblocker.bitsocial.net');
expect(useTrustedBoardUrlPermissionsStore.getState().isOriginTrusted('https://spamblocker.bitsocial.net')).toBe(false);
expect(useTrustedBoardUrlPermissionsStore.getState().getTrustedOrigins()).toEqual([]);
});
it('drops expired permissions when checked', () => {
useTrustedBoardUrlPermissionsStore.getState().trustOrigin('https://old.example', 'old.example', 10, 1);
expect(useTrustedBoardUrlPermissionsStore.getState().isOriginTrusted('https://old.example', 11)).toBe(false);
expect(useTrustedBoardUrlPermissionsStore.getState().trustedOrigins).toEqual({});
});
});
@@ -0,0 +1,71 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface TrustedBoardUrlPermission {
createdAt: number;
expiresAt: number | null;
origin: string;
site: string;
}
interface TrustedBoardUrlPermissionsState {
trustedOrigins: Record<string, TrustedBoardUrlPermission>;
clearAll: () => void;
getTrustedOrigins: (now?: number) => TrustedBoardUrlPermission[];
isOriginTrusted: (origin: string, now?: number) => boolean;
revokeOrigin: (origin: string) => void;
trustOrigin: (origin: string, site: string, expiresAt?: number | null, now?: number) => void;
}
const STORAGE_KEY = 'trusted-board-url-permissions-store';
const isPermissionActive = (permission: TrustedBoardUrlPermission | undefined, now: number) =>
!!permission && (permission.expiresAt === null || permission.expiresAt > now);
const removeExpiredPermissions = (trustedOrigins: Record<string, TrustedBoardUrlPermission>, now: number) =>
Object.fromEntries(Object.entries(trustedOrigins).filter(([, permission]) => isPermissionActive(permission, now)));
const useTrustedBoardUrlPermissionsStore = create<TrustedBoardUrlPermissionsState>()(
persist(
(set, get) => ({
trustedOrigins: {},
clearAll: () => set({ trustedOrigins: {} }),
getTrustedOrigins: (now = Date.now()) =>
Object.values(removeExpiredPermissions(get().trustedOrigins, now)).sort((a, b) => a.site.localeCompare(b.site) || a.origin.localeCompare(b.origin)),
isOriginTrusted: (origin, now = Date.now()) => {
const permission = get().trustedOrigins[origin];
if (isPermissionActive(permission, now)) return true;
if (permission) {
set((state) => {
const { [origin]: _expired, ...trustedOrigins } = state.trustedOrigins;
return { trustedOrigins };
});
}
return false;
},
revokeOrigin: (origin) =>
set((state) => {
const { [origin]: _removed, ...trustedOrigins } = state.trustedOrigins;
return { trustedOrigins };
}),
trustOrigin: (origin, site, expiresAt = null, now = Date.now()) =>
set((state) => ({
trustedOrigins: {
...state.trustedOrigins,
[origin]: {
createdAt: now,
expiresAt,
origin,
site,
},
},
})),
}),
{
name: STORAGE_KEY,
partialize: (state) => ({ trustedOrigins: state.trustedOrigins }),
},
),
);
export default useTrustedBoardUrlPermissionsStore;