quorate/services/bot-redirect/bots.fsx

95 lines
3.4 KiB
Text
Raw Normal View History

open System
open System.Text.Json
open System.Text.RegularExpressions
type Bot =
{ Slug: string
Patterns: string list
Examples: string list
Signer: string option }
type Header =
{ Name: string
Kind: string
Value: string }
let strings (value: JsonElement) name =
value.GetProperty(name: string).EnumerateArray()
|> Seq.map _.GetString()
|> Seq.toList
let decode (value: JsonElement) =
{ Slug = value.GetProperty("slug").GetString()
Patterns = strings value "userAgentPatterns"
Examples = strings value "userAgents"
Signer =
match value.TryGetProperty "signatureAgentUrl" with
| true, url when url.ValueKind = JsonValueKind.String -> Some(url.GetString())
| _ -> None }
let headers excluded bot =
let patterns = bot.Patterns |> List.map (fun value -> value.Trim(' ', '\t'))
[ for pattern in patterns do
{ Name = "User-Agent"
Kind = "RegularExpression"
Value = ".*" + Regex.Escape(pattern) + ".*" }
for example in bot.Examples do
if
not (Set.contains example excluded)
&& not (patterns |> List.exists example.Contains)
then
{ Name = "User-Agent"
Kind = "Exact"
Value = example.Trim(' ', '\t') }
match bot.Signer with
| Some signer ->
{ Name = "Signature-Agent"
Kind = "Exact"
Value = JsonSerializer.Serialize signer }
| None -> () ]
let routes config matches =
let text name =
(config: JsonElement).GetProperty(name: string).GetString()
matches
|> List.distinct
|> List.chunkBySize 128
|> List.mapi (fun index chunk ->
{| apiVersion = "gateway.networking.k8s.io/v1"
kind = "HTTPRoute"
metadata =
{| name = $"bot-redirect-{index}"
``namespace`` = text "namespace"
labels = Map [ ("app.kubernetes.io/managed-by", "bot-redirect") ] |}
spec =
{| parentRefs =
[| {| name = text "gateway"
``namespace`` = text "gatewayNamespace"
sectionName = "https" |} |]
hostnames = [| text "source" |]
rules =
chunk
|> List.chunkBySize 64
|> List.map (fun group ->
{| matches =
group
|> List.map (fun header ->
{| headers =
[| {| name = header.Name
``type`` = header.Kind
value = header.Value |} |] |})
filters =
[| box
{| ``type`` = "RequestRedirect"
requestRedirect =
{| hostname = text "target"
port = 443
statusCode = 301 |} |}
box
{| ``type`` = "ResponseHeaderModifier"
responseHeaderModifier =
{| set =
[| {| name = "X-Robots-Tag"
value = "noindex" |} |] |} |} |] |}) |} |})