🐐 Several security fixes

This commit is contained in:
2026-07-29 16:30:14 +02:00
parent b42abe5f5e
commit c56498239f
21 changed files with 660 additions and 204 deletions
@@ -24,6 +24,7 @@
let profile: any = $state(null);
let loading = $state(true);
let notFound = $state(false);
let needsAuth = $state(false);
let favExpanded = $state(false);
let wttExpanded = $state(false);
@@ -114,32 +115,36 @@
const username = get(page).params.username;
const token = localStorage.getItem('token');
const res = await fetch(`${API_URL}/users/${username}`);
// Profiles now require auth. Show a prompt rather than bouncing to /auth, so
// a shared profile link explains itself instead of silently vanishing.
if (!token) { needsAuth = true; loading = false; return; }
// apiFetch (not raw fetch) so an expired access token gets refreshed
const res = await apiFetch(`${API_URL}/users/${username}`);
if (res.status === 401) { needsAuth = true; loading = false; return; }
if (res.status === 404) { notFound = true; loading = false; return; }
const data = await res.json();
// Redirect to own profile if logged-in user visits their own public page
if (token) {
try {
const meRes = await fetch(`${API_URL}/profile`, {
headers: { Authorization: `Bearer ${token}` }
});
if (meRes.ok) {
const me = await meRes.json();
if (me.username === username) { goto('/profile'); return; }
isLoggedIn = true;
try {
const meRes = await fetch(`${API_URL}/profile`, {
headers: { Authorization: `Bearer ${token}` }
});
if (meRes.ok) {
const me = await meRes.json();
if (me.username === username) { goto('/profile'); return; }
isLoggedIn = true;
// Check existing friendship status
const statusRes = await apiFetch(`${API_URL}/friendship-status/${username}`);
if (statusRes.ok) {
const s = await statusRes.json();
if (s.status === 'friends') { friendStatus = 'friends'; friendshipId = s.friendship_id; }
else if (s.status === 'pending_sent') { friendStatus = 'pending'; }
else if (s.status === 'pending_received') { friendStatus = 'pending_received'; friendshipId = s.friendship_id; }
}
// Check existing friendship status
const statusRes = await apiFetch(`${API_URL}/friendship-status/${username}`);
if (statusRes.ok) {
const s = await statusRes.json();
if (s.status === 'friends') { friendStatus = 'friends'; friendshipId = s.friendship_id; }
else if (s.status === 'pending_sent') { friendStatus = 'pending'; }
else if (s.status === 'pending_received') { friendStatus = 'pending_received'; friendshipId = s.friendship_id; }
}
} catch { /* non-critical */ }
}
}
} catch { /* non-critical */ }
profile = data;
loading = false;
@@ -151,6 +156,16 @@
<p class="status-text">Loading...</p>
</main>
{:else if needsAuth}
<main class="page">
<div class="not-found">
<div class="not-found-sigil"></div>
<h1 class="not-found-title">Adventurers Only</h1>
<p class="not-found-sub">Sign in to view this collector's profile.</p>
<a href="/auth" class="btn-primary">Sign In</a>
</div>
</main>
{:else if notFound}
<main class="page">
<div class="not-found">