From 280d99da3200e3b9edb7865ca2b480562a5e59a2 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Sivakumar Date: Mon, 27 Jul 2026 18:07:56 +0530 Subject: [PATCH] Stop rendering permanent Backblaze URLs in the approval viewer Every image/PDF/document field in a submission was rendered directly from the stored profile_data value, which is a permanent, unsigned B2 URL. Resolve a short-lived signed URL via the new admin presign endpoint before ever using it as an img src, iframe src, or link href. Co-Authored-By: Claude Sonnet 5 --- src/routes/admin/approval/[id].tsx | 68 +++++++++++++++++++----------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/routes/admin/approval/[id].tsx b/src/routes/admin/approval/[id].tsx index d72fc03..e55f5b5 100644 --- a/src/routes/admin/approval/[id].tsx +++ b/src/routes/admin/approval/[id].tsx @@ -3,6 +3,24 @@ import { createMemo, createResource, createSignal, For, Show, createEffect } fro const API = ''; +// Documents submitted for verification are stored as permanent Backblaze URLs. +// Never render one of those directly (img src / a href) — always exchange it for +// a short-lived signed URL through this endpoint first, on demand. +async function presignDocUrl(url: string): Promise { + try { + const res = await fetch(`${API}/api/admin/verifications/presign`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ url }), + }); + if (!res.ok) return url; + const data = await res.json(); + return data?.url ?? url; + } catch { + return url; + } +} + // ── Types ────────────────────────────────────────────────────────── type RoleType = @@ -475,23 +493,11 @@ function SubmissionViewer(props: { rows: Array<{ key: string; value: string }> }
setLightbox({ src: field.value, label })} + onClick={async () => setLightbox({ src: await presignDocUrl(field.value), label })} > - {label} { - (e.target as HTMLImageElement).style.display = 'none'; - ((e.target as HTMLImageElement).nextElementSibling as HTMLElement)!.style.display = 'flex'; - }} - /> -
+
🖼 - Preview unavailable -
-
- 🔍 Click to enlarge + Click to view
@@ -499,7 +505,7 @@ function SubmissionViewer(props: { rows: Array<{ key: string; value: string }> }
setPdfViewer({ src: field.value, label })} + onClick={async () => setPdfViewer({ src: await presignDocUrl(field.value), label })} > 📄 PDF Document @@ -511,11 +517,17 @@ function SubmissionViewer(props: { rows: Array<{ key: string; value: string }> } @@ -529,7 +541,7 @@ function SubmissionViewer(props: { rows: Array<{ key: string; value: string }> } @@ -538,15 +550,21 @@ function SubmissionViewer(props: { rows: Array<{ key: string; value: string }> } - +