update
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
---
|
||||
plan_id: 20260712-1647-zapamietywanie-logowania
|
||||
title: Zapamiętywanie logowania przez 30 dni
|
||||
storage: plan-first
|
||||
legacy_phase: null
|
||||
created: 2026-07-12T16:47:19+02:00
|
||||
status: planned
|
||||
type: execute
|
||||
autonomous: true
|
||||
delegation: auto
|
||||
files_modified:
|
||||
- app/Database/Migrations/2026-07-12-160001_CreateRememberTokens.php
|
||||
- app/Models/RememberTokenModel.php
|
||||
- app/Controllers/Auth.php
|
||||
- app/Filters/AuthFilter.php
|
||||
- app/Views/auth/login.php
|
||||
- tests/unit/RememberTokenModelTest.php
|
||||
quality_radar: ok
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Cel
|
||||
Umożliwić użytkownikowi zaznaczenie opcji „Zapamiętaj mnie” podczas logowania i utrzymać dostęp przez 30 dni niezależnie na wielu komputerach.
|
||||
|
||||
## Powód
|
||||
Obecna sesja wygasa po 2 godzinach i nie przeżywa zamknięcia przeglądarki. Osobny token dla każdego urządzenia zachowuje równoległe logowania bez współdzielenia jednego identyfikatora sesji.
|
||||
|
||||
## Wynik
|
||||
Checkbox w formularzu, trwałe tokeny przechowywane w bazie wyłącznie jako skróty, automatyczne odtworzenie sesji oraz unieważnienie tokenu bieżącego urządzenia przy wylogowaniu.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Dokumenty projektu
|
||||
@.paul/PROJECT.md
|
||||
@.paul/STATE.md
|
||||
@.paul/config.md
|
||||
@.paul/codebase/impact_map.md
|
||||
@.paul/codebase/quality_risks.md
|
||||
|
||||
## Pliki źródłowe
|
||||
@app/Controllers/Auth.php
|
||||
@app/Filters/AuthFilter.php
|
||||
@app/Views/auth/login.php
|
||||
@app/Config/Routes.php
|
||||
@app/Config/Cookie.php
|
||||
@app/Config/Session.php
|
||||
</context>
|
||||
|
||||
<clarifications>
|
||||
- „Wiele komputerów jednocześnie” oznacza osobny aktywny token na każdym urządzeniu; kolejne logowanie nie usuwa wcześniejszych tokenów.
|
||||
- Wylogowanie usuwa token tylko z bieżącego urządzenia. Globalne „wyloguj wszędzie” jest poza zakresem.
|
||||
</clarifications>
|
||||
|
||||
<impact_scan>
|
||||
## Quality Radar
|
||||
|
||||
**Status:** ok
|
||||
**Narzędzia:** codebase-memory-mcp 0.6.1; jscpd i ast-grep wyłączone polityką projektu.
|
||||
|
||||
## Dotknięte obszary
|
||||
- Logowanie: `Auth::login`, `Auth::logout`, `app/Views/auth/login.php`.
|
||||
- Ochrona tras: `AuthFilter::before` odtwarza zwykłą sesję po poprawnym tokenie.
|
||||
- Dane: nowa tabela tokenów z wieloma rekordami; konto nadal pochodzi z `.env`.
|
||||
- Wdrożenie: nowa migracja wymaga ręcznego uruchomienia na hostido.
|
||||
|
||||
## Ryzyka duplikacji / wartości hardcoded
|
||||
- Czas 30 dni ma jedno źródło prawdy w `RememberTokenModel`.
|
||||
- Token cookie nie może być zapisany jawnie w bazie; tabela przechowuje selektor i hash walidatora.
|
||||
- Nie wydłużać globalnie `Session::$expiration`, bo nie zapewnia niezależnych urządzeń.
|
||||
|
||||
## Jawne odroczenia
|
||||
- Panel urządzeń i „wyloguj wszędzie” — dodać dopiero na żądanie.
|
||||
- Harmonogram czyszczenia — przy tej skali wygasłe tokeny wystarczy usuwać podczas użycia mechanizmu.
|
||||
</impact_scan>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Logowanie bez zapamiętania
|
||||
```gherkin
|
||||
Given użytkownik nie zaznaczył „Zapamiętaj mnie”
|
||||
When poda poprawny email i hasło
|
||||
Then otrzymuje wyłącznie obecną sesję bez trwałego cookie logowania
|
||||
```
|
||||
|
||||
## AC-2: Logowanie zapamiętane przez 30 dni
|
||||
```gherkin
|
||||
Given użytkownik zaznaczył „Zapamiętaj mnie”
|
||||
When poda poprawny email i hasło
|
||||
Then aplikacja zapisuje bezpieczny token i cookie ważne 30 dni
|
||||
And po utracie zwykłej sesji poprawny token odtwarza sesję i wpuszcza na chronioną trasę
|
||||
```
|
||||
|
||||
## AC-3: Wiele urządzeń
|
||||
```gherkin
|
||||
Given użytkownik zaznaczył opcję na dwóch urządzeniach
|
||||
When oba urządzenia otwierają chronioną trasę bez zwykłej sesji
|
||||
Then oba niezależne tokeny pozostają poprawne
|
||||
And wylogowanie na jednym urządzeniu nie unieważnia drugiego
|
||||
```
|
||||
|
||||
## AC-4: Odrzucenie nieważnego tokenu
|
||||
```gherkin
|
||||
Given cookie jest zmienione, wygasłe lub nie ma odpowiadającego rekordu
|
||||
When użytkownik otwiera chronioną trasę
|
||||
Then cookie i wadliwy rekord są usuwane w możliwym zakresie
|
||||
And użytkownik trafia na `/login`
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Dodać bezpieczne tokeny per urządzenie</name>
|
||||
<files>app/Database/Migrations/2026-07-12-160001_CreateRememberTokens.php, app/Models/RememberTokenModel.php</files>
|
||||
<action>Utworzyć tabelę z unikalnym selektorem, hashem walidatora, `expires_at` i timestampami. W modelu umieścić stałą 30 dni oraz operacje wystawienia tokenu przez `random_bytes`, weryfikacji przez `hash_equals`, usunięcia bieżącego tokenu i wygasłych rekordów. Każde logowanie dopisuje rekord.</action>
|
||||
<verify>php -l app/Database/Migrations/2026-07-12-160001_CreateRememberTokens.php; php -l app/Models/RememberTokenModel.php</verify>
|
||||
<done>AC-2, AC-3 i AC-4 mają trwały mechanizm danych bez jawnych sekretów w bazie.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Podłączyć checkbox, odtworzenie sesji i wylogowanie</name>
|
||||
<files>app/Controllers/Auth.php, app/Filters/AuthFilter.php, app/Views/auth/login.php</files>
|
||||
<action>Dodać checkbox `remember`. Po poprawnym logowaniu tworzyć cookie tylko po zaznaczeniu. W filtrze zachować obecną ścieżkę sesji, a przy jej braku zweryfikować cookie i ustawić `logged_in`/`user_email`. Cookie: HttpOnly, SameSite=Lax, 30 dni, Secure w produkcji. `logout()` usuwa token bieżącego cookie, cookie i sesję.</action>
|
||||
<verify>php -l app/Controllers/Auth.php; php -l app/Filters/AuthFilter.php; php -l app/Views/auth/login.php</verify>
|
||||
<done>AC-1..AC-4 są obsłużone w przepływie HTTP.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Sprawdzić bezpieczeństwo i równoległe urządzenia</name>
|
||||
<files>tests/unit/RememberTokenModelTest.php</files>
|
||||
<action>Dodać jeden mały test obejmujący dwa jednocześnie poprawne tokeny, odrzucenie zmienionego walidatora oraz unieważnienie jednego bez wpływu na drugi. Wykonać UAT w dwóch profilach przeglądarki.</action>
|
||||
<verify>vendor/bin/phpunit tests/unit/RememberTokenModelTest.php; ręcznie: dwa profile przeglądarki zgodnie z AC-1..AC-4</verify>
|
||||
<done>AC-1..AC-4 mają automatyczną kontrolę tokenów i potwierdzenie przepływu przeglądarkowego.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
## Nie zmieniać
|
||||
- Hasło i email nadal pochodzą z `.env`; nie tworzyć systemu wielu kont.
|
||||
- Nie zmieniać czasu zwykłej sesji ani chronionych tras.
|
||||
- Nie dotykać modułów finansów, inwestycji i paragonów.
|
||||
|
||||
## Ograniczenia zakresu
|
||||
- Bez nowej zależności, panelu urządzeń, resetu hasła i „wyloguj wszędzie”.
|
||||
- Bez surowego tokenu lub hasła w bazie i logach.
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
- [ ] `php -l` przechodzi dla zmienionych plików PHP.
|
||||
- [ ] `vendor/bin/phpunit tests/unit/RememberTokenModelTest.php` przechodzi w środowisku z `vendor/`.
|
||||
- [ ] UAT potwierdza zwykłe logowanie, 30-dniowe cookie, dwa profile, wylogowanie jednego profilu i odrzucenie zmienionego cookie.
|
||||
- [ ] Cookie ma HttpOnly, SameSite=Lax, właściwy termin i Secure na produkcji.
|
||||
- [ ] Migracja jest zastosowana ręcznie na zdalnej bazie przed wdrożeniem kodu.
|
||||
- [ ] Ryzyka Quality Radar są obsłużone lub jawnie odroczone.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Wszystkie AC przechodzą.
|
||||
- [ ] Weryfikacja jest kompletna.
|
||||
- [ ] Dwa urządzenia pozostają zalogowane niezależnie przez maksymalnie 30 dni.
|
||||
- [ ] Baza nie zawiera surowych tokenów.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
SUMMARY.md path: `.paul/plans/20260712-1647-zapamietywanie-logowania/SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user