fix: harden extension security and plugin reliability

Address audit findings across background handlers, openers,
plugins, and UI: URL allowlists, XSS reductions, popup lifecycle
fixes, plugin dispose/cleanup, cloud sync hardening, global search
mathjs sandbox, and settings storage fixes.
This commit is contained in:
2026-06-17 10:50:26 +09:30
parent 0e696e0175
commit 8a5424c5a4
70 changed files with 1229 additions and 430 deletions
+12 -6
View File
@@ -6,7 +6,7 @@
import browser from "webextension-polyfill";
import { standalone as StandaloneStore } from "../utils/standalone.svelte";
import { onMount } from "svelte";
import { onMount, onDestroy } from "svelte";
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup";
@@ -108,12 +108,14 @@
showDisclaimerModal = true;
};
const closePopupsOnSettingsClose = () => {
showColourPicker = false;
showFontPicker = false;
showCloudPanel = false;
};
onMount(() => {
settingsPopup.addListener(() => {
showColourPicker = false;
showFontPicker = false;
showCloudPanel = false;
});
settingsPopup.addListener(closePopupsOnSettingsClose);
if (standalone) {
StandaloneStore.setStandalone(true);
@@ -125,6 +127,10 @@
});
}
});
onDestroy(() => {
settingsPopup.removeListener(closePopupsOnSettingsClose);
});
</script>
<div
+4 -3
View File
@@ -19,6 +19,7 @@
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup"
import { getSnapshotForUpload } from "@/seqta/utils/cloudSettingsSync"
import { getStoredOverride, setApiBase } from "@/seqta/utils/DevApiBase"
import { onMount } from "svelte"
let devApiBaseInput = $state<string>(getStoredOverride() ?? "")
let devApiBaseActive = $state<string | null>(getStoredOverride())
@@ -128,9 +129,9 @@
await browser.storage.local.set({ [storageKey]: currentSettings });
}
$effect(() => {
loadPluginSettings();
})
onMount(() => {
void loadPluginSettings();
});
const { showColourPicker, showFontPicker, showDisclaimer, showCloudPanel } = $props<{
showColourPicker: () => void;
+5 -6
View File
@@ -23,7 +23,10 @@
const themeManager = ThemeManager.getInstance();
let cloudLoggedIn = $state(cloudAuth.state.isLoggedIn);
cloudAuth.subscribe((s) => { cloudLoggedIn = s.isLoggedIn; });
$effect(() => {
const unsub = cloudAuth.subscribe((s) => { cloudLoggedIn = s.isLoggedIn; });
return unsub;
});
// State variables
let searchTerm = $state('');
@@ -86,13 +89,11 @@
}
const toggleFavorite = async (theme: Theme) => {
const token = await cloudAuth.getStoredToken();
if (!token) return;
if (!cloudLoggedIn) return;
const isFavorite = !theme.is_favorited;
const result = (await browser.runtime.sendMessage({
type: 'cloudFavorite',
themeId: theme.id,
token,
action: isFavorite ? 'favorite' : 'unfavorite',
})) as { success?: boolean };
if (result?.success) {
@@ -119,14 +120,12 @@
error = null;
}
try {
const token = await cloudAuth.getStoredToken();
const data = await sendMessageWithTimeout<{
success?: boolean;
data?: { themes: unknown[] };
error?: string;
}>({
type: 'fetchThemes',
token: token ?? undefined,
});
if (!data?.success || !Array.isArray(data?.data?.themes)) {
throw new Error(data?.error || 'Failed to fetch themes');