{{- include "common.values.setup" . -}}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "common.names.fullname" . }}-config
  labels:
    {{- include "common.labels" . | nindent 4 }}
data:
  Caddyfile: |-
    {
      admin off
    {{- if .Values.caddy.noTls }}
      auto_https off
    {{- end }}
    }

    :80 {
        log {
            output discard
        }

        @api {
            path /config
            path /status
        }

        @static {
            path /static/*
        }

        @notstatic {
            not path /static/*
        }

        @morty {
            path /morty/*
        }

        @notmorty {
            not path /morty/*
        }

        header {
            # Enable HTTP Strict Transport Security (HSTS) to force clients to always connect via HTTPS
            Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

            # Enable cross-site filter (XSS) and tell browser to block detected attacks
            X-XSS-Protection "1; mode=block"

            # Prevent some browsers from MIME-sniffing a response away from the declared Content-Type
            X-Content-Type-Options "nosniff"

            # Disallow the site to be rendered within a frame (clickjacking protection)
            X-Frame-Options "SAMEORIGIN"

            # Disable some features
            Permissions-Policy "accelerometer=();ambient-light-sensor=(); autoplay=();camera=();encrypted-media=();focus-without-user-activation=(); geolocation=();gyroscope=();magnetometer=();microphone=();midi=();payment=();picture-in-picture=(); speaker=();sync-xhr=();usb=();vr=()"

            # Disable some features (legacy)
            Feature-Policy "accelerometer 'none';ambient-light-sensor 'none'; autoplay 'none';camera 'none';encrypted-media 'none';focus-without-user-activation 'none'; geolocation 'none';gyroscope 'none';magnetometer 'none';microphone 'none';midi 'none';payment 'none';picture-in-picture 'none'; speaker 'none';sync-xhr 'none';usb 'none';vr 'none'"

            # Referer
            Referrer-Policy "no-referrer"

            # X-Robots-Tag
            X-Robots-Tag "noindex, noarchive, nofollow"

            # Remove Server header
            -Server
        }

        header @api {
            Access-Control-Allow-Methods "GET, OPTIONS"
            Access-Control-Allow-Origin  "*"
        }

        # Cache
        header @static {
            # Cache
            Cache-Control "public, max-age=31536000"
            defer
        }

        header @notstatic {
            # No Cache
            Cache-Control "no-cache, no-store"
            Pragma "no-cache"
        }

        # CSP (see http://content-security-policy.com/ )
        header @morty {
            Content-Security-Policy "default-src 'none'; style-src 'self' 'unsafe-inline'; form-action 'self'; frame-ancestors 'self'; base-uri 'self'; img-src 'self' data:; font-src 'self'; frame-src 'self'"
        }

        header @notmorty {
            Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self'; font-src 'self'; frame-ancestors 'self'; base-uri 'self'; connect-src 'self' https://overpass-api.de; img-src 'self' data: https://*.tile.openstreetmap.org; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com"
        }

        # Morty
        handle @morty {
            reverse_proxy localhost:3000
        }

        # Filtron
        handle {
            encode zstd gzip

            reverse_proxy localhost:4040 {
                header_up X-Forwarded-Port {http.request.port}
                header_up X-Forwarded-Proto {http.request.scheme}
                header_up X-Forwarded-TlsProto {tls_protocol}
                header_up X-Forwarded-TlsCipher {tls_cipher}
                header_up X-Forwarded-HttpsProto {proto}
            }
        }
    }
  rules.json: |-
    [
        {
            "name": "searx.space",
            "filters": ["Header:X-Forwarded-For=nslookup(check.searx.space)"],
            "stop": true,
            "actions": [{ "name": "log"}]
        },
        {
            "name": "IP limit, all paths",
            "interval": 3,
            "limit": 25,
            "aggregations": ["Header:X-Forwarded-For"],
            "actions": [
                {"name": "block",
                "params": {"message": "Rate limit exceeded, try again later."}}
            ]
        },
        {
            "name": "useragent limit, all paths",
            "interval": 30,
            "limit": 200,
            "aggregations": ["Header:X-Forwarded-For", "Header:User-Agent"],
            "stop": true,
            "actions": [
                {"name": "block",
                "params": {"message": "Rate limit exceeded, try again later."}}
            ]
        },
        {
            "name": "search request",
            "filters": ["Param:q", "Path=^(/|/search)$"],
            "subrules": [
                {
                    "name": "allow Firefox Android (issue #48 and #60)",
                    "filters": [
                        "Param:q=^1$",
                        "Header:User-Agent=(^MozacFetch/[0-9]{2,3}.[0-9].[0-9]+$|^Mozilla/5.0 \\(Android [0-9]{1,2}(.[0-9]{1,2}.[0-9]{1,2})?; Mobile; rv:[0-9]{2,3}.[0-9]\\) Gecko/[0-9]{2,3}.[0-9] Firefox/[0-9]{2,3}.[0-9]$)"
                    ],
                    "stop": true,
                    "actions": [{"name": "log"}]
                },
                {
                    "name": "robot agent forbidden",
                    "limit": 0,
                    "stop": true,
                    "filters": ["Header:User-Agent=([Cc][Uu][Rr][Ll]|[wW]get|Scrapy|splash|JavaFX|FeedFetcher|python-requests|Go-http-client|Java|Jakarta|okhttp|HttpClient|Jersey|Python|libwww-perl|Ruby|SynHttpClient|UniversalFeedParser)"],
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "bot forbidden",
                    "limit": 0,
                    "stop": true,
                    "filters": ["Header:User-Agent=(Googlebot|GoogleImageProxy|bingbot|Baiduspider|yacybot|YandexMobileBot|YandexBot|Yahoo! Slurp|MJ12bot|AhrefsBot|archive.org_bot|msnbot|MJ12bot|SeznamBot|linkdexbot|Netvibes|SMTBot|zgrab|James BOT|Sogou|Abonti|Pixray|Spinn3r|SemrushBot|Exabot|ZmEu|BLEXBot|bitlybot)"],
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "block missing accept-language",
                    "filters": ["!Header:Accept-Language"],
                    "limit": 0,
                    "stop": true,
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "block Connection:close",
                    "filters": ["Header:Connection=close"],
                    "limit": 0,
                    "stop": true,
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "block no gzip support",
                    "filters": ["!Header:Accept-Encoding=(^gzip$|^gzip[;,]|[; ]gzip$|[; ]gzip[;,])"],
                    "limit": 0,
                    "stop": true,
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "block no deflate support",
                    "filters": ["!Header:Accept-Encoding=(^deflate$|^deflate[;,]|[; ]deflate$|[; ]deflate[;,])"],
                    "limit": 0,
                    "stop": true,
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "block accept everything",
                    "filters": ["!Header:Accept=text/html"],
                    "limit": 0,
                    "stop": true,
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded"}}
                    ]
                },
                {
                    "name": "rss/json limit",
                    "interval": 3600,
                    "limit": 4,
                    "stop": true,
                    "filters": ["Param:format=(csv|json|rss)"],
                    "aggregations": ["Header:X-Forwarded-For"],
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded, try again later."}}
                    ]
                },
                {
                    "name": "IP limit",
                    "interval": 3,
                    "limit": 3,
                    "aggregations": ["Header:X-Forwarded-For"],
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded, try again later."}}
                    ]
                },
                {
                    "name": "IP and useragent limit",
                    "interval": 600,
                    "limit": 60,
                    "stop": true,
                    "aggregations": ["Header:X-Forwarded-For", "Header:User-Agent"],
                    "actions": [
                        {"name": "block",
                        "params": {"message": "Rate limit exceeded, try again later."}}
                    ]
                }
            ]
        }
    ]
