allegedly more

This commit is contained in:
2026-07-25 03:41:21 -04:00
parent 0ff0242e00
commit 5ce382c54b
5 changed files with 30 additions and 18 deletions
+11 -10
View File
@@ -12,9 +12,10 @@ import { VolumeProvider } from "./context/VolumeContext";
type User = { id: number; email: string; username: string };
function getToken() { return localStorage.getItem("sessionToken"); }
function setToken(t: string) { localStorage.setItem("sessionToken", t); }
function clearToken() { localStorage.removeItem("sessionToken"); }
function getCookie(name: string) {
const match = document.cookie.match(`(?:^|;\\s*)${name}=([^;]*)`);
return match ? decodeURIComponent(match[1]) : null;
}
function AppInner() {
const [loading, setLoading] = useState(true);
@@ -38,11 +39,11 @@ function AppInner() {
}, []);
useEffect(() => {
const sessionToken = getToken();
const sessionToken = getCookie("sessionToken");
if (!sessionToken) { setLoading(false); return; }
fetch(`/api/session?sessionToken=${encodeURIComponent(sessionToken)}`).then((r) => {
if (!r.ok) { clearToken(); return null; }
fetch(`/api/session?sessionToken=${encodeURIComponent(sessionToken)}`, { credentials: "include" }).then((r) => {
if (!r.ok) { return null; }
return r.json();
}).then((u) => {
if (u) setUser(u);
@@ -57,13 +58,13 @@ function AppInner() {
fetch("/api/google-login", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({ credential }),
}).then((r) => {
if (!r.ok) return null;
return r.json();
}).then((u) => {
if (u) {
setToken(u.sessionToken);
setUser(u);
setShowLoginModal(false);
}
@@ -71,9 +72,9 @@ function AppInner() {
}
function handleLogout() {
const sessionToken = getToken();
if (sessionToken) fetch(`/api/session?sessionToken=${encodeURIComponent(sessionToken)}`, { method: "DELETE" }).catch(() => {});
clearToken();
const sessionToken = getCookie("sessionToken");
if (sessionToken) fetch(`/api/session?sessionToken=${encodeURIComponent(sessionToken)}`, { method: "DELETE", credentials: "include" }).catch(() => {});
document.cookie = "sessionToken=; path=/; max-age=0; Secure; SameSite=None";
setUser(null);
navigate("/");
}
+5 -2
View File
@@ -1,7 +1,10 @@
import { useState } from "react";
import { useTheme } from "../context/ThemeContext";
function getToken() { return localStorage.getItem("sessionToken"); }
function getCookie(name: string) {
const match = document.cookie.match(`(?:^|;\\s*)${name}=([^;]*)`);
return match ? decodeURIComponent(match[1]) : null;
}
type Props = {
user: { id: number; email: string; username: string };
@@ -26,7 +29,7 @@ function AccountPage({ user, onLogout, onUsernameChange }: Props) {
const res = await fetch("/api/username", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, sessionToken: getToken() }),
body: JSON.stringify({ username, sessionToken: getCookie("sessionToken") }),
});
const data = await res.json();
if (!res.ok) { setError(data.error || "failed"); setSaving(false); return; }
+6 -3
View File
@@ -1,7 +1,10 @@
import { FormEvent, useEffect, useRef, useState } from "react";
import { useTheme } from "../context/ThemeContext";
function getToken() { return localStorage.getItem("sessionToken"); }
function getCookie(name: string) {
const match = document.cookie.match(`(?:^|;\\s*)${name}=([^;]*)`);
return match ? decodeURIComponent(match[1]) : null;
}
type Tag = {
id: number;
@@ -71,7 +74,7 @@ function AdminPage({ user }: Props) {
const { dark } = useTheme();
const adminLoggedIn = user?.email === "invoictoan@gmail.com";
function ua(url: string) { const sep = url.includes("?") ? "&" : "?"; return `${url}${sep}sessionToken=${getToken()}`; }
function ua(url: string) { const sep = url.includes("?") ? "&" : "?"; return `${url}${sep}sessionToken=${getCookie("sessionToken")}`; }
const [tab, setTab] = useState<"ratings" | "reports" | "polls" | "assets" | "updates">("ratings");
const [ratings, setRatings] = useState<Rating[]>([]);
const [ratingTypes, setRatingTypes] = useState<{ id: number; name: string; hasAttachments: boolean; categories: { id: number; name: string }[] }[]>([]);
@@ -455,7 +458,7 @@ function AdminPage({ user }: Props) {
return (
<div style={{ maxWidth: 320, margin: "40px auto", color: textClr, fontSize: 16, textAlign: "center" }}>
<div style={{ marginBottom: 16 }}>Not authorized</div>
<button onClick={() => { localStorage.removeItem("sessionToken"); location.reload(); }} style={{ padding: "6px 14px", fontSize: 13, background: "none", color: textClr, border: `1px solid ${borderClr}`, cursor: "pointer" }}>Refresh Login</button>
<button onClick={() => { document.cookie = "sessionToken=; path=/; max-age=0; Secure; SameSite=None"; location.reload(); }} style={{ padding: "6px 14px", fontSize: 13, background: "none", color: textClr, border: `1px solid ${borderClr}`, cursor: "pointer" }}>Refresh Login</button>
</div>
);
}
+5 -2
View File
@@ -3,7 +3,10 @@ import { useParams, useNavigate } from "react-router-dom";
import { useTheme } from "../context/ThemeContext";
import { useVolume } from "../context/VolumeContext";
function getToken() { return localStorage.getItem("sessionToken"); }
function getCookie(name: string) {
const match = document.cookie.match(`(?:^|;\\s*)${name}=([^;]*)`);
return match ? decodeURIComponent(match[1]) : null;
}
type RatingCategory = {
id: number;
@@ -327,7 +330,7 @@ function RatingsPage({ user }: Props) {
const res = await fetch("/api/reviews", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ratingId, subject: reviewSubject.trim(), description: reviewDesc.trim(), sessionToken: getToken() }),
body: JSON.stringify({ ratingId, subject: reviewSubject.trim(), description: reviewDesc.trim(), sessionToken: getCookie("sessionToken") }),
});
const data = await res.json();
if (!res.ok) { setReviewError(data.error || "failed"); setSubmittingReview(false); return; }
+3 -1
View File
@@ -379,6 +379,7 @@ app.post("/api/google-login", async (req, res) => {
data: { token: sessionToken, userId: user.id, expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) },
});
res.setHeader("Set-Cookie", `sessionToken=${sessionToken}; Path=/; Max-Age=${30 * 24 * 60 * 60}; Secure; SameSite=None`);
const resp: Record<string, unknown> = { id: user.id, email: user.email, username: user.username, sessionToken };
res.json(resp);
} catch (e) {
@@ -387,13 +388,14 @@ app.post("/api/google-login", async (req, res) => {
});
app.get("/api/session", async (req, res) => {
const token = req.query.sessionToken as string;
const token = (req.query.sessionToken as string) || getCookie(req, "sessionToken");
if (!token) { res.status(401).json({ error: "no session" }); return; }
const session = await prisma.session.findUnique({ where: { token }, include: { user: true } });
if (!session || session.expiresAt < new Date()) {
if (session) await prisma.session.delete({ where: { id: session.id } }).catch(() => {});
res.status(401).json({ error: "session expired" }); return;
}
res.setHeader("Set-Cookie", `sessionToken=${token}; Path=/; Max-Age=${30 * 24 * 60 * 60}; Secure; SameSite=None`);
res.json({ id: session.user.id, email: session.user.email, username: session.user.username });
});