diff --git a/config/bootstrap.php b/config/bootstrap.php index 7fb9e24..4327e68 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -25,7 +25,7 @@ if (php_sapi_name() === 'cli-server') { // Simple helper function for including templates function include_template($name) { - $path = APP_ROOT . '/includes/' . $name; + $path = APP_ROOT . '/public/includes/' . $name; if (file_exists($path)) { include $path; } diff --git a/docs/DEPLOYMENT_STEPS.md b/docs/DEPLOYMENT_STEPS.md index d33b500..a3f2a9e 100644 --- a/docs/DEPLOYMENT_STEPS.md +++ b/docs/DEPLOYMENT_STEPS.md @@ -25,7 +25,7 @@ This deploys all files to `/var/www/posterg/`: - `includes/` → `/var/www/posterg/includes/` - `config/` → `/var/www/posterg/config/` - `database/` → `/var/www/posterg/database/` -- `lib/` → `/var/www/posterg/lib/` +- `src/` → `/var/www/posterg/lib/` ### 3. Update Nginx Configuration diff --git a/docs/DEVELOPMENT_GUIDE.md b/docs/DEVELOPMENT_GUIDE.md index 4146c5f..ad38940 100644 --- a/docs/DEVELOPMENT_GUIDE.md +++ b/docs/DEVELOPMENT_GUIDE.md @@ -130,7 +130,7 @@ just fixtures ### Create a New Page 1. Create `newpage.php` in root -2. Add `require_once __DIR__ . '/lib/Database.php';` +2. Add `require_once __DIR__ . '/src/Database.php';` 3. Include header: `include 'inc/header.php';` 4. Add your content 5. Include footer: `include 'inc/footer.php';` @@ -138,7 +138,7 @@ just fixtures Example: ```php @@ -154,7 +154,7 @@ include 'inc/header.php'; ### Add a Database Function -1. Edit `lib/Database.php` +1. Edit `src/Database.php` 2. Add your method to the `Database` class 3. Write a test in `tests/Unit/DatabaseTest.php` 4. Run tests: `just test-unit` @@ -215,7 +215,7 @@ See `tests/README.md` for complete testing guide. **Quick example:** ```php > .gitignore | `apps/public/inc/header.php` | `inc/header.php` | | `apps/public/assets/posterg.css` | `assets/posterg.css` | | `apps/admin/index.php` | `admin/index.php` | -| `shared/Database.php` | `lib/Database.php` | -| `shared/config.php` | `lib/config.php` | -| `shared/cache/` | `lib/cache/` | +| `shared/Database.php` | `src/Database.php` | +| `shared/config.php` | `src/config.php` | +| `shared/cache/` | `src/cache/` | ## Deployment Changes diff --git a/docs/SECURITY_ANALYSIS.md b/docs/SECURITY_ANALYSIS.md index 3bbad01..f8ba87d 100644 --- a/docs/SECURITY_ANALYSIS.md +++ b/docs/SECURITY_ANALYSIS.md @@ -138,7 +138,7 @@ and serve files through a dedicated PHP endpoint that validates access rights. ### 5. Rate Limiter Vulnerable to IP Spoofing -**File:** `lib/RateLimit.php` — method `getClientIdentifier()` +**File:** `src/RateLimit.php` — method `getClientIdentifier()` ```php if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { @@ -373,7 +373,7 @@ define('DATABASE_PATH', APP_ROOT . '/database/test.db'); ``` This constant is never used anywhere. `Database.php` uses `getDatabasePath()` from -`lib/config.php`. The duplicate creates confusion about which configuration is +`src/config.php`. The duplicate creates confusion about which configuration is authoritative and could lead to future bugs if someone uses the wrong one. **Fix:** Remove the `DATABASE_PATH` define from `bootstrap.php`. diff --git a/docs/SIMPLIFICATION.md b/docs/SIMPLIFICATION.md index f2fbb18..34aa9f2 100644 --- a/docs/SIMPLIFICATION.md +++ b/docs/SIMPLIFICATION.md @@ -111,7 +111,7 @@ include APP_ROOT . '/includes/header.php'; |---------|-------------|----------------------------| | Purpose | Reusable library | Single website | | Structure | Complex (PSR-4, namespaces) | Simple (includes, classes) | -| Directories | `src/`, `resources/`, `var/`, `bin/` | `public/`, `includes/`, `lib/` | +| Directories | `src/`, `resources/`, `var/`, `bin/` | `public/`, `includes/`, `src/` | | Autoloading | PSR-4 namespaces | Simple require statements | | Config | Complex bootstrap with many constants | Minimal bootstrap | | Caching | `var/cache/` with framework | Simple file-based if needed | diff --git a/docs/TODO.SECURITY.md b/docs/TODO.SECURITY.md index ecdf10b..b6e2e8f 100644 --- a/docs/TODO.SECURITY.md +++ b/docs/TODO.SECURITY.md @@ -14,7 +14,7 @@ | 1 | No HTTPS — admin credentials exposed in transit | 🔴 CRITICAL | **TLS is terminated upstream by the reverse proxy** (outside nginx). nginx.conf does not need to handle TLS directly. | | 3 | Uploaded files stored inside the webroot | 🟠 HIGH | Storage moved to `STORAGE_ROOT` (`/var/www/posterg/storage/`), defined in `config/bootstrap.php`. `formulaire.php` updated. | | 4 | File path mismatch — media files broken and insecure | 🟠 HIGH | DB paths are now storage-relative (`theses/YEAR/ID/file`, `covers/file`). New controller `public/media.php` serves files safely. `memoire.php` and `search.php` updated to use `/media.php?path=…`. Cover recording in `formulaire.php` fixed (was never inserted into DB). | -| 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `lib/RateLimit.php` `getClientIdentifier()` now uses `REMOTE_ADDR` only. | +| 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `src/RateLimit.php` `getClientIdentifier()` now uses `REMOTE_ADDR` only. | | 6 | `.htaccess` security rules silently ignored by nginx | 🟠 HIGH | All rules ported to `nginx/posterg.conf` (CSP to `/admin/` block, `.log` denial, `autoindex off`). See `nginx/HTACCESS_TO_NGINX.md`. | | 13 | Deprecated `X-XSS-Protection` header | 🔵 LOW | **Removed** from `nginx/posterg.conf`; see `nginx/SECURITY_HEADERS.md` for rationale. | @@ -49,7 +49,7 @@ | # | Issue | Severity | Resolution | |---|-------|----------|------------| -| 2 | No PHP-level authentication in admin panel | 🔴 CRITICAL | `lib/AdminAuth.php` implements a session guard with `password_verify` + `session_regenerate_id`. All admin PHP files now call `AdminAuth::requireLogin()` instead of bare `session_start()`. Credentials stored in gitignored `config/admin_credentials.php` (define `ADMIN_PASSWORD_HASH`). No-op when constant is absent (dev / cli-server). Also resolves item #8 (session cookie hardening via `session_set_cookie_params` before `session_start`). See `nginx/PHP_AUTH_LAYER.md`. | +| 2 | No PHP-level authentication in admin panel | 🔴 CRITICAL | `src/AdminAuth.php` implements a session guard with `password_verify` + `session_regenerate_id`. All admin PHP files now call `AdminAuth::requireLogin()` instead of bare `session_start()`. Credentials stored in gitignored `config/admin_credentials.php` (define `ADMIN_PASSWORD_HASH`). No-op when constant is absent (dev / cli-server). Also resolves item #8 (session cookie hardening via `session_set_cookie_params` before `session_start`). See `nginx/PHP_AUTH_LAYER.md`. | | 8 | Session cookies not hardened (`Secure`, `HttpOnly`, `SameSite` missing) | 🟡 MEDIUM | **Resolved as part of item #2.** `AdminAuth::startSession()` sets `HttpOnly=true`, `SameSite=Strict`, `Secure=true` (off on cli-server), `Path=/admin`, `Lifetime=0` before every `session_start()`. | --- diff --git a/justfile b/justfile index 9998a08..d2104c8 100644 --- a/justfile +++ b/justfile @@ -160,7 +160,7 @@ syntax: @echo "======================" @find . -maxdepth 1 -name "*.php" -not -path "./vendor/*" -exec php -l {} \; | grep -v "No syntax errors" @find admin/ -name "*.php" -exec php -l {} \; 2>/dev/null | grep -v "No syntax errors" || true - @find lib/ -name "*.php" -exec php -l {} \; | grep -v "No syntax errors" + @find src/ -name "*.php" -exec php -l {} \; | grep -v "No syntax errors" @echo "✅ All PHP files have valid syntax" # ============================================================================ @@ -315,7 +315,7 @@ clean: @echo "🧹 Cleaning up development files..." @rm -f error.log @rm -f admin/error.log - @rm -rf lib/cache/rate_limit/* + @rm -rf src/cache/rate_limit/* @rm -f /tmp/posterg-*.log @rm -f /tmp/posterg-*.pid @echo "✓ Cleanup complete" @@ -326,7 +326,7 @@ setup-dirs: @mkdir -p admin/data/theses @mkdir -p admin/data/covers @mkdir -p admin/data/yaml - @mkdir -p lib/cache/rate_limit + @mkdir -p src/cache/rate_limit @touch admin/data/theses/.gitkeep @touch admin/data/covers/.gitkeep @echo "✓ Directories created" diff --git a/lib/cache/rate_limit/ad921d60486366258809553a3db49a4a.json b/lib/cache/rate_limit/ad921d60486366258809553a3db49a4a.json deleted file mode 100644 index ba753f0..0000000 --- a/lib/cache/rate_limit/ad921d60486366258809553a3db49a4a.json +++ /dev/null @@ -1 +0,0 @@ -[1770319036] \ No newline at end of file diff --git a/lib/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json b/lib/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json deleted file mode 100644 index fe0acea..0000000 --- a/lib/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json +++ /dev/null @@ -1 +0,0 @@ -[1770377487] \ No newline at end of file diff --git a/includes/footer.php b/public/includes/footer.php similarity index 100% rename from includes/footer.php rename to public/includes/footer.php diff --git a/includes/header.php b/public/includes/header.php similarity index 100% rename from includes/header.php rename to public/includes/header.php diff --git a/public/index.php b/public/index.php index aad3ff8..2adce6a 100644 --- a/public/index.php +++ b/public/index.php @@ -1,7 +1,7 @@
@@ -54,4 +54,4 @@ include APP_ROOT . '/includes/header.php'; - + diff --git a/public/live-reload.php b/public/live-reload.php index e88e085..77a50e5 100644 --- a/public/live-reload.php +++ b/public/live-reload.php @@ -18,8 +18,7 @@ $root = dirname(__DIR__); $watchDirs = [ $root . '/public', - $root . '/includes', - $root . '/lib', + $root . '/src', $root . '/config', ]; diff --git a/public/memoire.php b/public/memoire.php index 0ec8f3a..3cf9d85 100644 --- a/public/memoire.php +++ b/public/memoire.php @@ -3,7 +3,7 @@ require_once __DIR__ . '/../config/bootstrap.php'; // Load required libraries and classes -require_once APP_ROOT . '/lib/Database.php'; +require_once APP_ROOT . '/src/Database.php'; // Check if an id parameter is provided in the URL if (isset($_GET['id'])) { @@ -29,7 +29,7 @@ if (isset($_GET['id'])) { } // Include the header template -include APP_ROOT . '/includes/header.php'; ?> +include APP_ROOT . '/public/includes/header.php'; ?>
@@ -151,4 +151,4 @@ include APP_ROOT . '/includes/header.php'; ?>
- \ No newline at end of file + \ No newline at end of file diff --git a/public/search.php b/public/search.php index f508886..b609b34 100644 --- a/public/search.php +++ b/public/search.php @@ -1,8 +1,8 @@ check()) { $rateLimit->sendHeaders(); // Display error page - include APP_ROOT . '/includes/header.php'; + include APP_ROOT . '/public/includes/header.php'; echo '
'; echo '
'; echo '
'; @@ -26,7 +26,7 @@ if (!$rateLimit->check()) { echo '
'; echo '
'; echo '
'; - include APP_ROOT . '/includes/footer.php'; + include APP_ROOT . '/public/includes/footer.php'; exit; } @@ -122,7 +122,7 @@ try { $languages = []; } -include APP_ROOT . '/includes/header.php'; ?> +include APP_ROOT . '/public/includes/header.php'; ?>
@@ -415,4 +415,4 @@ include APP_ROOT . '/includes/header.php'; ?>
- + diff --git a/lib/AdminAuth.php b/src/AdminAuth.php similarity index 100% rename from lib/AdminAuth.php rename to src/AdminAuth.php diff --git a/lib/Database.php b/src/Database.php similarity index 100% rename from lib/Database.php rename to src/Database.php diff --git a/lib/RateLimit.php b/src/RateLimit.php similarity index 100% rename from lib/RateLimit.php rename to src/RateLimit.php diff --git a/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json b/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json new file mode 100644 index 0000000..fe2ae9f --- /dev/null +++ b/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json @@ -0,0 +1 @@ +[1770894664] \ No newline at end of file diff --git a/lib/config.php b/src/config.php similarity index 100% rename from lib/config.php rename to src/config.php diff --git a/tests/Integration/SearchTest.php b/tests/Integration/SearchTest.php index 9147a6a..cdab595 100644 --- a/tests/Integration/SearchTest.php +++ b/tests/Integration/SearchTest.php @@ -4,7 +4,7 @@ * Tests search queries and results */ -require_once __DIR__ . '/../../lib/Database.php'; +require_once __DIR__ . '/../../src/Database.php'; echo "Search Functionality Test\n"; echo "=========================\n\n"; diff --git a/tests/Security/SecurityTest.php b/tests/Security/SecurityTest.php index 0be5463..4ae50a2 100644 --- a/tests/Security/SecurityTest.php +++ b/tests/Security/SecurityTest.php @@ -4,7 +4,7 @@ * Tests SQL injection protection and input sanitization */ -require_once __DIR__ . '/../../lib/Database.php'; +require_once __DIR__ . '/../../src/Database.php'; echo "Security Test Suite\n"; echo "===================\n\n"; diff --git a/tests/Unit/DatabaseTest.php b/tests/Unit/DatabaseTest.php index 4ffbbfa..e3e5f33 100644 --- a/tests/Unit/DatabaseTest.php +++ b/tests/Unit/DatabaseTest.php @@ -4,7 +4,7 @@ * Tests basic database connectivity and query functionality */ -require_once __DIR__ . '/../../lib/Database.php'; +require_once __DIR__ . '/../../src/Database.php'; echo "Database Connection Test\n"; echo "========================\n\n"; diff --git a/tests/Unit/RateLimitTest.php b/tests/Unit/RateLimitTest.php index c229cd3..42627b9 100644 --- a/tests/Unit/RateLimitTest.php +++ b/tests/Unit/RateLimitTest.php @@ -4,7 +4,7 @@ * Tests rate limiting functionality */ -require_once __DIR__ . '/../../lib/RateLimit.php'; +require_once __DIR__ . '/../../src/RateLimit.php'; echo "Rate Limit Test\n"; echo "===============\n\n";