import { createClient } from "@libsql/client/web"; import * as BunnySDK from "@bunny.net/edgescript-sdk"; import process from "node:process"; // --------------------------------------------------------------------------- // Embedded bloom filter (updated by bouncer.py via BunnyCDN API) // --------------------------------------------------------------------------- const BLOOM_B64 = "tBgBAAcAAACOmJnIe7yJjDGrkCYuyIrKiuKIK6Mqvqfgpgq6/4rKnvY83wqOrMQvKAxKCr6tqYPJmHitHs6ieIujmZuyMiqq+skqzKfk3viOFjrnqD6uKrqoDv2Iro8vnC2xibGYiCuJiqmDn7w5mtorg4qWSLpnqxps66Jfqpqqmgzifou2i4KIC7ql7F4b9vq5rJg+q64d6k6xa6gS6KOoAgqi0bHGI7rj7Jq6AkauwX9RvMhFtIi/u/iki3rqov246wsKrJMmmMx2+Yq6mSIPqBCGSZqqnsizcsoOKTqrr2go+oigRZq7uLLojJXKI3VLauVqgDvq6ooju4OIxo4Irj4d5qqokLYY6IQsgt+qiG7ciomarku8KteAm+MogbwIuLi8uusRq8Tkrpq6MtRJ6aKYqpv4uUwuuctSkjAIokHsg5iLKPryC2KLj4Lqv4yrqrpw7giinlcKxZ6a6YwP6yj+r7TiOslIgTmb2LqcruOmgrSpuaqtPKmKk75oCn6P6wuNTzOIzqmM7Aou7qwqqI/ui0xROyoOn/C6rtgMUKfq5CoNiaxc6baq6nJuv/voJSzq74ErosDpmwC/mLoEIKaqrKiYvccqMowjsq7ciF6aT/iICCCoh3oqrOFoLpTqox6OilzaCo6curDsp4rE6o/JjY8eroivCpwogpqpyruHDA3qh+BQaqkhhe/jLqX4/gXpMISJijzYnquYu//KIK7iy4qMiOsaDSL7f8a0TuC+P5M7yPqNOIaDqqubOgH8nrK/6QmqqCDAqKKmQCeLjO854qqgKbK0quHW+Ci5gMCK+oKYyj2KjqoYip+67WnaCDnorZOLiOir+qkoM4ifHuyjugjCD7qvaYqqqM6oqFyhsrz2Tvjgyab39ArOMp6rBmqI66Kijm7yyIouqva7+ZKoqXnUqK8tKi0ug+xADuozs6ug0vvoirGnNjn5v62Ij0rKvu04qp2MZqHCubCKjo64YSOSar+DaujKhrqKikKAieaoPM6UqrjsuYDqraiJfEqwjaooqj7N5q2qoIzonPR/LqjdqOnOuuIOqnqnoO7KCMxgrhyeqhyoi5WKLp6vD+YKnOb7n60DTqii9qP8LrCYkXriaoCS6IgaqCECuy+Kn567naXu/u/IlpSyGjapl6uk7q4q2q3IK7jKqyo2+WVoCAsKz6luuJ6fS8iCCcqs6P6q3t+oqMi7MpJ66tqcs+qc6Iyv66OayrrO4bequstDi5Kq7QiLKLwqna7wvimOaK+q7ejujWvIptnJyppnYOnuYPqJ3sPziYuoj5wKnrOOGKm9rjs6ZKgqqouh4rnoLDiv7mi8pu+Ihtnj/7iPitqqmGmki9v7jMgf64q4g+0pmrmspK3zrAiIOziLsKCsq+j4OTh064QyipC9QxywePCquQ7kmaOIqpIIjU4pmRCbmrjpG6qrmo4Xt46J6kiKwISquDCoawO8toIqssrpmnIhLrrqqkjeqqoZuLvjtsynquqI2Y+JsDgqvq6y7kuouamI6uyE4e3//wql7qGZWiCquYTmDcwL4Krpqr6+rqurCozJzAGqyvojf+hIvqqjKgKBmKgO56mYFgrw/5KbIUwuqpyPpbiimVq6SwiuYm3J6+HuK4FyOu776airqKWqicmeqLrI83TuScibCYokqdEYomvvf4zhSqAo+iyYANwkuqyzCoiKuQkJy/4I45OpmWKrv0zgd+LwIL+mna4I6KCiq+MJ577cqOmIi6g6jcmGjujK5gx07vrcuw27jO8sbLxqmoqh+qfNvuur6q+6zjmap4gagvJcq8isj/+sgt3IuoGOgrjK6AEtqLqm7DuaK8C6+qu4irOKxxarrIvp6ghBs8qqqtKvKQ7zkaiqvsiKqoijoqS5sRWJ+VpIyagerCk4qIiAKezq+DLq7q/aa7ynqwyJ2EeK2rNKp5yJj6Z4yIqwmcqKKwKYntif+pyAuqqfIKpqtGhopqCqTaWN68+aubNAsT8yaalzkjq+6EKLj7WIP8y5G7hL+7KOCD4Y6uqoKq/oGGFKAsmartvoyOt4SzA/0AjrenpgiBtaginI7I6Y+pI7uJGo2KKYoocWg6qK4x6gyEjpqv2a6KTq7Tgo2q/YEIjMuMVKjROpzGkPzMrJiHJp4ECYL6hO7BvnLooAuGjCwqszmkiWLp1G+5ojr+K6mgi7wraAZz2a/I264qrJiYqEYNglKODB6Jw7roosw4GyijlvmoqSjIPo772E6u6gGbqJoBUu8UwK48ox6Sjo/I7qmNqmGYyqaaqrqQ6AiJK6iqCbxo/qGorOhyiqjBIu0BqpkY2JqSGQaEa6+OGaAW2eiwiqqiuqaqSL2uIsm76bPqmknJuK+k6k4KGM6n6HOY9tjWPIDyno6zq4h4bOwNyfw8KPULvnDGsGg4iDKLrI6wf7qciuj76o8O65hrirqJkcCKyIyLbJvAiqLoisqSK76hkhit5U7i3+iqH9kruCj5mXsioZsY7+WSiAqvyNgBsl6jzorMgobCSlhZ6mr2KOwoC+iyv25PGuaMPAfs+Pu7LTqijqirqvKaKs+eLPwuqoaKWFjpOu6ayKrqDqKbSOoqzqaTDuS8sqqkCtOKujn1RaoJu/jtpKq+A6goALh+6qn7i2+r6JxYy2thiaKkn76/i5rZ0562qoevtzuyqwawqv6siWy3IOuSzqCynvopi7Geg66imQ4zqomQgKuM6O26gLqLBbjmqUowwJAB9tipyMupDqdhppIyLMnrqvi6+P63ju+hrrK8qSUnuGmo00S83OxrwkkcFziWesflp0kM6UaIkkqueSMuap3BHJrgwutlzLjvjqi8gc7YKuKij4GYqjPLLoeJjqiG74CKjLCyNgaKW6IAaKIsyCuOMujumClp+Kmd0lbCKjiOMhiWi+suySrfmArYjByCgsaoru6BaOgKjDqo1JoK0wR2IIlirou7ruk9+YqIOOyIvTrqCrCDuwgrjKuQJ5+4oi3pi7rB/Qa4iqqjCYGtoKn6tg6Qj/q86L+JkEHoyKItglarilinDMtAKImKi4t+qptr7umPqEspe4uoqYqjgep8gMTtzKy8/pkqzuoqgqi6qgrtYoirL62jwzudvvLegaHqkuxIiWk/JUPj5uqpDaLo6fpiqo7iLIKrSUTuYBfXTouY9nuq6LOdq9GALsDr7tAlawTNQoru7l4izLDq+4Lxyq26G4avrGsKuMKheD/qObikwue7rkPBaKKC6b7/86moiKaIqoSomAKLtKDKuA7IskiQhKsgjMmKGI8LkIihrqOL+7D6opiAuvoE6aiBm7oo+I7KfoOogoS6yok+rPrunQzJuqq5moyLmaK8qJliitqUrMnpKOIPz/LZKCoqACgoSFvmhqvirqoLDM4p4LuoCKgPn9cuwCyu/s6LoVrq7ZnyKGmyzyqureqL3YKYY3PrHIKbeOrtuviQ2Ji75Qv+ndi05ihIjqjIdIpPXx4g6Kk4WrrhyMqPyZoty05ntLiq6sOKoN3pI6cpuLesS/jSeoKsoPKY3yBYgEoI/r/o+Vg96qBUqJaHkKYssqKpip7CKQyKgaj4KEqaAuGcOcwonvSuxCpUuACdnTrt5brLl2qWa/Ka6ioryviSvtgrbXjoICyjOLP+qgYuCLgJ+buBKToo6Kzh++ooaFnP6WzyyAh4ySt6KKDqKurmi4tho5vVCvuC5sgzM6n+iqztusg8jLqoiCOs8gLb/h7JugOp7I0wTKiIv/q6RAI6mEgL46skS5LKwisHs6I7yCzbnOpeqCp6yjoMTaXkKCu8qNjIqLqCvg2KoPzoiOLyub7IjOqmCKqQ4KoYCiqhu639Dqn2SJPISCLomq6juBe++DgXwPGPiJ4Hy6vveoRx8bqM6PrPoSq7GNyP2AvDaguYysqrnqAMeKbGuHa4XHe+Szro6dSq6IiazKyKLBj1fQGazWuWgL7ras6RSPpIqxiIC5vNvqJOm6CIquuopo8caJxJyq6NHIu+hgpoPLc4iOU8uNDqjtzuig2nztKN7v+b++29gKowr/6xicngLePticsmKmmqymgPjYnISoJug4oqO6Cqls3q2PD8nguMk6nOmTKu7Yis1/iiCHmq6/qqDJu8gqwLruCKq4rS063OhuqPnnLm68+Ma47saoK6rD6x7t/spai97ezK44riD6T5myjansq10PpYUtLIjIn/F48aGsLYqLkLuHjAEuiyCpu0o4IYq9vinhMv+QqsqTrMrppUKda/KKqYjJsoq+ri7o9HaoAC/IkqudnDJgwlpanBzu3ei+gKuuvK53qO92OQpqKmqqaqMoWcmZq4CljmyIicno7/oNCo6BRq4ujXqLoqiKuojuzp6pShMuoIpauKg8yVC5Daiq6ous5yqEab4KIMstmSqkDaoAuqUqLiMBusQ22DZlPyOqbO8pufuqnooptZ/OrbqD2fDqKNSi/bmCqK+GiZrsi2qYqYgc6Qaqo+DKuagpKum6r0y5+sny7p4ibQjImIr+O6esyqkoiriEuiOMOp5OgCiqGIg73IxSihaxAKOya6pbIo4aqI8+ytrq74hLC7oBvLLozOCzvLYe+ZKTOPYY7it0ujiaE2BiqIG7OoaTGvHsTZloLM7guC/mhuypdjpty6mqK7+q6mQswtqizI44g66uCuiqqNtI5euGuMHoJcjAzcipq8kvqv7IqqqsCaKh88M6vy8uzK+oqK75qfmKqgKOir0KqOmwHMatrrroC4qYvpqpaNy8iQ2/bJqH4MiLGsgJ7a6arOaPrL6ogIK7Bu6oxD79vQqCAijeszmCouJO61j6mOfanqCxGjDZyKIc/kquCAgopIKrIvnyDm6IosiA/cuusSt7w4lMq6LiIf26j6qvUImuiK2IrooqrrGqBqeiqK04GrojgiKgvPvrS8OWoqq6i8reICoYL+MC+JoDjqnqqgyKKoultsliegiK54gIq5IPguyg6zAgLqnK2KrrqIuLwg5ObX7u+q6LCukBr7pF6qhoosJsooZDkYGuNU6oqIqiuqjOE6qKyZSOwvCqovCIqo7qiF654OiICpII2Iw4+qDmno4ci5iqrqngzK6WubCgOAWIgMjl6u4Y6oaogLDouW9a8VjA5YXOqgoauaroqCnKtS3Aj5Kbq+6om+gujruVrOvq+OYbp8CZkLEoy6HFq8AjgqjqpMK/JbqiIjarjIjeG2uOmpak+EqYi7qVmogDry7OuyY0aO+eip7qhoqAyi44WYiI9i6+yroLGoqOoP0oivyq7/qyseaeiiHuartIYbC2JUSsCro2I+24zXomaiiQjqSnL9PqCOqmgq/ayK2QKixmMoRLnCumG4gKegKqUrnvquLrjtariKpNfvrpSqsyvJ4J9o35/uoSguBcyiqpLiUzKwyAuMmQD8QOinqhoACm7GiTaHqr65CZrmzqrruo7vIocapSPVOw8uqp+qOLIZxrm6qMqrKLrqp4jtuy+yEwDY4soutyzC6JkIwavsFY+JmkLq++rOy8uhog8bDy0Ki2v3q+fSqajriyiKKrt/7Yg6K0DtjimFrxmLoq4vM1hqifuetkzroXaElYjk8uqcq6lzyqgsk6776LvxqNSKauyDKimooIsu4qOcIC3JyHqKwOsOcw4s6x+JgE8s6KuMrIeEqopqmeq7zoyK3OixaOPqqKuQi6igOeqdrtqomZbyDYaLqr67LzOoorqrr4+rpl2kqisusVqMnhjw6kiuLCASxRs66oOokuLaqFuOaAIEqsq7ICuvANo/r/GyPGMmjKIq6iv4RqMo69y7OkQ839i4r+PGiuuqsAi6vquss0OIuurNY8vpfpx4Sj9CqChs6bi4cqzZKMZ6+6yzqwyO+mMo6vgunKjaeImou/uNOhv5iqK+0kkqt5nePauWinCr5KGoCo2ZkBiC6ZqkYMDp6kg6zgq++Eqo0bUipqx6MNgLEe/rP773uggfSInLLM3aqH6MiyiQ5xOeSq3Ki7qviqLqrs/QmzL6o4RPqo+8C8uabIuXkqbElqCErZCirQgK86i4bY+jvC/2CLrJqrq97qjrLgkuODGI5NWfg9yTgIPlsayIL4veqAL7vEqD+IzuxODKKo+PC69IiYz64zYR6qrG6wiK3ruCo5Ce6ix6rvC4yeyaWoO7gaoaVtDYbqDK6IuIpEoo+uuq68rvAKl6ngihgc4Jqp6pmagQo2vL72vkj42J04zmqYvc4NyPgD6tzq4ezozMzryzqtCqK7q4aN7P1Iug6SJG7IqK2vybicrSLKSzvv3SqBboI4wIugp/HMrPzY0rKHiuD+rZSKK/+6jqqOSuHEwK/6/46WmO7un6Aou8me/pusqA7B6pj6moqJbKvzALiJqoQ8iu6qiQMvtrkCuWT7nrLiuq6YoKj4tqieq+ALoTIEgWmWDuyQzCY4mKo+lKK5briir6YoY6uey4iaFqjqrSDz1CgZlboAnRLpqmq6YsDIygOeDIouBqC5wynqi7wIqju6+Ku2IpjtAIiNArKDCrSpq0uqt4u/CrD+JNzqu2ietgJwhi2OwiyIiYfqmJAsByDoqCi46A8aigDq7rr8rxma6ahwLJzqs4I5vSScm76yPu2ieqqrsi6oBMMNhspsyJjhisuPhPrsKLRqoh6poI6IKoRmq1o0iG4xiLKHqorRqK6vmix9aobyGoqO+64rnqo46oERvcrqwimu2Luv/qog6LOO5nQItbqvzKioH2ureLAumAr0rrLLMneoiwinMaDGpQkoD7u9iN78r8E8q7JimQMYJZvJizbgw6756tkOAeLMK76pzCHaKwaCjK/qXMDu8rqfZLtMiendLqjN16vLrqirqEKqSyAasqnLoL0KKo5KicL56RDeP9PjjY+ozqqhmC5rmoaKit3JvTvooi8tICj+H+LrkCuyyup+CuAA0Kq8OsuouwuL6Koq/LiKrikiav7pogirL6mhv9ktxrhS8tNprrqaKqJLgS6ogqqk14iLpqjIr22ood/Ay5jKigqryoAqWoHpkmzzuCruqro6u7CbGr0uhoxMuQytnmk6ld+6abu8Q+syqTg4KtKrpR/pikpaqpvojzQKTkDmhDqoeaGn775pKYuoiugCYoIOC6aum6m6yiIooKhNp6P+6LjJiS6Qpeno8qqQuqIATmgA6GqmqImK6vi+jYo7nJqj7+vLoOO7qp66LOwc2t4C5q6mI566Jaja6o7ajZKwzLqkq6j8OMorW6uqqILzbKeq6XorGpE4yKw50q7F2xi83snEvbq8GoGqEKiIieT7S6pkuujQwIuqq6vq/rn6w0oI8uOykarMmErp7Cv4ivigi5BqaLggSorAe6ifjB7iqLmmygqUmgrAsWrqCSzuoHuPfsgA+xCEC4w6mZsXL6goCh4r7Qo7zMKsabuFqLTJ+Bo+qqiOqPnqI/n+y4K4oKqqLgueiqW8qo66S+hqIf/IPtOoyxm6ma6Qu4rrplaOKv2g0m+s6Oi/3FmrqZT6KoI4kKo3KEhuqcgCuhLi+6spAoqqBkOLq5qS0osoy6+g2wpvOZqA5qiquXuL3pupOrou6ZICEojJijiruKoOm0qomLLpoOvKS+i6M6Qqriialmr3oYoeqaIo4Dyq6hgUKq4qiyileMz4jPXpmWq6lsqmqK6pp6y9zKi4+mQqwZiqamqa8yaqeK6Pmom6pODzsmroLjywu6BahPOqANlIAuQTigiKgughOiSm2B4rstgYycnqjSZOgDKaqmqu4nxe7NikT55OKJjji+rLrjCJyJjLqiamYKqMgtKv4gOibCOKiQDa4vKOiykrvqi/dvn5WI8QuOjLGk5pv6yugjj6qhgYiE6+apqgoGi75Ar7pIv9ursrKgraov2iS46k8KuUjy6KCQGijP+BoqtZm98sia8qy26okpoLKK4ugKsODFFcUqmKqcu4jjmL2KYDu8L97+hqWruby52KGu6AC7omrr2qnMkROmuurAe+DsrEuhZtqKWBorqqCqN8qbOaquto4oOGiCjGKuuogtggIVAjLq6b+ur4zOP+mipbniH+pOAC2s1/qqnAIK47ixqggc7G/L+4oumiubroKK+SyaCIiKHqWLvlw9i6J9G71wHui47XtaCkZtC/KeuqPayDCqjK0qYoj3+w9y5ar96e7k0CGCZciIyKjIKqokL0isrfqq+oajsIKhobDrCp2F3tlpgKi/giqqdbhqiqqCq7up5qrGukOu5gysrrmgm5jiHbRMwahIoZo6iKhB54Qpji+rq/CjwBTOK/JpvYmoC4CLMwCeovZYrOYSbdio++YPuSirVIpBumLpO5+Bmp6CniGBKxqFsqO6guCsLwjO765JWYiuKqqImB+4sCg6iWHyrvmMyC7JglcGzYg+gEesmJronqirGGMrzAaAhrv2xoIELCoAmqmsgyv8V7oQzPTmD6Ruv3GfqCpIzNroLDS/G2jC8mrq+6ubpoHM2lSO2prB7W6Kim6bJJzryMorotP8kkiqv+rb7v867k9L244u+sZKivKssup9m97CA7mghQcenuK5qMrGqkgIHrq7wtCqvEXu7yKKNYmoqokqy7wnA7gpoOAgKu/a5/yO64B9m6vITLmswjiTmKqKqKGP5o+8na4ppji88q6Khq7w6cqmSmXIApuLKuLwLqiKmsx+gfyqyq6eyoigqf8pjiq83iweGvjyLzAqosnLso8r/E6qoOhbco3KKb6pqMaL7Om6sE86uZaowcr5vITsstuqizCx6p0IqpMolqagCoTOoQ6i6BjG4KudfotLnNhexKbeT6rvbN/LPril/Jw6WE0+KIir+vqSpQ+JuyKzy1pEutqZionqWNKrkiLIg2goir/sqJkKirkp6OOniq7Ovnur1Ir/7qaLqo90CCiOlzqviazrqqdzG4Ooh95qfYqoKRpMGgo2CUEaymqrym8G7UuhbunKqG2JiM46lvr+uIrNOMjKK6KCr4634qs7yoOKygSyDojqMn+oG8i4mQjJkZhkCFIrqj2DqcqbfCpK2gP0GoiI+vAnKB2bzqmo6OrQzJlNlGwr6NuY+LKYhIiA/oyAvWjDKCjat4ypjS9jND+oCjsaz6upgKou6JvI2bgmm8q4KK+otqjtww4tCGmgcoIAKg3Cp6P/Dg/a8OCp+6sv46qIs6jqcqH6uSr4L7uOzKqY7oiYp5iiur6KI7WWCJCJt27ACpa/Fp9JUP4/6Raoor+pwJyiurrXu6y4qinrwol7jr7A9t5m6oqt6IuKisoqmL2s6vop3u4iKEghqm+uK9Cyhukq0ay/2lhM+D1RirmIOgoBdOK6mG6j3mIOybLbuwqOIr6gzKhpWrCzyY2v7kyqlbqpg4yvjpvnfS4PmG7p5qy7GAgjQqI4opjZOagqrcYEZuCmaqrubuIOQbgoHgyMzigECErqiPzoiLr5KOuqmLB6K46ny7qNGZqqOq4Lo5NKvoi4xKi+L6q7qiKuojCSCCuMTouobBKaqqpajOqC/lBqztjNnYrybK6SCsDvq+nIGgqpPLpqiuRDnRi5rlAE+qqI74iL6opqH60BjomsytySdjDJrJkaqiiMasiiuowMq+DNXroJkmzKiB6P7Iiv6RgvGLjvqooJCubrC4qwu6q4VIiopti/qs+u99LvCi4K78OsmY2L6uirzZXRAurMzgU/qhiAoguKqKLq44iqosiYqgpCmpuKsumK+qwOqrmvzurqSeyYtbcbp+3r9mhdKqKu8VKs36/qpossP0xg62btKUYqT62r844uDqjq3Ay/243JXqsFilj8+qLKvuesGMCrKvparoh6mK+oYbvLn/+iEMAf6GmOkx5i6a6hgGB7CpCaoWq4BFfT46jsi364mejiMBqYhisrohKpdIKpAvWefpKJo46ImQnp9rq6vf4smfyBmbxoooZomauKrs5jOKwMKNgirLwqsv2rvPqPKaiYmIYqirPb3OvOgaqpQ6caPsgsA6irrqPM4ur56MK62hZKiCjaD4kKrp2jmyC7TFjikjglyC6p/KEPhqGIMoPO2OiuhsjivAyqOIuKsLAJXBiDguL4guKljrgu7rz6iestzMHuOgLwPqqMq6iwgAtjs4gIiAmjrKoo/mq0Qq2aqqpJqIgLqL/Tm4SqKfjuQuqqqgLY87i4jq65fEgypAm5rKmKqBrdDoKiqiqrFOmvgL/qihqJKq9gCsuqKdoqPl6ZaJpqrPi4nnyMrtyKOTmauq69o4ibGqKvP/C6vBrirLq5kGq+re4q2e5y0MpTprCbuOmjMZqqj4HAjvSaxiuNaIa5qn1LKqz6q9yr2Os8u6KrCbGo2Lucn9wrOrsoiJ6KuYiKhUKjtDg5YMqADQirueqVqqnoihKBLpO7zSDuKBgPq/hivaLs+igOMinPhorCIq7q844IL6oMYej6poWptauu/vCvasn8pkq24ODiLm7aySLrsa9jGKmhgkvRCjgdvyzrqnjxucor4yuS6WtpKob6uQvpSyy4auiYg9qbKIw4igh7Slrssoxp45ir64Grm5K+HKaoKn5uKgvo65i5hqhIXahm6oDYqNgJvLOMiopE+IsM+76hrOimes6IiuqOc7mqUo7cqei6yPvCF6TpO6QjfOYcpu96EofIKmCIN4Nonhj+C4rIqLjTqzOSh4jo6bPquIic5I2p2Dha7jiPpP6IfDI7qjTOa6iYiqie4q4ISMOK4fKriG4uvjuBik7rO4WoUIr+qC+KuKqtiC4LKiiIqwyqy6IzDf7JiA6sztBI7SjqOviW/oKLviyou476b5mli75B/Yo8p4EqurapwYae7syOjrpLLmqo2ooOoiawyquCCtObCGxoutGKBMrmIwormcKOLp+96rmB6pehnPmMwlJDAuos4qBqqIO+3t0v4qKYiIGI6CuML+rlqoi4uyosKr8gpijAu5H5orloyOLKKvjjy47g2/qK7Jiq+QpqHIyFo6Ku05jPDciMOL6ICua7yqisD/9q0M6JGIyPpzzIjTinajjpn6qZIe680s4in4O374IbrIigI6hRnaqprum56b9jhM6kq3luqPiJe9O6ys9M5asq8Mv4ojac76iwhTrsj8roqq4+zanzhfSIqoGKiPrunjJ4KAqwC8l8Qkksqu3ggKo6EbyuirksyqcJq4qqDqPpKPbtBqq9mq7rqb+gC5QDU77qjOluagqjiomrDq5ggrBoI9LireEOssSLqDxrqe5wiUKLig1MiLHyuJDYi67uv7/M7HKtKImujSiGKOanqogXoq2urnrEyAIjnbaG7IsYeUALLugDroqs6uteot4q0ioYuKrIctqsyIqN4IHoKsmKtZr4tIh7noLFiiiIhqvLYwuDIux7aioasqoqSosChcoOmMcJztzOMLv4Z2qomADyqqInD7muqUQcyJjNDIpaqYXSnqirKJuypaLqYgIZiOuJjZmzr3as7rDTCKZqqjuJ0gOt31qRwDo6/9pKyYzwyoeHw4YgmoyCiqDcqcgosDkqbckqisuvqKoDxKqKq0xthPjveQAfqpj+Ti4tJKqgiepboczOm6rjrqUQqgz+nSj2vK3bqKrqguyag2BAKKNTpooq637x8Gqoikmwoiio7bqCQM7TCjqpPJiLqL2gqoqiLNzIhLDGico+6q+v5TKK16mIqrnNmq2soKiSqgz85gXuj7reuLqp6D7ymq2J6GCIqgusz6raBOKpC4KJo07cyKsoCbuapCmKDvuoyqqmqqTarL+qv+NbprqIhv6J+bjuCyikgKy2yMm2rDy8KqolqwoOzvLarI7FGC6ovzuuSNaoICej4Mb6rRqO7ckcAMLr6Snq24Seos3ovfr64ukKvsCijE9qS9y6q4mL4KrLuCLuYKzOEs+fCqqbzMuhPruIqqyE1PT75nKtGE0KioosUavIK6LItLjtoSD6uZGLopFhsqKv4uofBqrkwqosjKa7mzj02Ii4aqrpnKjqmyHbsNgPgKEK6unLnm34sutaAL"; const BLOOM_VERSION = "efb9e3f964c0f417"; // --------------------------------------------------------------------------- // Database client (verified_ips only) // --------------------------------------------------------------------------- const db = createClient({ url: process.env.BUNNY_DATABASE_URL!, authToken: process.env.BUNNY_DATABASE_AUTH_TOKEN!, }); // --------------------------------------------------------------------------- // Turnstile config // --------------------------------------------------------------------------- const TURNSTILE_SITE_KEY = process.env.TURNSTILE_SITE_KEY || ""; const TURNSTILE_SECRET_KEY = process.env.TURNSTILE_SECRET_KEY || ""; // --------------------------------------------------------------------------- // Bloom filter (FNV-1a — must match bouncer.py) // --------------------------------------------------------------------------- function base64ToBytes(b64: string): Uint8Array { const bin = atob(b64); const bytes = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) { bytes[i] = bin.charCodeAt(i); } return bytes; } let bloomBits: Uint8Array | null = null; let bloomM = 0; let bloomK = 0; if (BLOOM_B64 && !BLOOM_B64.startsWith("__")) { const raw = base64ToBytes(BLOOM_B64); bloomM = raw[0] | (raw[1] << 8) | (raw[2] << 16) | (raw[3] << 24); bloomK = raw[4] | (raw[5] << 8) | (raw[6] << 16) | (raw[7] << 24); bloomBits = raw.slice(8); console.log( `Bloom filter loaded: version=${BLOOM_VERSION}, m=${bloomM}, k=${bloomK}, ${bloomBits.length} bytes`, ); } function fnv1a32(data: Uint8Array): number { let h = 0x811c9dc5; for (let i = 0; i < data.length; i++) { h ^= data[i]; h = Math.imul(h, 0x01000193) >>> 0; } return h; } function isBlocked(ip: string): boolean { if (!bloomBits) return false; const enc = new TextEncoder(); const ipBytes = enc.encode(ip); const ipBytesFF = new Uint8Array(ipBytes.length + 1); ipBytesFF.set(ipBytes); ipBytesFF[ipBytes.length] = 0xff; const h1 = fnv1a32(ipBytes); const h2 = fnv1a32(ipBytesFF); for (let i = 0; i < bloomK; i++) { const pos = (h1 + i * h2) % bloomM; if ((bloomBits[pos >> 3] & (1 << (pos & 7))) === 0) return false; } return true; } // --------------------------------------------------------------------------- // Clean IP cache (negative cache — bloom에 없는 정상 IP) // --------------------------------------------------------------------------- const cleanIpCache = new Set(); const CLEAN_CACHE_MAX = 50_000; function isCleanCached(ip: string): boolean { return cleanIpCache.has(ip); } function addCleanCache(ip: string): void { if (cleanIpCache.size >= CLEAN_CACHE_MAX) cleanIpCache.clear(); cleanIpCache.add(ip); } // --------------------------------------------------------------------------- // Verified IP cache (memory only, DB는 캡차 검증 시에만) // --------------------------------------------------------------------------- const verifiedCache = new Map(); const VERIFIED_TTL_MS = 14_400_000; const VERIFIED_CACHE_MAX = 10_000; function cacheEvict(m: Map, maxSize: number): void { if (m.size < maxSize) return; const now = Date.now(); for (const [key, val] of m) { if (val <= now) m.delete(key); } if (m.size >= maxSize) m.clear(); } // --------------------------------------------------------------------------- // HMAC cookie signing (Web Crypto API) // --------------------------------------------------------------------------- async function hmacSign(data: string, secret: string): Promise { const enc = new TextEncoder(); const key = await crypto.subtle.importKey( "raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"], ); const sig = await crypto.subtle.sign("HMAC", key, enc.encode(data)); return Array.from(new Uint8Array(sig)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } // --------------------------------------------------------------------------- // Cookie helper // --------------------------------------------------------------------------- function getCookie(request: Request, name: string): string | null { const header = request.headers.get("cookie") || ""; const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`)); return match ? decodeURIComponent(match[1]) : null; } // --------------------------------------------------------------------------- // Verified IP check (memory cache → cookie → DB) // --------------------------------------------------------------------------- async function isVerified(ip: string, request: Request): Promise { const cachedExp = verifiedCache.get(ip); if (cachedExp && cachedExp > Date.now()) return true; if (cachedExp) verifiedCache.delete(ip); const cookie = getCookie(request, "_cs_verified"); if (cookie) { const parts = cookie.split(":"); if (parts.length === 3) { const [cookieIp, ts, sig] = parts; if (cookieIp === ip) { const expected = await hmacSign(`${cookieIp}:${ts}`, TURNSTILE_SECRET_KEY); if (expected === sig) { const timestamp = parseInt(ts, 10); if (Date.now() - timestamp < VERIFIED_TTL_MS) { verifiedCache.set(ip, timestamp + VERIFIED_TTL_MS); return true; } } } } } try { const result = await db.execute({ sql: "SELECT 1 FROM verified_ips WHERE ip = ? AND expires_at > datetime('now')", args: [ip], }); if (result.rows.length > 0) { verifiedCache.set(ip, Date.now() + VERIFIED_TTL_MS); return true; } } catch (err) { console.error("Verified IP lookup failed:", err); } return false; } // --------------------------------------------------------------------------- // Turnstile server-side verification // --------------------------------------------------------------------------- async function verifyTurnstile(token: string, ip: string): Promise { try { const resp = await fetch( "https://challenges.cloudflare.com/turnstile/v0/siteverify", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `secret=${encodeURIComponent(TURNSTILE_SECRET_KEY)}&response=${encodeURIComponent(token)}&remoteip=${encodeURIComponent(ip)}`, }, ); const data = (await resp.json()) as { success: boolean }; return data.success === true; } catch (err) { console.error("Turnstile verification failed:", err); return false; } } // --------------------------------------------------------------------------- // Store verified IP // --------------------------------------------------------------------------- async function storeVerified(ip: string): Promise { try { await db.execute({ sql: "INSERT OR REPLACE INTO verified_ips (ip, expires_at) VALUES (?, datetime('now', '+4 hours'))", args: [ip], }); cacheEvict(verifiedCache, VERIFIED_CACHE_MAX); verifiedCache.set(ip, Date.now() + VERIFIED_TTL_MS); } catch (err) { console.error("Failed to store verified IP:", err); } } // --------------------------------------------------------------------------- // CAPTCHA HTML page // --------------------------------------------------------------------------- function escapeHtml(s: string): string { return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function captchaPage(originalPath: string, error?: string): Response { const safeRedirect = escapeHtml(originalPath); const html = ` 보안 확인

