Commit Graph

26 Commits

Author SHA1 Message Date
Pontoporeia
19784090a3 fix: pass PHP upload limits via -d flags in justfile serve recipe
php -S (built-in dev server) ignores .htaccess and .user.ini entirely.
The POST Content-Length limit was still 8M from /etc/php/php.ini.
Pass upload_max_filesize=512M, post_max_size=520M, memory_limit=256M,
max_execution_time=300, max_input_time=300 directly on the CLI.
2026-05-05 11:04:52 +02:00
Pontoporeia
6a37d21f3f docs: add file-uploads.md — accepted types, limits, storage, ordering, security 2026-05-05 11:04:52 +02:00
Pontoporeia
2188ff5479 docs: add SMTP 550 postfix fix report for mail admin 2026-05-05 11:04:52 +02:00
Pontoporeia
ab51bf3a66 fix: deploy-server.sh cleans up legacy posterg configs and prunes old xamxam backups 2026-05-05 11:04:52 +02:00
Pontoporeia
1b02ccb1d5 fix: mark languages as required, add required-field visual indicators on both forms
- checkbox-list.php: support $required prop → adds required + aria-required on fieldset
- add.php: languages checkbox now marked required (matches server-side validation)
- partage/index.php: same for student form
- admin.css: dashed border on required inputs, bold labels, red asterisk via :has(), "Champs obligatoires" note
- Both forms now show "* Champs obligatoires" note at top

Server-side required fields = titre, auteurice, synopsis, année, orientation, ap, finality, languages (≥1), access_type_id, confirmation_email. All now have required attribute + visual asterisk.
2026-04-20 16:19:55 +02:00
Pontoporeia
75f808bee4 feat: extract MediaController, wire into Dispatcher, delete media.php 2026-04-20 12:32:00 +02:00
Pontoporeia
c4705f6265 docs: add bookmarklet for auto-filling TFE test form
- bookmark.md with draggable link + readable source + lookup table reference
- all field selectors match actual form name attributes and schema IDs
2026-04-15 14:24:44 +02:00
Pontoporeia
f4aba500e6 feat: student mode support for thanks page (admin-auth only)
- add hidden student_mode field in add.php form
- pass mode=student through redirect to thanks.php in formulaire.php
- thanks.php renders clean student thank-you page (no header, centered button)
- add CSS for .thanks-student-page, .btn-new-form, .thanks-success, .thanks-error
- admin auth always required; student mode is purely UI variant on the physical machine
2026-04-15 14:24:44 +02:00
Pontoporeia
3cd96ed28a Deduplicate and standardise documentation
- Consolidate 36 markdown files → 14 (plus TODO.md)
- Merge overlapping docs into authoritative files:
  - database.md (from DATABASE_SPECIFICATION + QUICK_SCHEMA_REFERENCE + DATABASE_CONFIG + SETUP)
  - deployment.md (from SERVER_SETUP + COMPLETE_DEPLOYMENT_GUIDE + DEPLOYMENT_STEPS)
  - security.md (from SECURITY_ANALYSIS + TODO.SECURITY)
  - development.md (from DEVELOPMENT_GUIDE + LIVE_RELOAD_SETUP + TEST_CENTRALIZATION)
  - migration-history.md (from 11 past migration docs)
- Standardise all filenames to lowercase
- Remove non-doc files (Context.md research notes, chat export)
- Remove superseded docs (SECURITY.md pre-SQLite, SECURITY_IMPLEMENTATION, README_SECURE_SEARCH)
- Fix stale cross-references
2026-04-15 14:24:44 +02:00
Théophile Gervreau-Mercier
5c5054d744 Investigating VM crash 2026-04-13 11:12:12 +02:00
Pontoporeia
480451aa2b replace EasyMDE (333KB) with OverType (118KB) in pages-edit.php
- Remove easymde.min.js (320KB) and easymde.min.css (13KB)
- Vendor overtype.min.js (118KB, v2.3.5)
- Replace <textarea name=content> + 60-line toolbar/SVG init with:
  - <input type=hidden name=content> for form submission
  - <div id=editor> as OverType mount target
  - 6-line init: value from hidden input, onChange syncs it back
