diff --git a/.env.example b/.env.example index c0660ea..f076da4 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ -APP_NAME=Laravel +# --- Application --- +# En production : APP_ENV=production et APP_DEBUG=false (ne jamais exposer les +# traces d'erreur / la configuration au public). APP_KEY doit être généré via +# `php artisan key:generate` et rester secret (chiffrement des sessions/cookies). +APP_NAME="(RE)Sources Relationnelles" APP_ENV=local APP_KEY= APP_DEBUG=true @@ -20,15 +24,18 @@ LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug -DB_CONNECTION=sqlite -# DB_HOST=127.0.0.1 -# DB_PORT=3306 -# DB_DATABASE=laravel -# DB_USERNAME=root -# DB_PASSWORD= +# --- Base de données --- +# En production, utiliser MySQL/MariaDB (données ministérielles) plutôt que SQLite. +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=ressources_relationnel +DB_USERNAME=changeme +DB_PASSWORD=changeme SESSION_DRIVER=database SESSION_LIFETIME=120 +# En production, passer à true pour chiffrer les données de session (RGPD). SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..5d62c0e --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CI - Intégration continue + +# Intégration continue : à chaque push et chaque pull request, on vérifie +# automatiquement la qualité du code (Laravel Pint) puis on exécute les tests +# automatisés (PHPUnit). Un déploiement (voir deploy.yml) ne doit se faire que +# si cette étape est au vert. + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + quality-and-tests: + runs-on: ubuntu-latest + + steps: + - name: Récupération du code + uses: actions/checkout@v4 + + - name: Installation de PHP 8.2 + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: pdo_mysql, mbstring, exif, pcntl, bcmath, gd + coverage: none + + - name: Cache des dépendances Composer + uses: actions/cache@v4 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + + - name: Installation des dépendances + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Préparation de l'environnement de test + run: | + cp .env.example .env + php artisan key:generate + + - name: Vérification du style de code (Laravel Pint) + run: vendor/bin/pint --test + + - name: Exécution des tests automatisés (PHPUnit) + env: + DB_CONNECTION: sqlite + DB_DATABASE: ':memory:' + run: php artisan test diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..5ab7c54 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,49 @@ +name: CD - Déploiement continu + +# Déploiement continu : après un push sur master, une fois la CI passée, +# on se connecte en SSH au serveur de production et on met à jour l'application +# (git pull, rebuild des conteneurs, migrations, mise en cache). +# +# Secrets à définir dans Gitea (Settings > Actions > Secrets du dépôt) : +# - SSH_HOST : IP ou domaine du serveur +# - SSH_USER : utilisateur SSH +# - SSH_PRIVATE_KEY : clé privée SSH autorisée sur le serveur +# - SSH_PORT : port SSH (optionnel, 22 par défaut) + +on: + push: + branches: [ master ] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Déploiement sur le serveur via SSH + uses: appleboy/ssh-action@v1.2.0 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + port: ${{ secrets.SSH_PORT }} + script: | + set -e + cd /home/sam/mon-app-laravel + + # Récupération de la dernière version du code + git pull origin master + + # Reconstruction et redémarrage des conteneurs + docker compose up -d --build + + # Migrations de la base de données (sans interaction) + docker exec laravel_php php artisan migrate --force + + # Mise en cache de la configuration et des routes (performances en prod) + docker exec laravel_php php artisan config:cache + docker exec laravel_php php artisan route:cache + docker exec laravel_php php artisan view:cache + + # Correction des permissions sur les dossiers écrits par Laravel + docker exec -u 0 laravel_php chown -R www-data:www-data \ + /var/www/storage /var/www/bootstrap/cache diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index b83cbe3..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Deploy Laravel App - -on: - push: - branches: [ main ] # Déclenche le déploiement lors d'un push sur la branche main - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Deploy to Server via SSH - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - script: | - cd /home/sam/mon-app-laravel - git pull origin main - docker-compose up -d --build - docker exec laravel_app php artisan migrate --force - docker exec laravel_app php artisan config:cache - docker exec laravel_app php artisan route:cache - - name: Fix permissions - run: | - docker exec -u 0 laravel_php chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache /tmp - docker exec laravel_php php artisan view:clear diff --git a/README.md b/README.md index 0165a77..3328063 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,70 @@ -

Laravel Logo

+# (RE)Sources Relationnelles -

-Build Status -Total Downloads -Latest Stable Version -License -

