Options -Indexes -MultiViews

RewriteEngine On
RewriteBase /

# Hilangkan trailing slash pada file statis
RewriteRule ^(.+\.(?:css|js|mjs|map|webp|avif|png|jpg|jpeg|gif|svg|ico|json|webmanifest|woff2?|woff|ttf|eot|xml|txt))/$ $1 [R=302,L,NE]

# Route sensitive public paths through Core's cosmetic 404 before physical-file
# handling or per-directory access controls can reveal them with a 403.
RewriteRule ^(?:dev_lock\.php|views/.*\.php)$ router.php [L,QSA,NC]
RewriteRule (^|/)\. router.php [L,QSA]
RewriteRule \.(?:env|ini|log|sh|sql|bak|dist|ya?ml|md)(?:/|$) router.php [L,QSA,NC]

# Root PWA endpoints are dynamic and must replace any stale physical files.
RewriteRule ^(?:sw\.js|manifest\.webmanifest)$ router.php [L,QSA]

# Serve real files directly.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

# Execute only directories that intentionally expose an index.php. Physical
# directories without an entrypoint continue to Core's themed 404 renderer.
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME}/index.php -f
RewriteRule ^ - [L]

# Router fallback
RewriteRule ^ router.php [L,QSA]

# MIME yang sering bikin alert
AddType application/manifest+json .webmanifest
AddType image/svg+xml .svg
AddType application/xml .xml
AddType text/plain .txt

# Blokir file sensitif
<FilesMatch "\.(env|ini|log|sh|sql|bak|dist|yml|yaml|md)$">
    Require all denied
</FilesMatch>

<IfModule mod_headers.c>
    Header always unset X-Powered-By
    Header unset ETag
    Header always set Strict-Transport-Security "max-age=300"
    Header always set Content-Security-Policy-Report-Only "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'; script-src 'self' 'unsafe-inline' https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https: wss:; frame-src 'self' https://www.google.com https://www.youtube.com https://www.youtube-nocookie.com; media-src 'self' blob: https:; worker-src 'self' blob:"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
</IfModule>