- Net saving: ~215KB assets, ~54 lines of inline JS
2026-04-06 15:33:08 +02:00
Pontoporeia
bf2594112b fix serve recipe: filter output to Development Server start + [200] requests only
refactor: unify CSS color variables across public and admin

- Replace old variable structure with new standardized naming:
  - Background: --bg-primary, --bg-secondary, --bg-tertiary, --bg-active
  - Text: --text-primary, --text-secondary, --text-tertiary
  - Border: --border-primary, --border-secondary
  - Status: --success, --error, --warning
  - Accent: --accent-primary, --accent-secondary, --accent-foreground, --accent-muted
- Remove admin-specific color variables (--admin-*)
- Update all CSS files to use shared variables:
  - variables.css, common.css, main.css, admin.css
  - tfe.css, search.css, apropos.css, system.css, colors.css
2026-04-02 17:22:51 +02:00
Pontoporeia
2ec5a7f38f docs: ORM assessment — verdict: keep raw PDO, no ORM needed 2026-03-28 13:49:51 +01:00
Pontoporeia
7208292c0e deploy-nginx: add recipe, upload scripts to /tmp, print sudo instructions 2026-03-02 16:08:45 +01:00
Pontoporeia
e4b2205eac fix rsync permissions: setup-server.sh with setgid dirs, exclude .claude/.pi 2026-03-02 16:08:45 +01:00
Pontoporeia
52978aa658 ops: simplify justfile, guard deploy-db, extract scripts, fix .gitignore 2026-03-02 16:08:45 +01:00
Théophile Gervreau-Mercier
87971f9c23 refactor: extract templates from public/
- Created /templates for main site (header.php, footer.php)
- Created /templates/admin for admin section (head.php, footer.php)
- Removed /public/includes and /public/admin/inc
- Updated all references in code and docs
- Tests passing 

Cleaner separation: /public only contains web-accessible files (PHP entry points + assets)
2026-02-12 12:15:41 +01:00
Théophile Gervreau-Mercier
7fca85d1c1 refactor: rename database → storage
More semantically accurate: contains SQLite files, schema, fixtures, test data.
Updated all references in code, scripts, docs.
2026-02-12 12:12:58 +01:00
Théophile Gervreau-Mercier
0e4921583e refactor: reorganize to standard PHP structure
- Moved /lib → /src (PHP source code)
- Moved /includes → /public/includes (main site templates)
- Admin section remains self-contained in /public/admin with its own /inc
- Updated all require/include paths across codebase
- Updated config/bootstrap.php, justfile, tests, docs
- All tests passing 

Structure now follows PHP best practices:
  /config      - Configuration files
  /database    - SQLite database + schema
  /docs        - Documentation (intact)
  /nginx       - Server config (intact)
  /public      - Web-accessible files (entry point)
    /admin     - Self-contained admin interface
    /assets    - CSS, fonts, icons
    /includes  - Main site templates (header/footer)
  /scripts     - Deployment scripts (intact)
  /src         - PHP source classes (Database, AdminAuth, RateLimit)
  /tests       - Test suites
