# wms-app — web server rules for the repository root. # # The whole repository sits under the web root (/wms-app/), so everything that is # not part of the running app must be refused here: git history, .env files, # deployment and build folders, SDLC documents, the Node server source, CLI-only # PHP scripts and library internals. Needs AllowOverride All (docker/php/apache-wms.conf # enables it for the container) plus mod_rewrite and mod_headers. Options -Indexes RewriteEngine On # HTTP → HTTPS when the deployment says TLS is available (FORCE_HTTPS=true in the # environment). Honours X-Forwarded-Proto so it also works behind a TLS proxy. RewriteCond %{ENV:FORCE_HTTPS} ^true$ RewriteCond %{HTTPS} !=on RewriteCond %{HTTP:X-Forwarded-Proto} !=https RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # Dotfiles and dot-folders anywhere: .git, .env, .claude, .htaccess, .mcp.json … RewriteRule (^|/)\. - [R=404,L] # Folders that are never served. RewriteRule ^(nodejs|docker|sdlc|sdlc-delivery|scripts|lib|notes|docs|vendor|node_modules)(/|$) - [R=404,L] # Repository files at the root: build/deploy config, CLI scripts, archives, docs. RewriteRule ^(composer\.(json|lock)|docker-compose\.ya?ml|setup\.php|demo_seed[^/]*\.php)$ - [R=404,L] RewriteRule \.(zip|tar|gz|tgz|sql|sh|md|log|bak|old|orig|swp|dist|example|ini|yml|yaml|lock|env|pem|key|crt|map)$ - [R=404,L] # App internals included by the entry points, never requested directly: config, # DB connection, shared utilities, manager classes, bundled libraries (PHPMailer # ships get_oauth_token.php), and the page fragments. RewriteRule ^app/(config[^/]*\.php|dbconn\.php|preset\.php)$ - [R=404,L] RewriteRule ^app/assets/utils/ - [R=404,L] RewriteRule ^app/include_[^/]+\.php$ - [R=404,L] # Uploaded files are served through a PHP gate that requires a signed-in session. RewriteRule ^app/uploads/(.+)$ app/file.php?path=$1 [L,QSA,B] # Sent on every response (pages, API JSON, static files). Pages add a # Content-Security-Policy of their own from include_header.php. Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "geolocation=(), microphone=(), payment=(), usb=()" Header always unset X-Powered-By Header unset X-Powered-By # HSTS only means anything over HTTPS; browsers ignore it on plain HTTP. Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" "expr=%{HTTPS} == 'on' || %{HTTP:X-Forwarded-Proto} == 'https'"