From cd46072c00693d4a14f8b8dd972c2843027ba2b5 Mon Sep 17 00:00:00 2001 From: "Lucian I. Last" Date: Fri, 15 Mar 2024 17:55:41 +0100 Subject: [PATCH] Fix cookies once and for all --- .../react/components/ChainsList.tsx | 9 +++-- .../components/react/pages/AdminDashboard.tsx | 3 -- frontend/src/stores/auth.ts | 2 +- frontend/src/stores/browser_storage.ts | 34 ++++++++++++++++--- server/internal/app/auth/cookie.go | 10 +++--- server/internal/server.go | 17 ++++++++++ 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/react/components/ChainsList.tsx b/frontend/src/components/react/components/ChainsList.tsx index 9a110c4b2..00147ac34 100644 --- a/frontend/src/components/react/components/ChainsList.tsx +++ b/frontend/src/components/react/components/ChainsList.tsx @@ -6,8 +6,6 @@ import { type SetStateAction, } from "react"; -import Cookies from "js-cookie"; - import { $authUser, authUserRefresh } from "../../../stores/auth"; import { chainGet, @@ -23,6 +21,7 @@ import useToClipboard from "../util/to-clipboard.hooks"; import { useStore } from "@nanostores/react"; import { useTranslation } from "react-i18next"; import useLocalizePath from "../util/localize_path.hooks"; +import { cookiePoke } from "../../../stores/browser_storage"; const PUBLIC_BASE_URL = import.meta.env.PUBLIC_BASE_URL; @@ -69,7 +68,7 @@ export default function ChainsList({ chains, setChains }: Props) { addToastError(GinParseErrors(t, err), err.status); } - setIsPokeable(!(Cookies.get("poke") === authUser.uid)); + setIsPokeable(!(cookiePoke.get() === authUser.uid)); } } @@ -80,14 +79,14 @@ export default function ChainsList({ chains, setChains }: Props) { chainPoke(chainUID) .then(() => { addToast({ type: "success", message: t("reminderEmailSent") }); - Cookies.set("poke", authUser.uid, { expires: 7 }); + cookiePoke.set(authUser.uid, 7); setIsPokeable(false); }) .catch((err) => { addToastError(GinParseErrors(t, err), err.status); if (err.status === 429) { // hide for a day - Cookies.set("poke", authUser.uid, { expires: 1 }); + cookiePoke.set(authUser.uid, 1); setIsPokeable(false); } }); diff --git a/frontend/src/components/react/pages/AdminDashboard.tsx b/frontend/src/components/react/pages/AdminDashboard.tsx index bd8494c48..4a42da357 100644 --- a/frontend/src/components/react/pages/AdminDashboard.tsx +++ b/frontend/src/components/react/pages/AdminDashboard.tsx @@ -1,7 +1,6 @@ import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { useStore } from "@nanostores/react"; -import Cookies from "js-cookie"; import { userPurge } from "../../../api/user"; import ChainsList from "../components/ChainsList"; @@ -61,8 +60,6 @@ export default function AdminDashboard() { type: "error", fn: () => { userPurge(authUser!.uid).then(() => { - // Remove legacy cookies - Cookies.remove("user_uid"); window.location.href = localizePath("/users/logout"); }); }, diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index f7e8384fc..1a9579423 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -62,8 +62,8 @@ export function authUserRefresh(force = false): Promise { const hasLoginSession = !!user; if (hasLoginSession) console.info("has session storage"); - console.info("retrieve user uid from cookie"); let userUID = cookieUserUID.get(); + if (userUID) console.info("retrieved user uid from cookie"); if (!userUID) { $authUser.set(null); diff --git a/frontend/src/stores/browser_storage.ts b/frontend/src/stores/browser_storage.ts index 4962a7eca..8829c1a0c 100644 --- a/frontend/src/stores/browser_storage.ts +++ b/frontend/src/stores/browser_storage.ts @@ -1,8 +1,19 @@ import Cookies from "js-cookie"; import type { User } from "../api/types"; +const IS_PRODUCTION = + import.meta.env.PUBLIC_BASE_URL === "https://www.clothingloop.org"; +const IS_ACCEPTANCE = + import.meta.env.PUBLIC_BASE_URL === "https://acc.clothingloop.org"; + const IS_DEV_MODE = import.meta.env.DEV; +function cookiePostfix(name: string): string { + if (IS_PRODUCTION) return name; + if (IS_ACCEPTANCE) return name + "_acc"; + return name + "_dev"; +} + type BrowserAtom = { get: () => T | undefined | null; set: (v: T | undefined | null) => void; @@ -17,9 +28,12 @@ const cookieOptions: Cookies.CookieAttributes = { sameSite: "strict", }; -const KEY_C_USER_UID = "user_uid"; +const KEY_C_USER_UID = cookiePostfix("user_uid"); export const cookieUserUID: BrowserAtom = { - get: () => Cookies.get(KEY_C_USER_UID), + get: () => { + console.log(KEY_C_USER_UID); + return Cookies.get(KEY_C_USER_UID); + }, set: (uid) => { if (!uid) { Cookies.remove(KEY_C_USER_UID, cookieOptions); @@ -29,10 +43,22 @@ export const cookieUserUID: BrowserAtom = { }, }; +const KEY_C_POKE = cookiePostfix("poke"); +export const cookiePoke = { + get: () => Cookies.get(KEY_C_POKE), + set: (uid: string, days: number) => { + if (!uid) { + Cookies.remove(KEY_C_POKE); + return; + } + Cookies.set(KEY_C_POKE, uid, { expires: days }); + }, +}; + // Localstorage // ---------------------------------------------------------------- -const KEY_L_ROUTE_MAP_LINE = "route_map_line"; +const KEY_L_ROUTE_MAP_LINE = cookiePostfix("route_map_line"); export const localRouteMapLine: BrowserAtom = { get: () => getS(window.localStorage, KEY_L_ROUTE_MAP_LINE), set: (v) => setS(window.localStorage, KEY_L_ROUTE_MAP_LINE)(v), @@ -41,7 +67,7 @@ export const localRouteMapLine: BrowserAtom = { // Sessionstorage // ---------------------------------------------------------------- -const KEY_S_AUTH_USER = "auth_user"; +const KEY_S_AUTH_USER = cookiePostfix("auth_user"); export const sessionAuthUser: BrowserAtom = { get: () => { diff --git a/server/internal/app/auth/cookie.go b/server/internal/app/auth/cookie.go index 815dfa8b2..e7b0f41ed 100644 --- a/server/internal/app/auth/cookie.go +++ b/server/internal/app/auth/cookie.go @@ -11,14 +11,14 @@ import ( const cookieMaxAge = 3600 * 24 * 365 func cookieRead(c *gin.Context) (string, bool) { - token, err := c.Cookie("token") + token, err := c.Cookie(c.GetString("cookie_token")) return token, err == nil } func CookieRemove(c *gin.Context) { http.SetCookie(c.Writer, &http.Cookie{ - Name: "token", + Name: c.GetString("cookie_token"), Value: "", MaxAge: -1, Path: "/", @@ -29,7 +29,7 @@ func CookieRemove(c *gin.Context) { }) http.SetCookie(c.Writer, &http.Cookie{ - Name: "user_uid", + Name: c.GetString("cookie_user"), Value: "", MaxAge: -1, Path: "/", @@ -42,7 +42,7 @@ func CookieRemove(c *gin.Context) { func CookieSet(c *gin.Context, userUID, token string) { http.SetCookie(c.Writer, &http.Cookie{ - Name: "token", + Name: c.GetString("cookie_token"), Value: token, MaxAge: cookieMaxAge, Path: "/", @@ -53,7 +53,7 @@ func CookieSet(c *gin.Context, userUID, token string) { }) http.SetCookie(c.Writer, &http.Cookie{ - Name: "user_uid", + Name: c.GetString("cookie_user"), Value: userUID, MaxAge: cookieMaxAge, Path: "/", diff --git a/server/internal/server.go b/server/internal/server.go index b1ca256e7..db177fda7 100644 --- a/server/internal/server.go +++ b/server/internal/server.go @@ -77,6 +77,23 @@ func Routes() *gin.Engine { ) r.Use(controllers.MiddlewareSetDB(db)) + r.Use(func(c *gin.Context) { + var cookieToken = "token" + var cookieUser = "user_uid" + + switch app.Config.ENV { + case app.EnvEnumProduction: + case app.EnvEnumAcceptance: + cookieToken += "_acc" + cookieUser += "_acc" + default: + cookieToken += "_dev" + cookieUser += "_dev" + } + c.Set("cookie_token", cookieToken) + c.Set("cookie_user", cookieUser) + }) + thr := throttle.Policy(&throttle.Quota{ Limit: 30, Within: 2 * time.Hour,