2026-02-12 12:11:16 +01:00
Théophile Gervreau-Mercier
8613f71112 security: add PHP session auth guard for admin panel (item #2, CRITICAL)
- lib/AdminAuth.php: new class with requireLogin(), login(), logout(),
  isAuthenticated(); starts session with hardened cookie params
  (HttpOnly, SameSite=Strict, Secure, Path=/admin) — also resolves
  item #8 (session cookie hardening)
- requireLogin() auto-authenticates from nginx Basic Auth credentials
  ($_SERVER['PHP_AUTH_PW']) so the user only sees one browser prompt;
  falls back to /admin/login.php if the proxy is absent/misconfigured
- config/admin_credentials.php: gitignored credential store; define
  ADMIN_PASSWORD_HASH with a bcrypt hash to enable PHP auth
- config/admin_credentials.example.php: template for the above
- config/bootstrap.php: auto-loads admin_credentials.php if present
- .gitignore: exclude config/admin_credentials.php
- public/admin/login.php: fallback login form (shown only when nginx
  Basic Auth is bypassed / proxy absent)
- public/admin/logout.php: session destruction + redirect to login
- All 7 admin PHP files: replace session_start() with
  AdminAuth::requireLogin() (defence-in-depth behind nginx Basic Auth)
- public/admin/inc/head.php: Déconnexion button when ADMIN_PASSWORD_HASH
  is defined
- nginx/PHP_AUTH_LAYER.md: documents dual-auth architecture, UX flow,
  and setup instructions
- docs/TODO.SECURITY.md: items #2 and #8 moved to Resolved; priority
  order updated (all CRITICAL done)
2026-02-08 14:22:45 +01:00
Théophile Gervreau-Mercier
a2b1ff5f41 security: fix all HIGH priority items from TODO.SECURITY.md
Items resolved:
- #3 (HIGH): Move file uploads outside webroot to STORAGE_ROOT (/var/www/posterg/storage).
  Uploads were previously stored in public/admin/actions/data/ which is web-accessible.
- #4 (HIGH): Align file paths and add media.php controller.
  DB paths are now storage-relative (theses/YEAR/ID/file, covers/file).
  New public/media.php serves files with path-traversal jail, MIME allow-list,
  and proper caching headers. memoire.php and search.php updated to use /media.php?path=.
  Also fixed: cover images were never recorded in thesis_files (broken INSERT).
- #5 (HIGH): RateLimit::getClientIdentifier() now uses REMOTE_ADDR only.
  HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP are attacker-controlled headers that
  allowed unlimited rate-limit bypass by rotating spoofed IPs.
- #6 (HIGH): Port public/admin/.htaccess security rules to nginx/posterg.conf.
  Apache .htaccess directives are silently ignored by nginx; none were active.
  CSP added to /admin/ location block, .log file denial added globally,
  autoindex off made explicit. Documented in nginx/HTACCESS_TO_NGINX.md.

Supporting changes:
- config/bootstrap.php: add STORAGE_ROOT constant
- nginx/SECURITY_HEADERS.md: updated to reflect admin CSP and pending public CSP
- docs/TODO.SECURITY.md: items #3-6 moved to resolved; priority order updated
2026-02-08 14:01:45 +01:00
Théophile Gervreau-Mercier
f5d3281c43 security: fix all LOW priority items from TODO.SECURITY.md
Item 13 — Remove deprecated X-XSS-Protection header
- nginx/posterg.conf: header removed (was '1; mode=block')
- nginx/SECURITY_HEADERS.md: new file documenting header decisions
  and explaining why X-XSS-Protection is counterproductive

Item 14 — Add rel="noreferrer" to external target="_blank" link
- public/admin/thanks.php: rel="noopener" → rel="noopener noreferrer"

Item 15 — Explicit (int) casts on all integer HTML outputs
- public/index.php: (int) on item id, page numbers
- public/search.php: (int) on totalItems, year options, item id, pagination

Item 16 — Remove unused DATABASE_PATH constant
- config/bootstrap.php: define('DATABASE_PATH', ...) removed

docs/TODO.SECURITY.md updated: items 13-16 marked resolved and
moved to the  Resolved section.
2026-02-08 13:54:02 +01:00
Théophile Gervreau-Mercier
4bbbc58e24 Fix admin CSS not loading and quirks mode issues
Fixed multiple issues in admin panel:

1. CSS path: modern-normalize.css → modern-normalize.min.css
   (File is actually named .min.css)

2. Icon path: assets/icon.svg → /assets/admin_favicon.svg
   (Was relative, now absolute; correct filename)

3. Navigation: /admin/list.php → /admin/
   (list.php was renamed to index.php)

4. Short PHP tags: <? → <?php
   (Better compatibility, some servers don't enable short_open_tag)

5. Quirks mode warning was due to CSS not loading, not DOCTYPE
   (DOCTYPE was already present)

Files modified:
- public/admin/inc/head.php (main fixes)
- public/admin/index.php (short tags)
- public/admin/add.php (short tags)
- public/admin/import.php (short tags)

Need to redeploy for production: just deploy
2026-02-06 13:26:24 +01:00
Théophile Gervreau-Mercier
d2b3c6ca67 Major refactor
- update the structure to have monolithic setup
- updated deployments
- added live-reloading for devops
2026-02-05 20:16:19 +01:00
Théophile Gervreau-Mercier
f23fbb481b Nginx config, working deploy, basic theme, repo cleanup 2026-02-05 17:37:07 +01:00
Théophile Gervreau-Mercier
2cb5436647 Added Claude assessements 2026-02-02 18:56:12 +01:00