fix(borne): passerelle /api same-origin sur le vhost kiosk
All checks were successful
CI / static-tests (push) Successful in 52s
CI / php-lint (pull_request) Successful in 23s
CI / secret-scan (push) Successful in 12s
CI / php-lint (push) Successful in 24s
CI / js-tests (push) Successful in 27s
CI / secret-scan (pull_request) Successful in 10s
CI / static-tests (pull_request) Successful in 53s
CI / js-tests (pull_request) Successful in 27s

La borne consommait /api en chemin relatif sur sa propre origine
(APP_HOST_KIOSK), ou aucune API n'est routee : le fallback SPA du vhost
kiosk renvoyait index.html (HTML) -> data.js plantait sur res.json() ->
catalogue vide ("pas cable"). Le middleware CORS livre en #61 n'etait donc
jamais sollicite (la borne ne sortait pas vers l'origine API).

Fix : le vhost kiosk relaie /api/* au front controller admin via PHP-FPM.
ProxyFCGISetEnvIf force SCRIPT_FILENAME sur public/admin/index.php (sinon FPM
rejette en "Access denied" : l'extension != .php). REQUEST_URI est preserve,
le Router route correctement. data.js inchange (URLs relatives desormais
correctes en same-origin). Seul /api est relaye : le back-office (/login,
/admin/*) reste hors de l'origine borne. CORS conserve en defense en
profondeur (doc conventions section 10).

Verifie sur la vraie stack : /api/categories|products|menus|products/{id}|
menus/{id} depuis l'origine borne -> 200 application/json ; /login et
/admin/dashboard cote borne -> SPA borne (pas le back-office) ; admin direct
+ home borne sans regression.
This commit is contained in:
Imugiii 2026-06-19 14:11:43 +00:00
parent 7a0702ff6e
commit 988c1bbbdd
2 changed files with 33 additions and 3 deletions

View file

@ -55,7 +55,10 @@
# SPA-like fallback : toute URL non-fichier -> index.html # SPA-like fallback : toute URL non-fichier -> index.html
# (pour permettre de bookmarker un chemin profond dans la borne). # (pour permettre de bookmarker un chemin profond dans la borne).
# Exclusion /api/ : ces requetes sont relayees a l'API (cf. <Location /api>
# plus bas) et ne doivent JAMAIS retomber sur index.html.
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_URI} !^/api/
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L] RewriteRule ^ index.html [L]
@ -66,6 +69,28 @@
Require all denied Require all denied
</Directory> </Directory>
# === API en MEME origine (P4 - passerelle same-origin) ===
# La borne consomme l'API publique (/api/*) sur SA PROPRE origine : ce vhost
# relaie ces requetes au front controller admin via PHP-FPM. data.js garde
# donc ses URLs relatives (/api/categories...) -> aucune requete cross-origin
# cote borne -> CORS inutile pour ce parcours (le middleware reste en place
# cote API comme defense en profondeur). SEUL /api est relaye : le back-office
# (/login, /admin/*) n'est PAS joignable depuis l'origine borne.
#
# Le chemin apres host:port dans l'URL fcgi EST le SCRIPT_FILENAME envoye a
# FPM : on le force sur le front controller admin (un .php REEL). Sans ca, FPM
# recevrait un chemin sous le docroot borne sans extension .php et rejetterait
# (security.limit_extensions par defaut = .php -> reponse "Access denied").
# ProxyPassMatch intercepte des la phase translate -> le faux chemin
# /.../borne/api/... n'est jamais calcule. REQUEST_URI (=/api/categories) et la
# query string sont preserves -> le Router (qui lit REQUEST_URI) route correctement.
ProxyPassMatch "^/api(/.*)?$" "fcgi://wakdo-app:9000/var/www/html/public/admin/index.php"
# mod_proxy_fcgi derive un SCRIPT_FILENAME corrompu (prefixe proxy: + chemin
# original colle apres index.php) -> FPM rejette (extension != .php). On force
# la valeur sur le front controller admin (un .php REEL) ; REQUEST_URI reste
# intact, donc le Router route correctement.
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/var/www/html/public/admin/index.php"
# Compression text/html, css, js, json (Cr 1.e.8 temps de chargement). # Compression text/html, css, js, json (Cr 1.e.8 temps de chargement).
<IfModule mod_deflate.c> <IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/javascript \ AddOutputFilterByType DEFLATE text/html text/css text/javascript \

View file

@ -307,9 +307,14 @@ ici.
## 10. CORS ## 10. CORS
L'API admin sous `/api/*` autorise l'origine du kiosk via `CORS_ALLOWED_ORIGIN` (valeur exacte, La borne consomme `/api/*` en **meme origine** : le vhost kiosk (`docker/apache/vhost.conf`)
sans joker), configuree dans `docker/apache/vhost.conf`. L'origine doit correspondre a relaie `/api/*` au front controller admin via PHP-FPM (`ProxyPassMatch` + `ProxyFCGISetEnvIf`
`APP_URL_KIOSK`. qui force `SCRIPT_FILENAME` sur `public/admin/index.php`). `data.js` garde donc des URLs
relatives et le navigateur n'emet pas de requete cross-origin pour ce parcours.
Le middleware `App\Core\Cors` reste en place comme defense en profondeur : il lit
`CORS_ALLOWED_ORIGIN` (valeur exacte, sans joker, = `APP_URL_KIOSK`) et autorise un eventuel
consommateur cross-origin de l'API. Il n'est pas sur le chemin de la borne.
--- ---