From c765c92f895409d17ec2d26af3de117cf49ed56e Mon Sep 17 00:00:00 2001 From: Pc Date: Sun, 4 Jan 2026 13:56:00 +0100 Subject: [PATCH] feat: added cookies to use subdomains --- kittyurl-frontend/package-lock.json | 18 +++++++++++ kittyurl-frontend/package.json | 2 ++ .../src/context/AuthProvider.tsx | 30 +++++++++++-------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/kittyurl-frontend/package-lock.json b/kittyurl-frontend/package-lock.json index 55afc83..ae2e640 100644 --- a/kittyurl-frontend/package-lock.json +++ b/kittyurl-frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.18", "axios": "^1.13.2", + "js-cookie": "^3.0.5", "js-sha512": "^0.9.0", "lucide-react": "^0.562.0", "react": "^19.2.0", @@ -18,6 +19,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.1", + "@types/js-cookie": "^3.0.6", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", @@ -1588,6 +1590,13 @@ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3007,6 +3016,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-sha512": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.9.0.tgz", diff --git a/kittyurl-frontend/package.json b/kittyurl-frontend/package.json index 50fde4f..7057741 100644 --- a/kittyurl-frontend/package.json +++ b/kittyurl-frontend/package.json @@ -13,6 +13,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.18", "axios": "^1.13.2", + "js-cookie": "^3.0.5", "js-sha512": "^0.9.0", "lucide-react": "^0.562.0", "react": "^19.2.0", @@ -21,6 +22,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.1", + "@types/js-cookie": "^3.0.6", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", diff --git a/kittyurl-frontend/src/context/AuthProvider.tsx b/kittyurl-frontend/src/context/AuthProvider.tsx index 87d4abf..9dc0b99 100644 --- a/kittyurl-frontend/src/context/AuthProvider.tsx +++ b/kittyurl-frontend/src/context/AuthProvider.tsx @@ -1,8 +1,12 @@ import { useState, useCallback, type ReactNode } from 'react'; +import Cookies from 'js-cookie'; // Importujemy bibliotekę do ciasteczek import { AuthContext } from './AuthContext'; import { sha512 } from '../utils/crypto'; import type { AuthResponse } from '../types/auth'; +const TOKEN_KEY = 'ktty_shared_token'; +const PARENT_DOMAIN = '.ktty.is'; // Kropka na początku pozwala na dostęp ze wszystkich subdomen + const getSubdomain = (): string | null => { const hostname = window.location.hostname; const parts = hostname.split('.'); @@ -12,9 +16,9 @@ const getSubdomain = (): string | null => { export function AuthProvider({ children }: { children: ReactNode }) { const subdomain = getSubdomain(); - const storageKey = subdomain ? `ktty_token_${subdomain}` : 'ktty_token'; - const [token, setToken] = useState(sessionStorage.getItem(storageKey)); + // Pobieramy token z ciasteczka zamiast z sessionStorage + const [token, setToken] = useState(Cookies.get(TOKEN_KEY) || null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -24,9 +28,6 @@ export function AuthProvider({ children }: { children: ReactNode }) { try { const hashedPassword = await sha512(pass); - - // POPRAWKA: Ścieżka URL jest stała, zgodna z Twoim API. - // Vite Proxy przechwyci '/api' i skieruje to na https://www.ktty.is const fullUrl = `/api/v1/user/${endpoint}`; const response = await fetch(fullUrl, { @@ -34,7 +35,6 @@ export function AuthProvider({ children }: { children: ReactNode }) { headers: { 'accept': 'application/json', 'Content-Type': 'application/json', - // Subdomenę przekazujemy w nagłówku, aby backend wiedział, który to klient 'X-Subdomain': subdomain || '', }, body: JSON.stringify({ name, password: hashedPassword, ttl: 86400 }), @@ -43,12 +43,17 @@ export function AuthProvider({ children }: { children: ReactNode }) { const data: AuthResponse = await response.json(); if (!response.ok) { - const errorMsg = data?.error || data?.message || `Błąd serwera: ${response.status}`; - throw new Error(errorMsg); + throw new Error(data?.error || data?.message || 'Błąd logowania'); } if (data?.token) { - sessionStorage.setItem(storageKey, data.token); + // ZAPISYWANIE CIASTECZKA DLA WSZYSTKICH SUBDOMEN + Cookies.set(TOKEN_KEY, data.token, { + domain: PARENT_DOMAIN, + expires: 1, // 1 dzień + secure: true, // Wymagane dla HTTPS + sameSite: 'lax' + }); setToken(data.token); } return data; @@ -60,12 +65,13 @@ export function AuthProvider({ children }: { children: ReactNode }) { } finally { setLoading(false); } - }, [subdomain, storageKey]); + }, [subdomain]); const logout = useCallback(() => { - sessionStorage.removeItem(storageKey); + // Usuwamy ciasteczko z domeny nadrzędnej + Cookies.remove(TOKEN_KEY, { domain: PARENT_DOMAIN }); setToken(null); - }, [storageKey]); + }, []); return (