보안 확인이 필요합니다

계속하려면 아래 확인을 완료해주세요.

${error ? `
${escapeHtml(error)}
` : ""}
`; return new Response(html, { status: 403, headers: { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store", }, }); } // --------------------------------------------------------------------------- // CAPTCHA verify handler // --------------------------------------------------------------------------- async function handleCaptchaVerify( request: Request, ip: string, ): Promise { const body = await request.text(); const params = new URLSearchParams(body); const token = params.get("cf-turnstile-response") || ""; const redirect = params.get("redirect") || "/"; if (!token || !(await verifyTurnstile(token, ip))) { return captchaPage(redirect, "확인에 실패했습니다. 다시 시도해주세요."); } await storeVerified(ip); const ts = Date.now().toString(); const sig = await hmacSign(`${ip}:${ts}`, TURNSTILE_SECRET_KEY); const cookieValue = encodeURIComponent(`${ip}:${ts}:${sig}`); const safeRedirect = escapeHtml(redirect); return new Response( `

확인 완료. 이동 중…

`, { status: 200, headers: { "Content-Type": "text/html; charset=utf-8", "Set-Cookie": `_cs_verified=${cookieValue}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=14400`, "Cache-Control": "no-store", }, }, ); } // --------------------------------------------------------------------------- // Middleware // --------------------------------------------------------------------------- BunnySDK.net.http .servePullZone() .onOriginRequest(async (ctx) => { const ip = ctx.request.headers.get("X-Real-Ip"); if (!ip) return ctx.request; if (isCleanCached(ip)) return ctx.request; if (isBlocked(ip)) { if (!TURNSTILE_SITE_KEY || !TURNSTILE_SECRET_KEY) { return new Response("Forbidden", { status: 403 }); } if (await isVerified(ip, ctx.request)) { return ctx.request; } const url = new URL(ctx.request.url); if (url.pathname === "/__captcha/verify" && ctx.request.method === "POST") { return handleCaptchaVerify(ctx.request, ip); } return captchaPage(url.pathname + url.search); } addCleanCache(ip); return ctx.request; });