Options -Indexes
DirectoryIndex index.php


<IfModule mod_rewrite.c>
    RewriteEngine On

    # Hosting metapodaci i lokalna kontrola verzija nisu aplikacioni endpointi.
    # ACME/DCV validacione putanje ostaju pod kontrolom hostinga.
    RewriteRule ^(?:\.git|\.ssl-manager|\.well-known/ssl-manager)(?:/|$) - [F,L,NC]

    # SEC-AVATAR-ACCESS-CONTROL: nijedan avatar se ne servira direktno iz upload foldera.
    # Prikaz je dozvoljen isključivo kroz autentifikovani serve_avatar.php endpoint.
    RewriteRule ^uploads/avatars(?:/|$) - [F,L,NC]

    # SEC-ATTACHMENT-ACCESS-CONTROL: prilozi se preuzimaju samo kroz attachment_download.php.
    # Ovo je dodatna zaštita ako nested .htaccess nije prenet uz persistent uploads folder.
    RewriteRule ^uploads/tickets(?:/|$) - [F,L,NC]

    # Microsoft Entra ID rute imaju stabilne URL-ove registrovane u Entra portalu.
    RewriteRule ^auth/entra/login/?$ auth_entra_login.php [L,QSA,NC]
    RewriteRule ^auth/entra/callback/?$ auth_entra_callback.php [L,QSA,NC]

    # Composer biblioteke nisu javni web endpointi.
    RewriteRule ^vendor(?:/|$) - [F,L,NC]

    # Nepostojeće datoteke i rute interno se prosleđuju prilagođenoj 404 stranici.
    # Relativna zamena radi i kada je aplikacija instalirana u podfolderu.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ 404.php [L]
</IfModule>

<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "DENY"
    Header set Referrer-Policy "strict-origin-when-cross-origin"
    Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    Header set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
</IfModule>

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 30 days"
    ExpiresByType application/javascript "access plus 30 days"
    ExpiresByType image/svg+xml "access plus 30 days"
    ExpiresByType image/jpeg "access plus 30 days"
    ExpiresByType image/png "access plus 30 days"
    ExpiresByType image/webp "access plus 30 days"
</IfModule>

<FilesMatch "(?i)^(config\.php|config\.example\.php|composer\.(?:json|lock)|baza\.sql|database\.sql|README\.md|CHANGELOG\.md|SECURITY\.md|SEC-AVATAR-ACCESS-CONTROL\.md|SEC-AVATAR-IDOR-PREVENTION\.md|SEC-AVATAR-RBAC-ACCESS-CONTROL\.md|SECURITY_PERFORMANCE_PATCH\.md|\.productionignore|error_log)$">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
    <IfModule !mod_authz_core.c>
        Deny from all
    </IfModule>
</FilesMatch>

# Lokalna environment konfiguracija i instalacioni arhiv ne smeju biti javni.
<FilesMatch "(?i)^(\.env(?:\..*)?|\.user\.ini(?:\.example)?|\.gitignore|.*secrets.*\.php|entra-shared-hosting-vendor\.zip)$">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
    <IfModule !mod_authz_core.c>
        Deny from all
    </IfModule>
</FilesMatch>

# Development/QA artefakti ostaju u source projektu, ali nisu javni web endpointi.
<FilesMatch "(?i)^(qa_.*|qa_results_.*|upgrade_.*|test_.*|runtime_.*)$">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
    <IfModule !mod_authz_core.c>
        Deny from all
    </IfModule>
</FilesMatch>

# SQL migracije i tehnička dokumentacija nikada se ne serviraju direktno.
<FilesMatch "(?i)\.(?:sql|md|log)$">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>
    <IfModule !mod_authz_core.c>
        Deny from all
    </IfModule>
</FilesMatch>
