allegedly more
This commit is contained in:
+11
-10
@@ -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("/");
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user