+Plateforme de partage de ressources relationnelles à destination des citoyens +(simulation d'un projet du Ministère des Solidarités et de la Santé). +Projet collaboratif — **CDA / CESI — Groupe 1**. -## About Laravel +Application web développée avec **Laravel 12** (architecture MVC), conteneurisée +avec **Docker** et déployée en continu via **Gitea Actions**. -Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: +- Application : https://app.sam-coffre.duckdns.org +- Dépôt Git : https://gitea.sam-coffre.duckdns.org/ -- [Simple, fast routing engine](https://laravel.com/docs/routing). -- [Powerful dependency injection container](https://laravel.com/docs/container). -- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. -- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). -- Database agnostic [schema migrations](https://laravel.com/docs/migrations). -- [Robust background job processing](https://laravel.com/docs/queues). -- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). +## Stack technique -Laravel is accessible, powerful, and provides tools required for large, robust applications. +| Élément | Technologie | +|---------|-------------| +| Framework | Laravel 12 (PHP 8.2) | +| Base de données | MySQL / MariaDB (SQLite en test) | +| Serveur web | Nginx (reverse proxy + TLS) | +| Conteneurisation | Docker / Docker Compose | +| Gestion de version | Git + Gitea | +| CI/CD | Gitea Actions | +| Qualité de code | Laravel Pint | +| Tests | PHPUnit | -## Learning Laravel +## Installation en local -Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. You can also check out [Laravel Learn](https://laravel.com/learn), where you will be guided through building a modern Laravel application. +```bash +git clone https://gitea.sam-coffre.duckdns.org//ressources-relationnel.git +cd ressources-relationnel +cp .env.example .env +composer install +php artisan key:generate +php artisan migrate --seed +npm install && npm run build +php artisan serve +``` -If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. +## Développement -## Laravel Sponsors +```bash +# Lancer les tests automatisés +php artisan test -We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). +# Vérifier le style de code +vendor/bin/pint --test -### Premium Partners +# Corriger automatiquement le style de code +vendor/bin/pint +``` -- **[Vehikl](https://vehikl.com)** -- **[Tighten Co.](https://tighten.co)** -- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** -- **[64 Robots](https://64robots.com)** -- **[Curotec](https://www.curotec.com/services/technologies/laravel)** -- **[DevSquad](https://devsquad.com/hire-laravel-developers)** -- **[Redberry](https://redberry.international/laravel-development)** -- **[Active Logic](https://activelogic.com)** +## Déploiement -## Contributing +Le déploiement est **automatisé** : un `push` sur la branche `master` déclenche +la CI (qualité + tests) puis, si tout est vert, le déploiement en production. +Voir [`docs/02-plan-de-deploiement.md`](docs/02-plan-de-deploiement.md). -Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). +## Documentation (rendu bloc INFCDAAL3) -## Code of Conduct +La documentation technique « Déployer et sécuriser » est dans le dossier +[`docs/`](docs/README.md) : -In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). +- [Plan de sécurisation](docs/01-plan-de-securisation.md) +- [Plan de déploiement](docs/02-plan-de-deploiement.md) +- [Gestion des versions](docs/03-gestion-des-versions.md) +- [Gestion des évolutions](docs/04-gestion-des-evolutions.md) -## Security Vulnerabilities +## Licence -If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. - -## License - -The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +Projet pédagogique — usage limité au cadre de la formation. diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php index da4b774..5845b34 100644 --- a/app/Http/Controllers/LoginController.php +++ b/app/Http/Controllers/LoginController.php @@ -2,8 +2,8 @@ namespace App\Http\Controllers; -use App\Models\Utilisateur; use App\Models\Role; +use App\Models\Utilisateur; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; @@ -36,6 +36,7 @@ class LoginController extends Controller if (Auth::attempt($loginCredentials)) { $request->session()->regenerate(); + return redirect()->route('home')->with('success', 'Connexion réussie!'); } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 80f8b87..44850d5 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -14,6 +14,7 @@ class ProfileController extends Controller { /** @var Utilisateur $user */ $user = Auth::user(); + return view('profile.settings', compact('user')); } @@ -24,8 +25,8 @@ class ProfileController extends Controller $user = Auth::user(); $request->validate([ - 'Pseudo' => ['required', 'string', 'max:100', 'unique:utilisateurs,Pseudo,' . $user->ID_Utilisateur . ',ID_Utilisateur'], - 'Email' => ['required', 'string', 'email', 'max:255', 'unique:utilisateurs,Email,' . $user->ID_Utilisateur . ',ID_Utilisateur'], + 'Pseudo' => ['required', 'string', 'max:100', 'unique:utilisateurs,Pseudo,'.$user->ID_Utilisateur.',ID_Utilisateur'], + 'Email' => ['required', 'string', 'email', 'max:255', 'unique:utilisateurs,Email,'.$user->ID_Utilisateur.',ID_Utilisateur'], 'MotDePasse_Actuel' => ['nullable', 'string'], 'MotDePasse_Nouveau' => ['nullable', 'string', 'min:8', 'confirmed'], ], [ @@ -41,7 +42,7 @@ class ProfileController extends Controller // Vérifier le mot de passe actuel si on veut le modifier if ($request->filled('MotDePasse_Nouveau')) { - if (!Hash::check($request->MotDePasse_Actuel, $user->MotDePasse)) { + if (! Hash::check($request->MotDePasse_Actuel, $user->MotDePasse)) { return back()->withErrors([ 'MotDePasse_Actuel' => 'Le mot de passe actuel est incorrect.', ])->onlyInput('Email', 'Pseudo'); @@ -56,4 +57,34 @@ class ProfileController extends Controller return back()->with('success', 'Votre profil a été mis à jour avec succès!'); } + + // Supprimer / anonymiser son compte (droit à l'effacement RGPD) + public function destroy(Request $request) + { + /** @var Utilisateur $user */ + $user = Auth::user(); + + // Vérification du mot de passe pour confirmer l'action sensible + $request->validate([ + 'MotDePasse_Confirmation' => ['required', 'string'], + ], [ + 'MotDePasse_Confirmation.required' => 'Veuillez saisir votre mot de passe pour confirmer.', + ]); + + if (! Hash::check($request->MotDePasse_Confirmation, $user->MotDePasse)) { + return back()->withErrors([ + 'MotDePasse_Confirmation' => 'Mot de passe incorrect. Suppression annulée.', + ]); + } + + // Anonymisation des données personnelles, puis déconnexion sécurisée + $user->anonymiser(); + + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('home') + ->with('success', 'Votre compte a été supprimé et vos données personnelles anonymisées.'); + } } diff --git a/app/Http/Middleware/ForceHttps.php b/app/Http/Middleware/ForceHttps.php index 94077f2..888ea8c 100644 --- a/app/Http/Middleware/ForceHttps.php +++ b/app/Http/Middleware/ForceHttps.php @@ -9,8 +9,10 @@ class ForceHttps { public function handle(Request $request, Closure $next) { - // En production, forcer HTTPS même si on arrive en HTTP - if (!app()->environment('local') && !$request->isSecure()) { + // En production, forcer HTTPS même si on arrive en HTTP. + // On exclut les environnements local et testing (pas de TLS, et + // la redirection casserait la suite de tests automatisés / CI). + if (! app()->environment(['local', 'testing']) && ! $request->isSecure()) { return redirect( str_replace('http://', 'https://', $request->url()), 308 diff --git a/app/Http/Middleware/SecurityHeaders.php b/app/Http/Middleware/SecurityHeaders.php index cf3fe0c..30251f2 100644 --- a/app/Http/Middleware/SecurityHeaders.php +++ b/app/Http/Middleware/SecurityHeaders.php @@ -15,13 +15,41 @@ class SecurityHeaders { $response = $next($request); - // Ajouter les headers de sécurité + // --- En-têtes de sécurité HTTP (défense en profondeur) --- + + // Force le navigateur à n'utiliser que HTTPS pendant 1 an (protection contre le SSL stripping). $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains', true); + + // Empêche le navigateur de "deviner" le type MIME d'une ressource (protection contre le MIME sniffing). $response->headers->set('X-Content-Type-Options', 'nosniff', true); + + // Interdit l'affichage du site dans une iframe externe (protection contre le clickjacking). $response->headers->set('X-Frame-Options', 'SAMEORIGIN', true); + + // Ancienne protection XSS des navigateurs (conservée pour les navigateurs anciens). $response->headers->set('X-XSS-Protection', '1; mode=block', true); + + // Limite les informations de provenance envoyées aux sites tiers. $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin', true); + // Désactive des API sensibles du navigateur non utilisées par l'application (RGPD / vie privée). + $response->headers->set('Permissions-Policy', 'geolocation=(), microphone=(), camera=(), payment=()', true); + + // Content-Security-Policy : réduit fortement le risque d'injection de scripts (XSS). + // Politique volontairement compatible avec Laravel/Vite (styles et scripts inline autorisés). + // Pour durcir davantage, remplacer 'unsafe-inline' par un système de nonce. + $response->headers->set('Content-Security-Policy', implode('; ', [ + "default-src 'self'", + "script-src 'self' 'unsafe-inline'", + "style-src 'self' 'unsafe-inline'", + "img-src 'self' data: https:", + "font-src 'self' data:", + "connect-src 'self'", + "object-src 'none'", + "base-uri 'self'", + "frame-ancestors 'self'", + ]), true); + return $response; } } diff --git a/app/Models/Activite.php b/app/Models/Activite.php index f826c2a..5f7f1c1 100644 --- a/app/Models/Activite.php +++ b/app/Models/Activite.php @@ -7,8 +7,11 @@ use Illuminate\Database\Eloquent\Model; class Activite extends Model { protected $primaryKey = 'ID_Instance'; + protected $table = 'activites'; + public $incrementing = true; + public $timestamps = false; protected $fillable = [ diff --git a/app/Models/ActiviteMessage.php b/app/Models/ActiviteMessage.php index 140d96f..dcaae59 100644 --- a/app/Models/ActiviteMessage.php +++ b/app/Models/ActiviteMessage.php @@ -7,8 +7,11 @@ use Illuminate\Database\Eloquent\Model; class ActiviteMessage extends Model { protected $primaryKey = 'ID_Message'; + protected $table = 'activite_messages'; + public $incrementing = true; + public $timestamps = false; protected $fillable = [ diff --git a/app/Models/Categorie.php b/app/Models/Categorie.php index 7e66e27..358ae4a 100644 --- a/app/Models/Categorie.php +++ b/app/Models/Categorie.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Categorie extends Model { public $timestamps = false; + protected $primaryKey = 'ID_Categorie'; + protected $table = 'categories'; protected $fillable = [ diff --git a/app/Models/Commentaire.php b/app/Models/Commentaire.php index c00e596..06afb13 100644 --- a/app/Models/Commentaire.php +++ b/app/Models/Commentaire.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Commentaire extends Model { protected $primaryKey = 'ID_Commentaire'; + protected $table = 'commentaires'; + public $incrementing = true; protected $fillable = [ @@ -42,4 +44,4 @@ class Commentaire extends Model { return $this->belongsTo(Commentaire::class, 'ID_Parent_Commentaire', 'ID_Commentaire'); } -} \ No newline at end of file +} diff --git a/app/Models/Ressource.php b/app/Models/Ressource.php index e89d7a5..cf9cba6 100644 --- a/app/Models/Ressource.php +++ b/app/Models/Ressource.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Ressource extends Model { protected $primaryKey = 'ID_Ressource'; + protected $table = 'ressources'; + public $incrementing = true; protected $fillable = [ @@ -59,4 +61,4 @@ class Ressource extends Model { return $this->hasMany(Utilisateur_Progression::class, 'ID_Ressource', 'ID_Ressource'); } -} \ No newline at end of file +} diff --git a/app/Models/Role.php b/app/Models/Role.php index 826fa4b..ca7689c 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Role extends Model { public $timestamps = false; + protected $primaryKey = 'ID_Role'; + protected $table = 'roles'; protected $fillable = [ diff --git a/app/Models/TypeRessource.php b/app/Models/TypeRessource.php index d706696..0bd202f 100644 --- a/app/Models/TypeRessource.php +++ b/app/Models/TypeRessource.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class TypeRessource extends Model { public $timestamps = false; + protected $primaryKey = 'ID_Type_Ressource'; + protected $table = 'type_ressources'; protected $fillable = [ diff --git a/app/Models/Utilisateur.php b/app/Models/Utilisateur.php index 23c2252..9597cea 100644 --- a/app/Models/Utilisateur.php +++ b/app/Models/Utilisateur.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Carbon; /** * @property int $ID_Utilisateur @@ -12,7 +13,7 @@ use Illuminate\Notifications\Notifiable; * @property string $Pseudo * @property string $Statut * @property int $ID_Role - * @property \Illuminate\Support\Carbon $DateInscription + * @property Carbon $DateInscription */ class Utilisateur extends Authenticatable { @@ -20,10 +21,15 @@ class Utilisateur extends Authenticatable // Nom de la table protected $table = 'utilisateurs'; - + + // La table utilise DateInscription et non created_at/updated_at + public $timestamps = false; + // Clé primaire personnalisée protected $primaryKey = 'ID_Utilisateur'; + public $incrementing = true; + protected $keyType = 'int'; // Colonnes modifiables (Mass Assignment) @@ -88,4 +94,21 @@ class Utilisateur extends Authenticatable { return $this->hasMany(Utilisateur_Progression::class, 'ID_Utilisateur', 'ID_Utilisateur'); } -} \ No newline at end of file + + /** + * Anonymise le compte (droit à l'effacement RGPD). + * + * Les données personnelles identifiantes (e-mail, pseudo, mot de passe) + * sont remplacées par des valeurs neutres et non réversibles, tandis que + * les contributions liées (ressources, commentaires) restent en base sous + * une forme anonyme afin de préserver l'intégrité référentielle. + */ + public function anonymiser(): void + { + $this->Email = 'anonyme_'.$this->ID_Utilisateur.'@anonymise.local'; + $this->Pseudo = 'Utilisateur supprimé'; + $this->MotDePasse = bin2hex(random_bytes(32)); // mot de passe non utilisable + $this->Statut = 'Inactif'; // compte désactivé (valeur de l'enum Statut) + $this->save(); + } +} diff --git a/app/Models/Utilisateur_Progression.php b/app/Models/Utilisateur_Progression.php index 4637f40..6be5483 100644 --- a/app/Models/Utilisateur_Progression.php +++ b/app/Models/Utilisateur_Progression.php @@ -7,7 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Utilisateur_Progression extends Model { protected $table = 'utilisateur_progressions'; + public $timestamps = false; + public $incrementing = false; protected $primaryKey = ['ID_Utilisateur', 'ID_Ressource']; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 60142b0..68c9c33 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,9 +2,8 @@ namespace App\Providers; -use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\URL; -use Symfony\Component\HttpFoundation\Request as SymfonyRequest; +use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { @@ -21,7 +20,7 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - if (!app()->environment('local')) { + if (! app()->environment('local')) { URL::forceScheme('https'); } // ForceHttps middleware se charge de forcer HTTPS diff --git a/bootstrap/app.php b/bootstrap/app.php index 7d7bd0e..f2ba62f 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,10 +1,10 @@ withRouting( diff --git a/database/migrations/2026_03_23_211437_create_roles_table.php b/database/migrations/2026_03_23_211437_create_roles_table.php deleted file mode 100644 index 0b4fe21..0000000 --- a/database/migrations/2026_03_23_211437_create_roles_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('roles'); - } -}; diff --git a/database/migrations/2026_03_23_211437_create_utilisateurs_table.php b/database/migrations/2026_03_23_211437_create_utilisateurs_table.php deleted file mode 100644 index 4bb24e8..0000000 --- a/database/migrations/2026_03_23_211437_create_utilisateurs_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->string('Email')->unique(); - $table->string('MotDePasse'); - $table->string('Pseudo')->nullable(); - $table->unsignedBigInteger('ID_Role')->nullable(); - $table->string('Statut')->default('Actif'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('utilisateurs'); - } -}; diff --git a/database/migrations/2026_03_23_211438_create_activites_table.php b/database/migrations/2026_03_23_211438_create_activites_table.php deleted file mode 100644 index 71a9ef9..0000000 --- a/database/migrations/2026_03_23_211438_create_activites_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('activites'); - } -}; diff --git a/database/migrations/2026_03_23_211438_create_categories_table.php b/database/migrations/2026_03_23_211438_create_categories_table.php deleted file mode 100644 index 24c1532..0000000 --- a/database/migrations/2026_03_23_211438_create_categories_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('categories'); - } -}; diff --git a/database/migrations/2026_03_23_211438_create_commentaires_table.php b/database/migrations/2026_03_23_211438_create_commentaires_table.php deleted file mode 100644 index 92f55d9..0000000 --- a/database/migrations/2026_03_23_211438_create_commentaires_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('commentaires'); - } -}; diff --git a/database/migrations/2026_03_23_211438_create_ressources_table.php b/database/migrations/2026_03_23_211438_create_ressources_table.php deleted file mode 100644 index 71d31fa..0000000 --- a/database/migrations/2026_03_23_211438_create_ressources_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('ressources'); - } -}; diff --git a/database/migrations/2026_03_23_211438_create_type_ressources_table.php b/database/migrations/2026_03_23_211438_create_type_ressources_table.php deleted file mode 100644 index 16b8c3c..0000000 --- a/database/migrations/2026_03_23_211438_create_type_ressources_table.php +++ /dev/null @@ -1,27 +0,0 @@ -id(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('type_ressources'); - } -}; diff --git a/docker-compose.yml b/docker-compose.yml index 468f09e..43067d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: container_name: laravel_web restart: always ports: - - "8000:80" + - "8005:80" - "8443:443" # HTTPS port volumes: - .:/var/www diff --git a/docs/01-plan-de-securisation.md b/docs/01-plan-de-securisation.md new file mode 100644 index 0000000..c9df0a4 --- /dev/null +++ b/docs/01-plan-de-securisation.md @@ -0,0 +1,99 @@ +# 01 — Plan de sécurisation + +Projet **(RE)Sources Relationnelles** — Bloc INFCDAAL3 + +> Contexte : plateforme ministérielle manipulant des **données personnelles** +> (comptes citoyens, ressources privées, échanges modérés). La sécurité et la +> conformité **RGPD** sont donc des exigences fortes. + +## 1. Identification des risques de sécurité + +Analyse inspirée du **Top 10 OWASP** et adaptée au projet. + +| Risque | Exemple sur le projet | Gravité | Traitement mis en place | +|--------|-----------------------|---------|-------------------------| +| Injection SQL | Recherche / filtres de ressources | Élevée | ORM Eloquent (requêtes préparées), validation des entrées | +| XSS (injection de scripts) | Commentaires, ressources créées par les citoyens | Élevée | Échappement Blade `{{ }}`, en-tête **CSP** | +| CSRF | Formulaires (login, création de ressource) | Élevée | Jeton CSRF Laravel automatique sur les formulaires | +| Vol de session | Cookies de session | Élevée | Cookies `HttpOnly` + `Secure`, HTTPS forcé, `session.regenerate()` à la connexion | +| Mots de passe faibles / en clair | Comptes citoyens | Élevée | Hachage **bcrypt** (`hashed` cast), min. 8 caractères | +| Contrôle d'accès défaillant | Accès Back Office / pages profil | Élevée | Middleware `auth`, rôles (Citoyen / Modérateur / Admin / Super-Admin) | +| Man-in-the-middle | Transport des données | Élevée | **TLS/HTTPS** obligatoire + **HSTS** | +| Exposition d'informations | Messages d'erreur, debug | Moyenne | `APP_DEBUG=false` et `APP_ENV=production` en prod | +| Clickjacking | Intégration en iframe | Moyenne | En-tête `X-Frame-Options: SAMEORIGIN` | +| Dépendances vulnérables | Paquets Composer / npm | Moyenne | `composer audit` / mises à jour régulières | + +## 2. Mesures de prévention des risques + +### 2.1 Sécurité applicative (implémentée dans le code) + +- **Authentification** : hachage bcrypt des mots de passe, régénération de + session à la connexion, invalidation à la déconnexion + (`app/Http/Controllers/LoginController.php`). +- **Contrôle d'accès** : les routes sensibles sont regroupées derrière le + middleware `auth` (`routes/web.php`), avec un modèle de **rôles** + (`app/Models/Role.php`). +- **Validation des entrées** : toutes les données reçues sont validées + (règles `required`, `email`, `unique`, `min:8`, `confirmed`…). +- **Protection CSRF** : activée par défaut sur tous les formulaires POST/PUT. +- **En-têtes de sécurité HTTP** (`app/Http/Middleware/SecurityHeaders.php`) : + - `Strict-Transport-Security` (HSTS) — impose HTTPS, + - `Content-Security-Policy` (CSP) — limite les sources de scripts (anti-XSS), + - `X-Content-Type-Options: nosniff`, + - `X-Frame-Options: SAMEORIGIN` (anti-clickjacking), + - `Referrer-Policy` et `Permissions-Policy`. +- **Forçage HTTPS** (`app/Http/Middleware/ForceHttps.php`) : redirection + automatique de HTTP vers HTTPS hors environnement local/test. + +### 2.2 Sécurité du transport et de l'infrastructure + +- **TLS/HTTPS** terminé au niveau du reverse proxy (`nginx.conf`) : le port 80 + redirige en 301 vers le port 443. +- Nom de domaine du service : `https://app.sam-coffre.duckdns.org`. +- Séparation des rôles conteneurs : PHP-FPM (`laravel_php`) et serveur web + (`laravel_web`) isolés (`docker-compose.yml`). + +## 3. Chiffrement des données + +| Donnée | État au repos | En transit | +|--------|---------------|-----------| +| Mots de passe | Hachage **bcrypt** (non réversible) | HTTPS | +| Sessions / cookies | Chiffrés via `APP_KEY` (AES-256), `SESSION_ENCRYPT=true` en prod | HTTPS + cookie `Secure`/`HttpOnly` | +| Données personnelles sensibles | Chiffrables via les *casts* `encrypted` d'Eloquent | HTTPS | +| Communications client ↔ serveur | — | **TLS 1.2+** obligatoire | + +> Laravel chiffre en **AES-256-CBC** à partir de la clé `APP_KEY`. Cette clé est +> stockée hors dépôt (`.env` est dans `.gitignore`) et ne doit jamais être versionnée. + +## 4. Conformité RGPD + +- **Minimisation** : seules les données nécessaires sont collectées (pseudo, e-mail). +- **Base légale et information** : pages légales présentes + (`resources/views/legal/mentions.blade.php`, + `resources/views/legal/politique.blade.php`). +- **Droit d'accès / rectification** : espace profil + (`/profile/settings`, `ProfileController`). +- **Droit à l'effacement / anonymisation** : implémenté. Depuis son espace + profil, l'utilisateur peut supprimer son compte (confirmation par mot de passe) ; + ses données personnelles (e-mail, pseudo, mot de passe) sont alors anonymisées + de façon irréversible via `Utilisateur::anonymiser()` + (`app/Http/Controllers/ProfileController@destroy`), tout en préservant + l'intégrité référentielle des contributions. +- **Sécurité par défaut** (privacy by design) : chiffrement, HTTPS, contrôle d'accès. +- **Sous-traitance et hébergement** : hébergement maîtrisé, journalisation des accès. + +## 5. Bonnes pratiques de développement + +- **Style de code homogène** : **Laravel Pint** (PSR-12), vérifié en CI + (`vendor/bin/pint --test`). +- **Commentaires** : le code de sécurité (middlewares) est documenté en français. +- **Tests automatisés** : `tests/Feature/SecuriteTest.php` vérifie les en-têtes + de sécurité et le contrôle d'accès aux pages protégées. +- **Séparation des environnements** : configuration via `.env` (jamais de secret en dur). +- **Architecture MVC** : contrôleurs / modèles / vues séparés. + +## 6. Synthèse — traçabilité risque → mesure + +Chaque risque du §1 est couvert par au moins une mesure du §2/§3/§4, et les +mesures critiques (en-têtes, contrôle d'accès) sont **vérifiées automatiquement** +par la CI à chaque évolution du code. diff --git a/docs/02-plan-de-deploiement.md b/docs/02-plan-de-deploiement.md new file mode 100644 index 0000000..0e73456 --- /dev/null +++ b/docs/02-plan-de-deploiement.md @@ -0,0 +1,109 @@ +# 02 — Plan de déploiement + +Projet **(RE)Sources Relationnelles** — Bloc INFCDAAL3 + +## 1. Stratégie de déploiement + +Le déploiement repose sur trois piliers : + +1. **Conteneurisation** (Docker) pour un environnement reproductible. +2. **Gestion de version** (Gitea) comme source unique de vérité. +3. **Intégration et déploiement continus** (Gitea Actions) pour automatiser + qualité, tests et mise en production. + +Approche retenue : à chaque `push` sur `master`, la CI valide le code +(qualité + tests) ; si tout est vert, le déploiement se déclenche automatiquement +sur le serveur. + +## 2. Environnements + +| Environnement | Rôle | Hébergement | +|---------------|------|-------------| +| **Local (dev)** | Développement sur le poste | Docker / `php artisan serve` | +| **Test (CI)** | Exécution automatisée des tests | Runner Gitea Actions (base SQLite en mémoire) | +| **Pré-production (QA)** *(recommandé)* | Recette avant mise en ligne | Conteneurs Docker, base dédiée | +| **Production** | Service ouvert aux citoyens | Serveur `app.sam-coffre.duckdns.org` | + +> La configuration de chaque environnement est portée par un fichier `.env` +> distinct (jamais versionné). Seul `.env.example` est présent dans le dépôt. + +## 3. Architecture de déploiement + +``` + Internet (HTTPS) + │ + ▼ + ┌───────────────────────────┐ + │ Nginx (conteneur web) │ :443 TLS / redirection 80→443 + │ laravel_web │ + └─────────────┬─────────────┘ + │ FastCGI :9000 + ▼ + ┌───────────────────────────┐ + │ PHP-FPM (conteneur app) │ Laravel 12 + │ laravel_php │ + └─────────────┬─────────────┘ + │ + ▼ + Base de données MySQL +``` + +Fichiers concernés : `Dockerfile` (image PHP), `docker-compose.yml` +(orchestration), `nginx.conf` (reverse proxy / TLS). + +## 4. Pipeline d'intégration et de déploiement continus (CI/CD) + +### 4.1 Intégration continue — `.gitea/workflows/ci.yml` + +Déclenchée sur chaque `push` et chaque `pull_request` vers `master` : + +1. Récupération du code. +2. Installation de PHP 8.2 et des extensions. +3. Installation des dépendances Composer (avec cache). +4. **Vérification du style de code** : `vendor/bin/pint --test`. +5. **Exécution des tests** : `php artisan test` (PHPUnit). + +### 4.2 Déploiement continu — `.gitea/workflows/deploy.yml` + +Déclenché sur `push` vers `master`, il se connecte en **SSH** au serveur et exécute : + +1. `git pull origin master` — récupération de la nouvelle version. +2. `docker compose up -d --build` — reconstruction des conteneurs. +3. `php artisan migrate --force` — application des migrations de base. +4. `config:cache`, `route:cache`, `view:cache` — optimisations de production. +5. Correction des permissions (`storage`, `bootstrap/cache`). + +**Secrets Gitea requis** (Settings → Actions → Secrets) : `SSH_HOST`, +`SSH_USER`, `SSH_PRIVATE_KEY`, `SSH_PORT`. + +> Prérequis : un **runner Gitea Actions** doit être enregistré sur l'instance +> (`https://gitea.sam-coffre.duckdns.org/`) et les Actions activées pour le dépôt. + +## 5. Plan de déploiement détaillé (étapes, ressources, responsables) + +| # | Étape | Ressource / Outil | Responsable | Automatisé ? | +|---|-------|-------------------|-------------|--------------| +| 1 | Développement + commit | Git / Gitea | Développeur | Non | +| 2 | Push sur `master` | Gitea | Développeur | Non | +| 3 | Contrôle qualité (Pint) | Gitea Actions | Runner CI | ✅ Oui | +| 4 | Tests automatisés (PHPUnit) | Gitea Actions | Runner CI | ✅ Oui | +| 5 | Connexion au serveur | SSH | Runner CD | ✅ Oui | +| 6 | Récupération du code | Git | Serveur | ✅ Oui | +| 7 | Build des conteneurs | Docker Compose | Serveur | ✅ Oui | +| 8 | Migrations BDD | Artisan | Serveur | ✅ Oui | +| 9 | Mise en cache config/routes/vues | Artisan | Serveur | ✅ Oui | +| 10 | Vérification post-déploiement | Endpoint `/up` (health check) | Équipe | Semi | + +## 6. Retour arrière (rollback) + +En cas de problème après un déploiement : + +- **Code** : `git revert` ou retour à un tag précédent, puis nouveau déploiement. +- **Base de données** : `php artisan migrate:rollback` (migrations réversibles). +- **Conteneurs** : redéploiement de l'image précédente via `docker compose`. + +## 7. Supervision + +- **Health check** : endpoint `/up` exposé par Laravel (voir `bootstrap/app.php`). +- **Journaux** : `storage/logs/laravel.log` + logs des conteneurs Docker. +- **Historique des déploiements** : onglet *Actions* de Gitea. diff --git a/docs/03-gestion-des-versions.md b/docs/03-gestion-des-versions.md new file mode 100644 index 0000000..5e9f529 --- /dev/null +++ b/docs/03-gestion-des-versions.md @@ -0,0 +1,61 @@ +# 03 — Outil de gestion des versions + +Projet **(RE)Sources Relationnelles** — Bloc INFCDAAL3 + +## 1. Outil choisi : Git + Gitea (auto-hébergé) + +Le versionnement du code repose sur **Git**, hébergé sur une instance +**Gitea** auto-hébergée par l'équipe : + +- Instance : `https://gitea.sam-coffre.duckdns.org/` +- Motivations du choix : + - **Maîtrise des données** : hébergement sur notre propre serveur (cohérent + avec un contexte ministériel / RGPD, pas de dépendance à un tiers). + - **Léger et open source** : Gitea est simple à administrer et gratuit. + - **Fonctionnalités complètes** : dépôts Git, *pull requests*, *issues*, + *releases*, et **Gitea Actions** (CI/CD) intégrés. + +## 2. Organisation du dépôt + +- **Branche principale** : `master` (branche de référence, protégée, déployée). +- **Branches de fonctionnalité** *(recommandé)* : une branche par fonctionnalité + (`feature/…`), fusionnée via *pull request* après relecture. +- Fichiers de configuration Git présents : `.gitignore`, `.gitattributes`, + `.editorconfig` (cohérence entre développeurs). + +## 3. Convention de nommage des commits + +Convention recommandée (type *Conventional Commits*) : + +``` +: + +Types : feat, fix, docs, style, refactor, test, chore +Exemples : + feat: ajout de la création de ressources + fix: correction de la redirection HTTPS + docs: rédaction du plan de sécurisation +``` + +## 4. Flux de travail (workflow) proposé + +1. Créer une branche depuis `master` : `git checkout -b feature/ma-fonctionnalite`. +2. Développer + commits atomiques. +3. Pousser la branche : `git push origin feature/ma-fonctionnalite`. +4. Ouvrir une **Pull Request** sur Gitea. +5. La **CI** (Pint + tests) s'exécute automatiquement sur la PR. +6. Relecture par un pair, puis fusion dans `master`. +7. La fusion déclenche le **déploiement automatique** en production. + +## 5. Gestion des livraisons (releases) + +- Utilisation des **tags Git** pour marquer les versions : `v1.0.0`, `v1.1.0`… +- Convention **SemVer** : `MAJEUR.MINEUR.CORRECTIF`. +- Les *Releases* Gitea documentent chaque version livrée (notes de version). + +## 6. Sécurité du dépôt + +- Aucun secret versionné : `.env`, clés et certificats sont exclus via + `.gitignore`. +- Accès au dépôt restreint aux membres de l'équipe (comptes Gitea). +- Historique complet et traçable (auteur, date, message de chaque modification). diff --git a/docs/04-gestion-des-evolutions.md b/docs/04-gestion-des-evolutions.md new file mode 100644 index 0000000..6fe9cfa --- /dev/null +++ b/docs/04-gestion-des-evolutions.md @@ -0,0 +1,63 @@ +# 04 — Outil de gestion des demandes d'évolutions et des incidents + +Projet **(RE)Sources Relationnelles** — Bloc INFCDAAL3 + +## 1. Outil choisi : les *Issues* de Gitea + +La gestion des évolutions et des incidents s'appuie sur le module **Issues** de +Gitea (déjà utilisé pour le code), ce qui évite d'ajouter un outil externe et +centralise le suivi au même endroit que le code et les déploiements. + +- Instance : `https://gitea.sam-coffre.duckdns.org/` + +## 2. Typologie des demandes (labels) + +Chaque demande est catégorisée par un **label** : + +| Label | Usage | +|-------|-------| +| `bug` | Incident / anomalie en production | +| `evolution` | Demande d'évolution fonctionnelle | +| `securite` | Faille ou correctif de sécurité (priorité haute) | +| `documentation` | Mise à jour de documentation | +| `priorite:haute` / `priorite:basse` | Niveau de priorité | + +## 3. Cycle de vie d'une demande + +``` +Ouverte → À traiter → En cours → En test (QA) → Résolue / Fermée +``` + +- Une *issue* est **liée à une branche et à une Pull Request** ; la fusion de la + PR ferme automatiquement l'issue (mot-clé `Closes #12` dans le commit). +- Le tableau **Projects (Kanban)** de Gitea permet de visualiser l'avancement + (colonnes : À faire / En cours / Terminé). +- Les **Milestones** regroupent les demandes par version cible (ex. `v1.1`). + +## 4. Processus de gestion des incidents (maintenance corrective) + +1. **Détection** : signalement (utilisateur, supervision, logs). +2. **Qualification** : création d'une issue `bug`, évaluation de la gravité. +3. **Priorisation** : affectation d'un label de priorité et d'un responsable. +4. **Correction** : branche `fix/…`, développement, tests. +5. **Validation** : CI verte + recette en QA. +6. **Déploiement** : fusion sur `master` → mise en production automatique. +7. **Clôture** : fermeture de l'issue, note de version si nécessaire. + +## 5. Processus de gestion des évolutions (maintenance évolutive) + +1. **Recueil du besoin** : issue `evolution` décrivant le besoin et la valeur. +2. **Analyse et estimation** : faisabilité, impact, charge. +3. **Planification** : affectation à un *milestone* / une version. +4. **Réalisation** : branche `feature/…`, développement + tests. +5. **Revue et intégration** : Pull Request relue, CI validée. +6. **Livraison** : déploiement continu, communication de la nouvelle version. + +## 6. Traçabilité + +Grâce à Gitea, chaque évolution est traçable de bout en bout : + +**Issue → Branche → Commits → Pull Request → CI → Déploiement → Release** + +Cette chaîne assure la traçabilité complète exigée pour la maintenance d'une +application manipulant des données sensibles. diff --git a/docs/Dossier-technique-INFCDAAL3.docx b/docs/Dossier-technique-INFCDAAL3.docx new file mode 100644 index 0000000..265d74b Binary files /dev/null and b/docs/Dossier-technique-INFCDAAL3.docx differ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..3f09baa --- /dev/null +++ b/docs/README.md @@ -0,0 +1,36 @@ +# Dossier de rendu — Bloc INFCDAAL3 + +**Déployer et sécuriser les applications informatiques** +Projet collaboratif : **(RE)Sources Relationnelles** + +Ce dossier regroupe les documents techniques attendus pour le bloc INFCDAAL3. +Il sert de base au **document écrit de 15 à 20 pages** demandé dans les consignes. + +## Sommaire + +| # | Document | Répond au critère de la grille | +|---|----------|--------------------------------| +| 01 | [Plan de sécurisation](01-plan-de-securisation.md) | Risques de sécurité, RGPD, chiffrement, prévention des risques | +| 02 | [Plan de déploiement](02-plan-de-deploiement.md) | Environnement de déploiement, automatisation, intégration continue, étapes et ressources | +| 03 | [Gestion des versions](03-gestion-des-versions.md) | Outil de gestion des versions (Gitea / Git) | +| 04 | [Gestion des évolutions](04-gestion-des-evolutions.md) | Outil de gestion des demandes d'évolutions et des incidents | + +## Correspondance avec la grille d'évaluation + +- **Déploiement de l'application** → doc 02 + fichiers `Dockerfile`, `docker-compose.yml`, `nginx.conf`, `.gitea/workflows/` +- **Maintenance** (gestion des versions et des évolutions) → docs 03 et 04 +- **Sécurité** (risques, RGPD, bonnes pratiques, plan de sécurisation) → doc 01 + code (`app/Http/Middleware/`, tests, Laravel Pint) +- **Organisation / Prestation orale** → non technique (support de soutenance ~10 slides) + +## Éléments techniques livrés dans le dépôt + +| Élément | Emplacement | Objectif | +|---------|-------------|----------| +| Intégration continue (qualité + tests) | `.gitea/workflows/ci.yml` | Automatiser Pint + PHPUnit à chaque push | +| Déploiement continu (SSH) | `.gitea/workflows/deploy.yml` | Automatiser la mise en production | +| Conteneurisation | `Dockerfile`, `docker-compose.yml` | Environnement reproductible | +| Serveur web / TLS | `nginx.conf` | Redirection HTTP→HTTPS, HTTPS | +| En-têtes de sécurité | `app/Http/Middleware/SecurityHeaders.php` | HSTS, CSP, X-Frame-Options, etc. | +| Forçage HTTPS | `app/Http/Middleware/ForceHttps.php` | Chiffrement du transport | +| Tests de sécurité | `tests/Feature/SecuriteTest.php` | Vérification automatisée | +| Qualité de code | `laravel/pint` (dev) | Standard PSR / style homogène | diff --git a/docs/Soutenance-INFCDAAL3.pptx b/docs/Soutenance-INFCDAAL3.pptx new file mode 100644 index 0000000..cf6db79 Binary files /dev/null and b/docs/Soutenance-INFCDAAL3.pptx differ diff --git a/resources/views/profile/settings.blade.php b/resources/views/profile/settings.blade.php index 8722d7c..90b5467 100644 --- a/resources/views/profile/settings.blade.php +++ b/resources/views/profile/settings.blade.php @@ -148,12 +148,39 @@

⚠️ Zone de danger

Les actions ci-dessous ne peuvent pas être annulées.

-
+ @csrf
+ +
+ + +

Supprimer mon compte

+

+ Conformément au RGPD, vous pouvez demander la suppression de votre compte. + Vos données personnelles (e-mail, pseudo) seront définitivement anonymisées. + Cette action est irréversible. +

+
+ @csrf + @method('DELETE') +
+ + +
+ +
diff --git a/routes/web.php b/routes/web.php index a3be1e1..3200755 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,16 +1,19 @@ name('home'); -Route::get('/form-csrf', function () {return view('form-csrf');}); +Route::get('/form-csrf', function () { + return view('form-csrf'); +}); -Route::get('/debug-https', function (Illuminate\Http\Request $request) { +Route::get('/debug-https', function (Request $request) { return response()->json([ 'isSecure' => $request->isSecure(), 'url' => $request->url(), @@ -44,4 +47,5 @@ Route::post('/logout', [LoginController::class, 'logout'])->name('logout'); Route::middleware('auth')->group(function () { Route::get('/profile/settings', [ProfileController::class, 'settings'])->name('profile.settings'); Route::put('/profile/update', [ProfileController::class, 'update'])->name('profile.update'); + Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); }); diff --git a/tests/Feature/SecuriteTest.php b/tests/Feature/SecuriteTest.php new file mode 100644 index 0000000..095404e --- /dev/null +++ b/tests/Feature/SecuriteTest.php @@ -0,0 +1,68 @@ +get('/'); + + $response->assertStatus(200); + $response->assertHeader('X-Content-Type-Options', 'nosniff'); + $response->assertHeader('X-Frame-Options', 'SAMEORIGIN'); + $response->assertHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); + $response->assertHeader('Content-Security-Policy'); + $response->assertHeader('Permissions-Policy'); + } + + /** + * Vérifie que les pages protégées redirigent un visiteur non authentifié + * vers la page de connexion (contrôle d'accès). + */ + public function test_les_pages_protegees_exigent_une_authentification(): void + { + $response = $this->get('/profile/settings'); + + $response->assertRedirect('/login'); + } + + /** + * Vérifie le droit à l'effacement RGPD : la suppression du compte + * anonymise bien les données personnelles de l'utilisateur. + */ + public function test_la_suppression_de_compte_anonymise_les_donnees(): void + { + $role = Role::create(['Nom' => 'Utilisateur']); + + $user = Utilisateur::create([ + 'Pseudo' => 'JeanDupont', + 'Email' => 'jean.dupont@example.com', + 'MotDePasse' => Hash::make('motdepasse123'), + 'ID_Role' => $role->ID_Role, + 'Statut' => 'Actif', + ]); + + $response = $this->actingAs($user)->delete('/profile', [ + 'MotDePasse_Confirmation' => 'motdepasse123', + ]); + + $response->assertRedirect('/'); + + $user->refresh(); + $this->assertSame('Utilisateur supprimé', $user->Pseudo); + $this->assertSame('Inactif', $user->Statut); + $this->assertStringNotContainsString('jean.dupont', $user->Email); + } +}