mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Requirements: - parametres.php toggle: 'restricted_files_enabled' enables/disables the feature - Public TFE page: when enabled + access_type=Interne, hides files, shows French restriction message + access request form (metadata/synopsis still visible) - ERG emails (@erg.school / @erg.be): auto-approve, send 24h access link immediately - External emails: show justification textarea, create pending request, notify admin - Admin panel /admin/file-access.php: approve/reject requests with optional notes, sends access email on approval (linked from admin nav with pending count badge) Security: - One-time 24h email tokens (used_at + is_valid=0 on first click) - Token redeemed via POST /validate-access (GET shows confirmation page only) - Long-lived 30-day browser session in file_access_sessions table - Cookie: HttpOnly + Secure + SameSite=Strict - CSRF on all mutations, rate limiting on request submission - Audit trail: IP, UA, event, timestamp in file_access_audit Bug fixes: - admin/file-access.php: $vars never extract()ed → page was blank - Template had self-contained head/footer includes (double-include) - Admin approval URL used $requestId instead of $request['thesis_id'] - App::boot() now starts session so CSRF token works on public pages - Dispatcher routes /validate-access and /request-access through front controller
3.5 KiB
3.5 KiB
TFE Access Restriction Feature
Overview
Add access restriction for TFE attached files based on user email domain, with admin validation workflow.
Implementation Plan
1. Database Changes
- Add
restricted_files_enabledsetting to site_settings table - Create
file_access_requeststable- id, thesis_id, email, justification, status (pending/approved/rejected), admin_notes, created_at, approved_at, approved_by_admin_id
- Create
file_access_tokenstable (short-lived, one-time email links, 24h)- id, request_id, token (unique), expires_at, used_at (one-time mark)
- Create
file_access_sessionstable (long-lived browser sessions, 30 days)- id, request_id, session_token, expires_at, is_valid
- Create
file_access_audittable (IP, UA, timestamp on redemption)
2. Configuration
- Add
restricted_files_enabledcheckbox in parametres.php (Formulaire section) - Update settings.php action handler to persist the setting
3. Public TFE View (tfe.php) - Restricted Access UI
- TfeController checks restricted flag + access_type_id=2 + cookie session
- French text: "Accès restreint — Les fichiers attachés à ce TFE sont réservés aux utilisateurs autorisés."
- Request form: email input + conditional justification textarea (non-ERG only)
- JS: shows/hides justification textarea based on email domain (@erg.school / @erg.be)
- Form submits via fetch POST to /request-access.php with CSRF token
- Metadata, title, authors, synopsis all remain visible regardless of restriction
4. Email Flow
- @erg.school / @erg.be → auto-approve, generate 24h one-time token, send email immediately
- External email → create pending request, notify admin by email
- Admin approves → generate 24h token, send email to requester
- Email contains link to GET /validate-access (confirmation page) → POST to redeem
5. Secure Token Redemption
- One-time email token (24h, marked used_at on first click, is_valid=0)
- GET /validate-access → shows confirmation page (no side effects)
- POST /validate-access → redeems token (CSRF required), creates browser session cookie
- Cookie: HttpOnly; Secure; SameSite=Strict; 30 days
- Session stored in file_access_sessions (separate from one-time email token)
- TfeController checks file_access_sessions via hasValidCookieAccess()
- Audit trail: IP, User-Agent, timestamp in file_access_audit on every redemption attempt
6. Admin Panel - Access Requests Management
- Admin page: /admin/file-access.php (linked from admin nav with pending badge)
- List pending/approved/rejected requests with tab filters and pagination
- Approve dialog (with optional note) → sends 24h access email
- Reject dialog (with optional note)
- Bug fix: $vars was never extract()ed — page was blank
- Bug fix: template included head.php/header.php/footer.php itself (double-include)
- Bug fix: admin approval URL used $requestId instead of $request['thesis_id']
7. Security
- One-time use tokens (used_at + is_valid=0)
- POST-based redemption (token in hidden form field, not URL action)
- 256-bit random tokens, rate limiting on request submission (3/10min per IP)
- HttpOnly cookie + SameSite=Strict
- CSRF on all mutations
- Audit trail (IP, UA, event, timestamp)
- Short-lived email links (24h), long-lived browser sessions (30 days)
- App::boot() starts session for all public requests (CSRF token available everywhere)