# CS2 Services - document root rules.
# Works on cPanel and in the Docker container (both Apache with AllowOverride All).
#
# ── IF YOUR HOST ALREADY PUT AN .htaccess IN public_html ──────────────────
# cPanel generates its own blocks - the PHP version handler and error_log
# settings, each wrapped in "do not edit" comments. Uploading this file on top
# of them deletes them, which loses your PHP handler and your error log.
#
# Keep both: paste the cPanel-generated blocks ABOVE this line, then leave
# everything below untouched. The two do not conflict - cPanel's blocks set the
# PHP handler, these set routing and security headers.
#
# If the site returns HTTP 500 after uploading, comment out the "Options
# -Indexes" line first: a few hosts do not allow Options in .htaccess, and
# Apache answers a disallowed directive with a 500 rather than ignoring it.
# ──────────────────────────────────────────────────────────────────────────

Options -Indexes

# The pages are PHP now; there are no .html files left to fall back to.
DirectoryIndex index.php

<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "same-origin"
    # Nothing here needs a camera, mic or location.
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

# Belt and braces. config.php and lib/ live above the document root, so these
# should be unreachable anyway - but a future deploy that flattens the layout
# would otherwise serve credentials as plain text.
<FilesMatch "^(config\.php|.*\.(sql|ini|log|md|json|lock|sh))$">
    Require all denied
</FilesMatch>

# Dotfiles: .env, .git, editor leftovers.
<FilesMatch "^\.">
    Require all denied
</FilesMatch>

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Force HTTPS in production. Skipped for localhost so the Docker stack
    # works on plain http.
    RewriteCond %{HTTPS} off
    RewriteCond %{HTTP_HOST} !^localhost [NC]
    RewriteCond %{HTTP_HOST} !^127\.0\.0\.1 [NC]
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]


    # Clean URLs. The pages are PHP; visitors should never see the extension.
    #
    # /free            -> free.php
    # /free.php|.html  -> /free           (301, so old links and any bookmark
    #                                      made before this change still land)
    # Crawler files. Generated by PHP so the URLs inside them always carry the
    # configured host rather than a domain hardcoded at build time.
    RewriteRule ^robots\.txt$       robots.php   [L]
    RewriteRule ^sitemap\.xml$      sitemap.php  [L]
    RewriteRule ^site\.webmanifest$ manifest.php [L]

    RewriteRule ^install/?$ install.php [L]
    RewriteRule ^free/?$    free.php    [L]
    RewriteRule ^terms/?$   terms.php   [L]
    RewriteRule ^privacy/?$ privacy.php [L]

    # Matched against THE_REQUEST, not the path: after the rule above rewrites
    # /free to free.php internally, the path would match too and the redirect
    # would loop. THE_REQUEST holds what the browser actually asked for.
    RewriteCond %{THE_REQUEST} "\s/+free\.(php|html)[\s?]" [NC]
    RewriteRule ^ /free? [R=301,L]

    RewriteCond %{THE_REQUEST} "\s/+terms\.(php|html)[\s?]" [NC]
    RewriteRule ^ /terms? [R=301,L]

    RewriteCond %{THE_REQUEST} "\s/+privacy\.(php|html)[\s?]" [NC]
    RewriteRule ^ /privacy? [R=301,L]

    RewriteCond %{THE_REQUEST} "\s/+index\.(php|html)[\s?]" [NC]
    RewriteRule ^ /? [R=301,L]

    # Anything else still asking for a .html file we no longer serve.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.+)\.html$ /$1 [R=301,L]

    # cPanel/Apache strips the Authorization header before PHP sees it, which
    # silently breaks the worker's bearer token. Put it back.
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>

# Cache static assets, never the API.
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 7 days"
    ExpiresByType application/javascript "access plus 7 days"
    ExpiresByType image/svg+xml "access plus 30 days"
    ExpiresByType image/png "access plus 30 days"
</IfModule>

<IfModule mod_headers.c>
    # Pages and API responses must never be cached: they carry session state.
    # robots.php, sitemap.php and manifest.php are the exceptions - they are
    # public, identical for everyone, and set their own cache lifetime. Without
    # this exclusion the header below would override theirs and make crawlers
    # re-fetch the sitemap on every visit.
    <FilesMatch "\.php$">
        Header always set Cache-Control "no-store, no-cache, must-revalidate"
    </FilesMatch>
    <FilesMatch "^(robots|sitemap|manifest)\.php$">
        Header unset Cache-Control
        Header always set Cache-Control "public, max-age=3600"
    </FilesMatch>
</IfModule>

# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php82” package as the default “PHP” programming language.
<IfModule mime_module>
  AddHandler application/x-httpd-ea-php82 .php .php8 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit
