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>
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
plan_id: 20260712-1647-zapamietywanie-logowania
|
||||
title: Zapamiętywanie logowania przez 30 dni
|
||||
completed: 2026-07-12T17:31:28+02:00
|
||||
storage: plan-first
|
||||
quality_radar: degraded
|
||||
---
|
||||
|
||||
# Summary: Zapamiętywanie logowania przez 30 dni
|
||||
|
||||
## Objective
|
||||
|
||||
Dodano opcjonalne logowanie zapamiętane przez 30 dni z niezależnym tokenem dla każdego komputera.
|
||||
|
||||
## What Was Built
|
||||
|
||||
| Area | Result |
|
||||
|------|--------|
|
||||
| Dane | Tabela `remember_tokens` z selektorem, hashem walidatora i terminem ważności; tabela utworzona również na zdalnej bazie. |
|
||||
| Logowanie | Checkbox `remember` wystawia 30-dniowe cookie tylko po zaznaczeniu. |
|
||||
| Ochrona tras | `AuthFilter` odtwarza zwykłą sesję z poprawnego tokenu. |
|
||||
| Wylogowanie | Usuwa token wyłącznie bieżącego urządzenia, cookie i sesję. |
|
||||
| Test | Dodano jeden test dwóch tokenów, manipulacji walidatorem i selektywnego unieważnienia. |
|
||||
|
||||
## Files Modified
|
||||
|
||||
- `app/Database/Migrations/2026-07-12-160001_CreateRememberTokens.php` — schemat tokenów.
|
||||
- `app/Models/RememberTokenModel.php` — wystawianie, weryfikacja i usuwanie tokenów.
|
||||
- `app/Controllers/Auth.php` — wystawianie cookie i selektywne wylogowanie.
|
||||
- `app/Filters/AuthFilter.php` — odtworzenie sesji.
|
||||
- `app/Views/auth/login.php` — checkbox „Zapamiętaj mnie”.
|
||||
- `tests/unit/RememberTokenModelTest.php` — kontrola logiki wielu urządzeń.
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Evidence |
|
||||
|-----------|--------|----------|
|
||||
| AC-1 | Pass | Bez checkboxa `Auth::login` nie wystawia trwałego cookie. |
|
||||
| AC-2 | Partial | Kod, cookie 30 dni i zdalna tabela są gotowe; brak potwierdzonego końcowego UAT po migracji. |
|
||||
| AC-3 | Partial | Model dopisuje niezależne rekordy, a logout usuwa bieżący selektor; test nie został uruchomiony lokalnie. |
|
||||
| AC-4 | Partial | Filtr odrzuca zły/wygasły token i usuwa cookie; test nie został uruchomiony lokalnie. |
|
||||
|
||||
## Verification Results
|
||||
|
||||
| Check | Result | Notes |
|
||||
|-------|--------|-------|
|
||||
| `php -l` dla 6 plików | Pass | Brak błędów składni. |
|
||||
| `vendor/bin/phpunit tests/unit/RememberTokenModelTest.php` | Skipped | Lokalnie brak `vendor/` i `vendor/bin/phpunit`. |
|
||||
| Zdalny `remember_tokens` | Pass | Potwierdzono 6 kolumn i 3 indeksy. |
|
||||
| UAT w dwóch profilach | Skipped | Niepotwierdzony przez użytkownika po aktualizacji bazy. |
|
||||
|
||||
## Quality Radar Results
|
||||
|
||||
**Status:** degraded
|
||||
|
||||
- New risks: wdrożenie kodu przed migracją powoduje błąd DB przy użyciu tokenu.
|
||||
- Resolved risks: zdalna tabela została utworzona; surowy walidator nie trafia do bazy.
|
||||
- Deferred risks: test PHPUnit i UAT dwóch profili — środowisko lokalne nie ma `vendor/`, UAT wymaga potwierdzenia przeglądarkowego.
|
||||
- Raw outputs: `.paul/codebase/radar/codebase-memory-post-apply.txt`.
|
||||
|
||||
## Deviations
|
||||
|
||||
- PHPUnit nie został uruchomiony lokalnie; wykonano lint pliku testowego.
|
||||
- UAT w dwóch profilach nie został potwierdzony przed UNIFY.
|
||||
- Legacy `ROADMAP.md` pominięto w trybie plan-first. Commit fazowy pominięto zgodnie z `preferences.auto_commit: false` oraz z powodu licznych niezwiązanych zmian w working tree.
|
||||
|
||||
## Key Decisions / Patterns
|
||||
|
||||
- Osobny token per urządzenie zamiast wydłużania globalnej sesji.
|
||||
- W bazie przechowywany jest wyłącznie hash walidatora.
|
||||
- Wylogowanie nie usuwa tokenów innych urządzeń.
|
||||
|
||||
## Follow-up
|
||||
|
||||
- Jednorazowo potwierdzić logowanie w dwóch profilach, zamknięcie sesji i wylogowanie tylko jednego profilu.
|
||||
Reference in New Issue
Block a user