- Utworzono autoload/autoloader.php (hybrydowy PSR-4 + legacy) - Zmigrowano 7 entry pointów do centralnego autoloadera - Dodano PSR-4 mapowanie w composer.json (Domain, Shared, Admin, Frontend) - Utworzono Shared\Email\Email (PHPMailer, migracja z Helpers) - Utworzono Shared\Security\CsrfToken (random_bytes + hash_equals) - Wrappery w Helpers delegują do nowych klas - Zaktualizowano docs/PROJECT_STRUCTURE.md - Inicjalizacja PAUL (.paul/) z roadmapą 19 faz refaktoryzacji Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
183 lines
6.7 KiB
Markdown
183 lines
6.7 KiB
Markdown
---
|
|
phase: 02-shared-email-security
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: ["01-01"]
|
|
files_modified:
|
|
- autoload/Shared/Email/Email.php
|
|
- autoload/Shared/Security/CsrfToken.php
|
|
- autoload/Shared/Helpers/Helpers.php
|
|
autonomous: true
|
|
delegation: off
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Utworzyć Shared\Email\Email i Shared\Security\CsrfToken wzorując się na shopPRO. Przenieść logikę z Helpers::send_email() i Helpers::get_token()/is_token_valid() do dedykowanych klas. Zachować wrappery w Helpers dla kompatybilności.
|
|
|
|
## Purpose
|
|
Email i Security to brakujące moduły Shared potrzebne przed refaktoryzacją Admin i Frontend kontrolerów. CsrfToken z kryptograficznie bezpiecznym tokenem zastąpi słaby sha1(mt_rand()).
|
|
|
|
## Output
|
|
- autoload/Shared/Email/Email.php — klasa email z PHPMailer
|
|
- autoload/Shared/Security/CsrfToken.php — CSRF z random_bytes + hash_equals
|
|
- Wrappery w Helpers.php delegujące do nowych klas
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
|
|
## Prior Work
|
|
@.paul/phases/01-infrastructure/01-01-SUMMARY.md — autoloader gotowy, PSR-4 działa
|
|
|
|
## Source Files
|
|
@autoload/Shared/Helpers/Helpers.php — zawiera send_email(), get_token(), is_token_valid()
|
|
|
|
## Reference
|
|
shopPRO autoload/Shared/Email/Email.php — docelowa implementacja
|
|
shopPRO autoload/Shared/Security/CsrfToken.php — docelowa implementacja
|
|
</context>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Email class
|
|
```gherkin
|
|
Given plik autoload/Shared/Email/Email.php istnieje
|
|
When załaduję klasę Shared\Email\Email
|
|
Then klasa ma metody: send(), email_check(), load_by_name()
|
|
And send() używa PHPMailer do wysyłki maili
|
|
```
|
|
|
|
## AC-2: CsrfToken class
|
|
```gherkin
|
|
Given plik autoload/Shared/Security/CsrfToken.php istnieje
|
|
When załaduję klasę Shared\Security\CsrfToken
|
|
Then klasa ma statyczne metody: getToken(), validate(), regenerate()
|
|
And getToken() używa bin2hex(random_bytes(32))
|
|
And validate() używa hash_equals() (timing-safe)
|
|
```
|
|
|
|
## AC-3: Wrappery w Helpers
|
|
```gherkin
|
|
Given Helpers::send_email() i Helpers::get_token() nadal istnieją
|
|
When wywołam je z istniejącego kodu
|
|
Then delegują do nowych klas (Shared\Email\Email i Shared\Security\CsrfToken)
|
|
And istniejący kod działa bez zmian
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Utworzenie Shared\Email\Email</name>
|
|
<files>autoload/Shared/Email/Email.php</files>
|
|
<action>
|
|
Utworzyć klasę Email wzorowaną na shopPRO:
|
|
- namespace Shared\Email
|
|
- Właściwość $table = 'pp_newsletter_templates'
|
|
- Właściwość $text (treść maila), $headers, $newsletter_headers, $newsletter_footers
|
|
- Metoda load_by_name(string $name) — ładuje szablon z DB
|
|
- Metoda email_check($email) — walidacja filter_var
|
|
- Metoda send(string $email, string $subject, bool $newsletter_headers = false, string $file = null)
|
|
- Używa PHPMailer (require_once z libraries/)
|
|
- Regex do naprawy relatywnych URL w obrazkach/linkach
|
|
- Obsługa załączników
|
|
- Return $mail->Send()
|
|
|
|
WAŻNE: Sprawdzić w Helpers.php jak wygląda obecna implementacja send_email()
|
|
i przenieść tę logikę do nowej klasy, dostosowując do wzorca shopPRO.
|
|
PHP < 8.0 — brak named args, union types, match.
|
|
</action>
|
|
<verify>Sprawdzić że plik istnieje, ma namespace Shared\Email, klasę Email z metodami send(), email_check()</verify>
|
|
<done>AC-1 satisfied: Email class z PHPMailer</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Utworzenie Shared\Security\CsrfToken</name>
|
|
<files>autoload/Shared/Security/CsrfToken.php</files>
|
|
<action>
|
|
Utworzyć klasę CsrfToken wzorowaną na shopPRO:
|
|
- namespace Shared\Security
|
|
- const SESSION_KEY = 'csrf_token'
|
|
- static getToken(): string
|
|
- Jeśli brak tokenu w sesji → generuje bin2hex(random_bytes(32))
|
|
- Zapisuje w $_SESSION[self::SESSION_KEY]
|
|
- Zwraca token
|
|
- static validate(string $token): bool
|
|
- Porównuje z $_SESSION[self::SESSION_KEY] używając hash_equals()
|
|
- Return true/false (NIE usuwać tokenu po walidacji — to robi regenerate())
|
|
- static regenerate(): void
|
|
- Wymusza nowy token: unset($_SESSION[self::SESSION_KEY])
|
|
|
|
PHP < 8.0 — brak named args, union types, match.
|
|
</action>
|
|
<verify>Sprawdzić że plik istnieje, ma namespace Shared\Security, klasę CsrfToken z metodami getToken(), validate(), regenerate()</verify>
|
|
<done>AC-2 satisfied: CsrfToken z random_bytes + hash_equals</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Wrappery w Helpers.php</name>
|
|
<files>autoload/Shared/Helpers/Helpers.php</files>
|
|
<action>
|
|
W klasie Helpers:
|
|
1. Metoda send_email() — zamienić ciało na delegację:
|
|
$email = new \Shared\Email\Email();
|
|
$email->text = $text;
|
|
return $email->send($to, $subject, false, $file);
|
|
2. Metoda get_token() — zamienić ciało na delegację:
|
|
return \Shared\Security\CsrfToken::getToken();
|
|
3. Metoda is_token_valid() — zamienić ciało na delegację:
|
|
return \Shared\Security\CsrfToken::validate($token);
|
|
|
|
Zachować sygnatury metod identyczne — żaden calling code się nie zmienia.
|
|
NIE usuwać metod — to wrappery dla kompatybilności wstecznej.
|
|
NIE zmieniać żadnych innych metod w Helpers.
|
|
</action>
|
|
<verify>Sprawdzić że Helpers::send_email(), get_token(), is_token_valid() delegują do nowych klas</verify>
|
|
<done>AC-3 satisfied: Wrappery delegują, istniejący kod działa bez zmian</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- autoload/Domain/* (nie ruszać repositories)
|
|
- autoload/Shared/Cache/* (nie ruszać)
|
|
- autoload/Shared/Html/* (nie ruszać)
|
|
- autoload/Shared/Image/* (nie ruszać)
|
|
- autoload/Shared/Tpl/* (nie ruszać)
|
|
- config.php, libraries/* (nie ruszać)
|
|
|
|
## SCOPE LIMITS
|
|
- Tylko Email i Security — nie refaktoryzować innych metod Helpers
|
|
- Nie zmieniać callerów (admin/, front/) — oni nadal używają Helpers::
|
|
- Nie dodawać nowych zależności poza tym co już jest w libraries/
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] autoload/Shared/Email/Email.php istnieje z namespace Shared\Email
|
|
- [ ] autoload/Shared/Security/CsrfToken.php istnieje z namespace Shared\Security
|
|
- [ ] Helpers::send_email() deleguje do Email class
|
|
- [ ] Helpers::get_token() deleguje do CsrfToken::getToken()
|
|
- [ ] Helpers::is_token_valid() deleguje do CsrfToken::validate()
|
|
- [ ] Żadne inne metody w Helpers nie zostały zmienione
|
|
- All acceptance criteria met
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Email i CsrfToken klasy utworzone z poprawnymi namespace'ami
|
|
- Wrappery w Helpers zachowują kompatybilność wsteczną
|
|
- Zero regresji — istniejący kod używający Helpers:: działa bez zmian
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/02-shared-email-security/02-01-SUMMARY.md`
|
|
</output>
|