fix: make logging in not mandatory
All checks were successful
deploy to cloudflare pages / deploy (push) Successful in 32s

This commit is contained in:
uku 2024-11-25 12:17:27 +01:00
parent d1a3772f6c
commit 67d2358a37
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
12 changed files with 99 additions and 24 deletions

View file

@ -13,3 +13,8 @@ export interface User {
name: string;
avatarHash: string;
}
export interface CookieData {
state: string;
next: string;
}

View file

@ -13,7 +13,7 @@ let lazyTram: [GeoJSON.Feature, string][] | null = null;
let lazyStops: GeoJSON.Feature[] | null = null;
export async function createGame(
userId: string,
userId: string | null,
mode: string,
stopsType: string,
stops: GeoJSON.Feature[],

View file

@ -1,10 +1,5 @@
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async ({ locals }) => {
if (locals.user === null) {
redirect(302, "/login");
} else {
return { user: locals.user };
}
return { user: locals.user };
};

View file

@ -6,9 +6,7 @@ export const GET: RequestHandler = async ({ url, platform, locals }) => {
const db = platform?.env?.TCL_GUESSR_D1 ?? null;
if (db === null) error(500, "could not connect to d1");
const user = locals.user;
if (user === null) error(401, "not logged in");
const userId = locals.user?.id ?? null;
const options = parseOptions(url);
const crossingStops = await getMergedStops(options.stopsType);
@ -18,7 +16,7 @@ export const GET: RequestHandler = async ({ url, platform, locals }) => {
error(400, "could not select random stop");
}
const gameData = await createGame(user.id, options.mode, options.stopsType, randomStops, db);
const gameData = await createGame(userId, options.mode, options.stopsType, randomStops, db);
return Response.json(gameData);
};

View file

@ -0,0 +1,16 @@
import { error, redirect } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async ({ locals, platform, url }) => {
const db = platform?.env?.TCL_GUESSR_D1 ?? null;
if (db === null) error(500, "could not connect to d1");
const gameId = url.searchParams.get("id") ?? null;
if (gameId === null) error(400, "no game id specified");
if (locals.user === null) error(401);
await db.prepare("UPDATE game SET user_id = ? WHERE id = ?").bind(locals.user.id, gameId).run();
redirect(302, `/results?gameId=${gameId}`);
};

View file

@ -2,18 +2,20 @@ import { redirect } from "@sveltejs/kit";
import { generateState } from "arctic";
import { discord } from "$lib/auth/discord";
import type { RequestHandler } from "./$types";
import type { CookieData } from "$lib/auth";
export const GET: RequestHandler = async ({ cookies, url }) => {
const cookie: CookieData = { state: generateState(), next: url.searchParams.get("next") ?? "/" };
export const GET: RequestHandler = async ({ cookies }) => {
const state = generateState();
const scopes = ["identify"];
const url = discord.createAuthorizationURL(state, scopes);
const authUrl = discord.createAuthorizationURL(cookie.state, scopes);
cookies.set("discord_oauth_state", state, {
cookies.set("discord_oauth_state", JSON.stringify(cookie), {
path: "/",
httpOnly: true,
maxAge: 60 * 10,
sameSite: "lax",
});
redirect(302, url);
redirect(302, authUrl);
};

View file

@ -1,9 +1,11 @@
import { error, redirect } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import { discord, type DiscordUser } from "$lib/auth/discord";
import { OAuth2RequestError, type OAuth2Tokens } from "arctic";
import { createSession, generateSessionToken } from "$lib/auth/session";
import { setSessionTokenCookie } from "$lib/auth/cookie";
import { destr } from "destr";
import type { RequestHandler } from "./$types";
import type { CookieData } from "$lib/auth";
export const GET: RequestHandler = async ({ platform, url, cookies, fetch }) => {
const db = platform?.env?.TCL_GUESSR_D1 ?? null;
@ -11,13 +13,13 @@ export const GET: RequestHandler = async ({ platform, url, cookies, fetch }) =>
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const storedState = cookies.get("discord_oauth_state") ?? null;
const cookie = destr<CookieData>(cookies.get("discord_oauth_state")) ?? null;
if (code === null || state === null || storedState === null) {
if (code === null || state === null || cookie === null) {
error(400, "missing things from oauth2 response");
}
if (state !== storedState) {
if (state !== cookie.state) {
error(400, "state does not match");
}
@ -49,5 +51,5 @@ export const GET: RequestHandler = async ({ platform, url, cookies, fetch }) =>
const session = await createSession(sessionToken, discordUser.id, db);
setSessionTokenCookie(cookies, sessionToken, session.expiresAt);
redirect(302, "/");
redirect(302, cookie.next);
};

View file

@ -4,12 +4,13 @@ import { error } from "@sveltejs/kit";
interface JoinedRoundScore {
mode: string;
total_score: number;
name: string;
points: number;
distance: number;
stop_name: string;
}
export const load: PageServerLoad = async ({ url, platform }) => {
export const load: PageServerLoad = async ({ locals, url, platform }) => {
const db = platform?.env?.TCL_GUESSR_D1;
if (!db) error(500, "could not connect to d1");
@ -18,10 +19,10 @@ export const load: PageServerLoad = async ({ url, platform }) => {
const { results } = await db
.prepare(
"SELECT game.mode, game.total_score, round.points, round.distance, round.stop_name FROM game INNER JOIN round ON round.game_id = game.id WHERE game.id = ?;",
"SELECT game.mode, game.total_score, user.name, round.points, round.distance, round.stop_name FROM game INNER JOIN round ON round.game_id = game.id LEFT JOIN user ON user.id = game.user_id WHERE game.id = ?;",
)
.bind(gameId)
.all<JoinedRoundScore>();
return { rounds: results, gameId };
return { rounds: results, gameId, loggedIn: locals.user !== null };
};

View file

@ -10,6 +10,9 @@
const totalScore = props.data.rounds[0].total_score;
const mode = props.data.rounds[0].mode;
const name = props.data.rounds[0].name;
const saveParams = new URLSearchParams({ next: `/api/save?id=${props.data.gameId}` });
</script>
<div class="container">
@ -19,6 +22,14 @@
<span>mode: {mode}</span>
{#if name !== null}
<span>joué par {name}</span>
{:else if props.data.loggedIn}
<span>joué par <i>un inconnu...</i></span>
{:else}
<span><a href="/login?{saveParams}">connectez vous</a> pour sauvegarder votre score!</span>
{/if}
<table>
<tbody>
{#each props.data.rounds as round}