Skip to content

Commit aafcaaf

Browse files
AzizX-coderclaude
andcommitted
fix: real bugs found in audit pass
Followed up the audit with concrete fixes for what was actually broken: 1. BLOCKER — desktop & Android releases shipped with empty Supabase env. .github/workflows/main.yml passed GH_TOKEN to all four platform build steps but never VITE_SUPABASE_URL / VITE_SUPABASE_ANON_KEY. Result: the bundled app called createClient("", "") and isSupabaseConfigured returned false, so the installed desktop app had no cloud features at all and Account/Workspaces showed "sign in" with no working sign-in. Now passed on Win / Mac / Linux / Android. 2. captureStore.loadItems() was only called by CapturePage's useEffect. Quick Capture (Ctrl+Shift+S from anywhere) and the command palette read the same store. If the user used those before visiting the Saved tab, the store was [] in memory while localStorage had content — making it look like Saved messages were silently failing. App.tsx now pre-loads captureStore + flowsStore at boot. 3. MarkdownRenderer (used by AI chat for assistant replies) wrote raw markdown HTML through dangerouslySetInnerHTML without sanitization. renderMarkdown escapes inline text but inline HTML in the input would leak through. Now wrapped with DOMPurify (same config as the public note share page). 4. package.json bumped to 3.2.1 — tagging this immediately so the next release build picks up #1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9bbc919 commit aafcaaf

4 files changed

Lines changed: 44 additions & 2 deletions

File tree

.github/workflows/main.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ jobs:
4040
npx electron-builder --win --config.directories.output=release
4141
env:
4242
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43+
# Bake Supabase + tldraw env vars into the desktop bundle so the
44+
# installed app actually connects to the cloud. Without these, the
45+
# built app shows "Sign in" but isSupabaseConfigured is false.
46+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
47+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
48+
VITE_TLDRAW_LICENSE_KEY: ${{ secrets.VITE_TLDRAW_LICENSE_KEY }}
49+
VITE_OPENROUTER_API_KEY: ${{ secrets.VITE_OPENROUTER_API_KEY }}
4350

4451
- name: Generate SHA-256 checksums
4552
shell: pwsh
@@ -84,6 +91,10 @@ jobs:
8491
env:
8592
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8693
CSC_IDENTITY_AUTO_DISCOVERY: "false"
94+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
95+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
96+
VITE_TLDRAW_LICENSE_KEY: ${{ secrets.VITE_TLDRAW_LICENSE_KEY }}
97+
VITE_OPENROUTER_API_KEY: ${{ secrets.VITE_OPENROUTER_API_KEY }}
8798

8899
- name: Generate SHA-256 checksums
89100
run: |
@@ -122,6 +133,10 @@ jobs:
122133
npx electron-builder --linux --config.directories.output=release
123134
env:
124135
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
137+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
138+
VITE_TLDRAW_LICENSE_KEY: ${{ secrets.VITE_TLDRAW_LICENSE_KEY }}
139+
VITE_OPENROUTER_API_KEY: ${{ secrets.VITE_OPENROUTER_API_KEY }}
125140

126141
- name: Generate SHA-256 checksums
127142
run: |
@@ -164,6 +179,11 @@ jobs:
164179

165180
- name: Build web app
166181
run: npx vite build
182+
env:
183+
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
184+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
185+
VITE_TLDRAW_LICENSE_KEY: ${{ secrets.VITE_TLDRAW_LICENSE_KEY }}
186+
VITE_OPENROUTER_API_KEY: ${{ secrets.VITE_OPENROUTER_API_KEY }}
167187

168188
- name: Add & sync Capacitor Android platform
169189
run: |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "delay",
3-
"version": "3.2.0",
3+
"version": "3.2.1",
44
"description": "Notes, tasks, calendar & AI — beautifully organized.",
55
"author": "AzizX-coder",
66
"license": "Apache-2.0",

src/App.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ export default function App() {
122122
async function init() {
123123
await initSettings();
124124
await initTheme();
125+
// Pre-load stores whose page might not be visited but whose data
126+
// we still need warm (Quick Capture modal writes to captureStore, the
127+
// command palette searches its items, etc.). Without this, opening
128+
// QuickCapture before ever visiting the Saved page silently writes
129+
// into an empty in-memory list and the user thinks Saved is broken.
130+
try { (await import("@/stores/captureStore")).useCaptureStore.getState().loadItems(); } catch {}
131+
try { (await import("@/stores/flowsStore")).useFlowsStore.getState().loadFlows(); } catch {}
125132
setReady(true);
126133
const timer = setTimeout(() => setShowSplash(false), 600);
127134
return () => clearTimeout(timer);

src/components/ui/MarkdownRenderer.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
import { useMemo } from "react";
2+
import DOMPurify from "dompurify";
23

34
interface MarkdownRendererProps {
45
content: string;
56
className?: string;
67
}
78

9+
/**
10+
* Renders Markdown as HTML. `renderMarkdown` already escapes inline text,
11+
* but Markdown that comes from AI / shared notes / a chat partner can
12+
* include raw HTML in unexpected places. We pass the result through
13+
* DOMPurify so even a clever payload can't smuggle <script>, <iframe>,
14+
* or onerror attributes into the page.
15+
*/
816
export function MarkdownRenderer({ content, className = "" }: MarkdownRendererProps) {
9-
const html = useMemo(() => renderMarkdown(content), [content]);
17+
const html = useMemo(() => {
18+
const raw = renderMarkdown(content);
19+
return DOMPurify.sanitize(raw, {
20+
USE_PROFILES: { html: true },
21+
FORBID_TAGS: ["style", "form", "input", "textarea", "button", "iframe", "object", "embed", "script"],
22+
FORBID_ATTR: ["onerror", "onload", "onclick", "onmouseover", "onfocus", "style"],
23+
});
24+
}, [content]);
1025

1126
return (
1227
<div

0 commit comments

Comments
 (0)