From ade8505b2656ab8553c2458e8f4d2c806329cbcf Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Mon, 15 Dec 2025 18:27:39 -0500 Subject: [PATCH] feat: first implementation of honeypot logic This is a bit of an experiment, stick with me. The core idea here is that badly written crawlers are that: badly written. They look for anything that contains `` tags and will blindly use those values to recurse. This takes advantage of that by hiding a link in a ` ``` Browsers will ignore it because they have no handler for the "ignore" script type. This current draft is very unoptimized (it takes like 7 seconds to generate a page on my tower), however switching spintax libraries will make this much faster. The hope is to make this pluggable with WebAssembly such that we force administrators to choose a storage method. First we crawl before we walk. The AI involvement in this commit is limited to the spintax in affirmations.txt, spintext.txt, and titles.txt. This generates a bunch of "pseudoprofound bullshit" like the following: > This Restoration to Balance & Alignment > > There's a moment when creators are being called to realize that the work > can't be reduced to results, but about energy. We don't innovate products > by pushing harder, we do it by holding the vision. Because momentum can't > be forced, it unfolds over time when culture are moving in the same > direction. We're being invited into a paradigm shift in how we think > about innovation. [...] This is intended to "look" like normal article text. As this is a first draft, this sucks and will be improved upon. Assisted-by: GLM 4.6, ChatGPT, GPT-OSS 120b Signed-off-by: Xe Iaso --- data/botPolicies.yaml | 80 +++++------ go.mod | 1 + go.sum | 6 + internal/honeypot/honeypot.go | 23 +++ internal/honeypot/naive/100bytes.css | 7 + internal/honeypot/naive/affirmations.txt | 1 + internal/honeypot/naive/naive.go | 120 ++++++++++++++++ internal/honeypot/naive/page.templ | 36 +++++ internal/honeypot/naive/page_templ.go | 160 +++++++++++++++++++++ internal/honeypot/naive/spintext.txt | 1 + internal/honeypot/naive/titles.txt | 1 + lib/config.go | 4 + web/index.go | 11 ++ web/index.templ | 2 + web/index_templ.go | 171 ++++++++++++----------- 15 files changed, 503 insertions(+), 121 deletions(-) create mode 100644 internal/honeypot/honeypot.go create mode 100644 internal/honeypot/naive/100bytes.css create mode 100644 internal/honeypot/naive/affirmations.txt create mode 100644 internal/honeypot/naive/naive.go create mode 100644 internal/honeypot/naive/page.templ create mode 100644 internal/honeypot/naive/page_templ.go create mode 100644 internal/honeypot/naive/spintext.txt create mode 100644 internal/honeypot/naive/titles.txt diff --git a/data/botPolicies.yaml b/data/botPolicies.yaml index 1288f635..ac45da2a 100644 --- a/data/botPolicies.yaml +++ b/data/botPolicies.yaml @@ -95,49 +95,49 @@ bots: # weight: # adjust: -10 - # Assert behaviour that only genuine browsers display. This ensures that Chrome - # or Firefox versions - - name: realistic-browser-catchall - expression: - all: - - '"User-Agent" in headers' - - '( userAgent.contains("Firefox") ) || ( userAgent.contains("Chrome") ) || ( userAgent.contains("Safari") )' - - '"Accept" in headers' - - '"Sec-Fetch-Dest" in headers' - - '"Sec-Fetch-Mode" in headers' - - '"Sec-Fetch-Site" in headers' - - '"Accept-Encoding" in headers' - - '( headers["Accept-Encoding"].contains("zstd") || headers["Accept-Encoding"].contains("br") )' - - '"Accept-Language" in headers' - action: WEIGH - weight: - adjust: -10 + # # Assert behaviour that only genuine browsers display. This ensures that Chrome + # # or Firefox versions + # - name: realistic-browser-catchall + # expression: + # all: + # - '"User-Agent" in headers' + # - '( userAgent.contains("Firefox") ) || ( userAgent.contains("Chrome") ) || ( userAgent.contains("Safari") )' + # - '"Accept" in headers' + # - '"Sec-Fetch-Dest" in headers' + # - '"Sec-Fetch-Mode" in headers' + # - '"Sec-Fetch-Site" in headers' + # - '"Accept-Encoding" in headers' + # - '( headers["Accept-Encoding"].contains("zstd") || headers["Accept-Encoding"].contains("br") )' + # - '"Accept-Language" in headers' + # action: WEIGH + # weight: + # adjust: -10 - # The Upgrade-Insecure-Requests header is typically sent by browsers, but not always - - name: upgrade-insecure-requests - expression: '"Upgrade-Insecure-Requests" in headers' - action: WEIGH - weight: - adjust: -2 + # # The Upgrade-Insecure-Requests header is typically sent by browsers, but not always + # - name: upgrade-insecure-requests + # expression: '"Upgrade-Insecure-Requests" in headers' + # action: WEIGH + # weight: + # adjust: -2 - # Chrome should behave like Chrome - - name: chrome-is-proper - expression: - all: - - userAgent.contains("Chrome") - - '"Sec-Ch-Ua" in headers' - - 'headers["Sec-Ch-Ua"].contains("Chromium")' - - '"Sec-Ch-Ua-Mobile" in headers' - - '"Sec-Ch-Ua-Platform" in headers' - action: WEIGH - weight: - adjust: -5 + # # Chrome should behave like Chrome + # - name: chrome-is-proper + # expression: + # all: + # - userAgent.contains("Chrome") + # - '"Sec-Ch-Ua" in headers' + # - 'headers["Sec-Ch-Ua"].contains("Chromium")' + # - '"Sec-Ch-Ua-Mobile" in headers' + # - '"Sec-Ch-Ua-Platform" in headers' + # action: WEIGH + # weight: + # adjust: -5 - - name: should-have-accept - expression: '!("Accept" in headers)' - action: WEIGH - weight: - adjust: 5 + # - name: should-have-accept + # expression: '!("Accept" in headers)' + # action: WEIGH + # weight: + # adjust: 5 # Generic catchall rule - name: generic-browser diff --git a/go.mod b/go.mod index 28f60c69..ae8e5048 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 github.com/joho/godotenv v1.5.1 github.com/lum8rjack/go-ja4h v0.0.0-20250828030157-fa5266d50650 + github.com/m1/gospin v0.0.0-20200506075355-4345dd621d4a github.com/nicksnyder/go-i18n/v2 v2.6.0 github.com/playwright-community/playwright-go v0.5200.1 github.com/prometheus/client_golang v1.23.2 diff --git a/go.sum b/go.sum index ea8e6f91..21fc228c 100644 --- a/go.sum +++ b/go.sum @@ -255,6 +255,7 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -282,6 +283,8 @@ github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr32 github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lum8rjack/go-ja4h v0.0.0-20250828030157-fa5266d50650 h1:hhx/Mo6+Hk0mAQS5MW311ON1VlSzp0D1cYhY27IcmnI= github.com/lum8rjack/go-ja4h v0.0.0-20250828030157-fa5266d50650/go.mod h1:bMqyXOakqQIdx82d4vcnk5TIZLptZ2gLqju9xmPrWYA= +github.com/m1/gospin v0.0.0-20200506075355-4345dd621d4a h1:1SIAGB8spa9zVw6UL59uT5xQWjQMe7EK6rw7eYA8kdI= +github.com/m1/gospin v0.0.0-20200506075355-4345dd621d4a/go.mod h1:Mxpzp00JqlLiQAoV1bOlEKWjT5wbK9/YqHqTUvcE+4I= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= @@ -374,6 +377,8 @@ github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -382,6 +387,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/internal/honeypot/honeypot.go b/internal/honeypot/honeypot.go new file mode 100644 index 00000000..f03b2db4 --- /dev/null +++ b/internal/honeypot/honeypot.go @@ -0,0 +1,23 @@ +package honeypot + +import ( + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var Timings = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "anubis", + Subsystem: "honeypot", + Name: "pagegen_timings", + Help: "The amount of time honeypot page generation takes per method", + Buckets: prometheus.ExponentialBuckets(0.5, 2, 32), +}, []string{"method"}) + +type Info struct { + CreatedAt time.Time `json:"createdAt"` + UserAgent string `json:"userAgent"` + IPAddress string `json:"ipAddress"` + HitCount int `json:"hitCount"` +} diff --git a/internal/honeypot/naive/100bytes.css b/internal/honeypot/naive/100bytes.css new file mode 100644 index 00000000..7de70f3f --- /dev/null +++ b/internal/honeypot/naive/100bytes.css @@ -0,0 +1,7 @@ +html { + max-width: 70ch; + padding: 3em 1em; + margin: auto; + line-height: 1.75; + font-size: 1.25em; +} diff --git a/internal/honeypot/naive/affirmations.txt b/internal/honeypot/naive/affirmations.txt new file mode 100644 index 00000000..6092398a --- /dev/null +++ b/internal/honeypot/naive/affirmations.txt @@ -0,0 +1 @@ +{Yeah|Yep|Yup|Yes|Absolutely|Definitely|Sure|Sounds|That's|I'm|I am| Totally|Completely|Totally|Right|Correct|Exactly|Perfectly|Certainly|Of course|Naturally|Indeed|Totally|Awesome|Sweet|Cool|Neat|Great|Excellent|Fantastic|Wonderful|Amazing|Love it|Nice|Right on|You bet|For sure|No doubt|Without a doubt|Undoubtedly|Indeed|Certainly|Absolutely|Positively|Definitely|Surely|Truly|Really|Genuinely|Honestly|Frankly|Literally|Exactly|Precisely|Spot on|On point|Perfectly|Ideally|Optimally|Superbly|Brilliantly|Marvelously|Splendidly|Magnificently|Phenomenally|Extraordinarily|Remarkably|Exceptionally|Outstandingly|Impressively|Stunningly|Breathtakingly|Astonishingly|Surprisingly|Pleasantly|Delightfully|Charmingly|Appealingly|Attractively|Invitingly|Encouragingly|Motivatingly|Inspiringly|Upliftingly|Positive|Optimistic|Encouraging|Supportive|Approving|Favorable|Enthusiastic|Eager|Willing|Ready|Prepared|Set|Go|Let's|Alright|Okay|Sure thing|No problem|You got it|Consider it done|Will do|Roger that|Copy that|Got it|Understood|Acknowledged|Noted|Confirmed|Agreed|Approved|Accepted|Endorsed|Supported|Backed|Championed} {sounds|looks|seems|feels|is|appears|comes across|strikes me|hits me|registers|resonates|clicks|makes sense|fits|works|functions|operates|performs|delivers|succeeds|achieves|accomplishes|excels|shines|stands out|impresses|satisfies|meets expectations|exceeds expectations|delights|pleases|gratifies|fulfills|completes|finishes|concludes|wraps up|finalizes|settles|resolves|solves|fixes|addresses|handles|manages|tackles|conquers|overcomes|defeats|beats|wins|triumphs|prevails|dominates|leads|guides|directs|steers|navigates|paves the way|opens doors|creates opportunities|makes possible|enables|allows|permits|facilitates|supports|encourages|motivates|inspires|drives|pushes|propels|launches|initiates|starts|begins|commences|kicks off|gets going|moves forward|progresses|advances|develops|evolves|grows|expands|improves|enhances|upgrades|optimizes|refines|perfects|polishes|finishes|completes} {good|great|perfect|excellent|wonderful|fantastic|amazing|awesome|fine|okay|alright|nice|cool|spot on|reasonable|about right|superb|brilliant|marvelous|splendid|magnificent|phenomenal|extraordinary|remarkable|exceptional|outstanding|impressive|stunning|breathtaking|astonishing|surprising|pleasant|delightful|charming|appealing|attractive|inviting|encouraging|motivating|inspiring|uplifting|positive|optimistic|encouraging|supportive|approving|favorable|enthusiastic|eager|willing|ready|prepared|set|solid|strong|robust|powerful|effective|efficient|productive|successful|fruitful|beneficial|valuable|useful|helpful|advantageous|profitable|rewarding|satisfying|gratifying|fulfilling|complete|whole|total|entire|full|thorough|comprehensive|exhaustive|detailed|precise|accurate|correct|right|true|valid|sound|logical|reasonable|rational|practical|realistic|feasible|possible|doable|achievable|attainable|obtainable|reachable|accessible|available|present|ready|waiting|prepared|set|arranged|organized|structured|planned|scheduled|timed|perfectly placed|well positioned|strategically located|ideally situated|perfectly suited|well matched|compatible|harmonious|balanced|proportional|symmetrical|aesthetic|beautiful|gorgeous|lovely|pretty|attractive|handsome|striking|dramatic|bold|confident|assertive|decisive|clear|obvious|apparent|evident|manifest|plain|simple|easy|straightforward|uncomplicated|complex|intricate|detailed|nuanced|subtle|refined|elegant|sophisticated|advanced|progressive|innovative|creative|original|unique|special|distinctive|memorable|unforgettable|remarkable|notable|significant|important|major|key|critical|essential|vital|crucial|fundamental|basic|primary|principal|main|chief|leading|top|best|finest|ultimate|supreme|paramount|foremost|number one|first class|world class|professional|expert|master|skilled|talented|gifted|brilliant|genius|intelligent|smart|clever|wise|knowledgeable|informed|educated|learned|scholarly|academic|theoretical|practical|applied|hands on|experienced|seasoned|veteran|mature|developed|evolved|grown|advanced|progressive|forward thinking|visionary|prophetic|intuitive|perceptive|insightful|wise|sage|profound|deep|meaningful|significant|substantial|considerable|major|important|influential|powerful|strong|robust|resilient|tough|durable|lasting|permanent|enduring|timeless|classic|traditional|conventional|standard|regular|normal|typical|usual|common|ordinary|average|mediocre|fair|decent|respectable|acceptable|satisfactory|adequate|sufficient|enough|plentiful|abundant|ample|generous|plenty|rich|wealthy|prosperous|successful|thriving|flourishing|blooming|growing|expanding|developing|improving|better|superior|higher|elevated|advanced|progressive|modern|contemporary|current|up to date|latest|new|fresh|novel|innovative|creative|original|unique|different|special|extraordinary|unusual|rare|uncommon|exceptional|outstanding|remarkable|notable|memorable|unforgettable|legendary|famous|well known|recognized|acknowledged|celebrated|acclaimed|honored|awarded|decorated|distinguished|illustrious|prestigious|reputable|respected|admired|revered|worshipped|idolized|beloved|cherished|treasured|valued|prized|precious|dear|close|intimate|personal|private|individual|unique|special|one of a kind|irreplaceable|invaluable|priceless|worthwhile|valuable|useful|beneficial|helpful|advantageous|profitable|rewarding|satisfying|gratifying|fulfilling|complete|whole|total|entire|full|perfect|ideal|ultimate|best|finest|supreme|excellent|outstanding|superior|exceptional|remarkable|extraordinary|special|unique|distinctive|memorable|impressive|striking|dramatic|powerful|strong|effective|efficient|successful|productive|fruitful|beneficial|valuable|useful|helpful|worthwhile|rewarding|satisfying|gratifying|fulfilling} {to me|for me|with me|, I agree|, I like it|, let's do it|, count me in|, I'm on board|, I'm in|, I'm up for it|, I'm down for that|, I'm all for it|, I'm good with that|, I'm happy with that|, I'm cool with that|, let's go with that|, let's make it happen|, that works|, that'll work|, sounds like a plan|, that's a good idea|, that's a great choice|, I think so too|, my thoughts exactly|, you read my mind|, couldn't agree more|, absolutely right|, you nailed it|, spot on|, perfect|, excellent|, brilliant|, outstanding|, superb|, fantastic|, wonderful|, marvelous|, splendid|, magnificent|, phenomenal|, extraordinary|, remarkable|, exceptional|, impressive|, stunning|, breathtaking|, astonishing|, amazing|, awesome|, cool|, neat|, sweet|, groovy|, far out|, wicked|, sick|, dope|, lit|, fire|, slay|, yass|, let's go|, game on|, challenge accepted|, say no more|, you had me at hello|, I'm sold|, sign me up|, I'm in|, count me in|, I'm there|, won't miss it|, be there|, definitely|, absolutely|, for sure|, no doubt|, without a doubt|, undoubtedly|, certainly|, of course|, naturally|, indeed|, truly|, really|, genuinely|, honestly|, frankly|, literally|, exactly|, precisely|, yes|, yeah|, yep|, yup|, absolutely|, definitely|, sure|, sounds good|, looks good|, seems good|, feels good|, is good|, perfect|, great|, excellent|, wonderful|, fantastic|, amazing|, awesome|, superb|, brilliant|, outstanding|, remarkable|, exceptional|, extraordinary|, impressive|, stunning|, beautiful|, gorgeous|, lovely|, pretty|, attractive|, appealing|, inviting|, encouraging|, motivating|, inspiring|, uplifting|, positive|, optimistic|, supportive|, approving|, favorable|, enthusiastic|, eager|, willing|, ready|, prepared|, set|, go|, let's do this|, time to rock|, let's roll|, here we go|, off we go|, moving forward|, full steam ahead|, all systems go|, green light|, clear for takeoff|, ready when you are|, on your mark|, get set|, let's begin|, commence operation|, initiate protocol|, execute plan|, implement strategy|, deploy solution|, activate system|, engage process|, start procedure|, begin sequence|, launch project|, kick off event|, open doors|, make way|, clear path|, pave way|, create opportunity|, make possible|, enable success|, facilitate growth|, support development|, encourage progress|, inspire change|, motivate action|, drive results|, push boundaries|, break barriers|, overcome challenges|, solve problems|, fix issues|, address concerns|, handle situations|, manage difficulties|, tackle obstacles|, conquer fears|, defeat doubts|, win battles|, triumph over adversity|, prevail against odds|, rise above|, excel beyond|, achieve greatness|, reach heights|, attain goals|, accomplish dreams|, realize potential|, fulfill destiny|, complete journey|, finish race|, cross finish line|, arrive at destination|, reach summit|, climb mountain|, sail seas|, fly skies|, explore worlds|, discover truths|, find answers|, solve mysteries|, uncover secrets|, reveal wonders|, share insights|, spread joy|, create happiness|, build relationships|, strengthen bonds|, foster community|, grow together|, learn constantly|, improve daily|, evolve continuously|, adapt quickly|, change rapidly|, transform completely|, renew fully|, refresh completely|, restart anew|, begin again|, start fresh|, clean slate|, new chapter|, fresh start|, bright future|, promising tomorrow|, better days|, good times|, great moments|, wonderful experiences|, fantastic adventures|, amazing journeys|, awesome memories|, precious moments|, valuable lessons|, helpful advice|, useful tips|, practical solutions|, effective strategies|, successful methods|, proven approaches|, tested techniques|, reliable systems|, dependable support|, consistent performance|, steady progress|, continuous improvement|, ongoing development|, perpetual growth|, endless possibilities|, unlimited potential|, infinite opportunities|, boundless horizons|, vast expanses|, wide ranges|, broad spectrums|, diverse options|, multiple choices|, various paths|, different routes|, alternative ways|, other methods|, additional approaches|, extra techniques|, supplementary tools|, auxiliary resources|, backup plans|, contingency options|, emergency measures|, safety nets|, security blankets|, comfort zones|, safe spaces|, peaceful havens|, tranquil sanctuaries|, serene environments|, calm atmospheres|, relaxed vibes|, easy feelings|, comfortable sensations|, pleasant experiences|, enjoyable moments|, delightful times|, charming encounters|, appealing situations|, attractive prospects|, inviting opportunities|, encouraging signs|, motivating factors|, inspiring elements|, uplifting aspects|, positive features|, optimistic views|, encouraging outlooks|, supportive attitudes|, approving perspectives|, favorable opinions|, enthusiastic responses|, eager reactions|, willing participants|, ready volunteers|, prepared individuals|, set teams|, organized groups|, structured units|, planned initiatives|, scheduled events|, timed activities|, perfect placements|, well positioned assets|, strategically located resources|, ideally situated elements|, perfectly suited components|, well matched partners|, compatible collaborations|, harmonious relationships|, balanced arrangements|, proportional distributions|, symmetrical designs|, aesthetic presentations|, beautiful displays|, gorgeous exhibitions|, lovely shows|, pretty sights|, attractive views|, striking scenes|, dramatic performances|, bold statements|, confident expressions|, decisive actions|, clear communications|, obvious demonstrations|, apparent revelations|, evident truths|, manifest realities|, plain facts|, simple solutions|, easy implementations|, straightforward processes|, uncomplicated procedures|, complex systems|, intricate networks|, detailed analyses|, nuanced discussions|, subtle distinctions|, refined approaches|, elegant solutions|, sophisticated methods|, advanced technologies|, progressive ideas|, innovative concepts|, creative designs|, original works|, unique creations|, special projects|, distinctive features|, memorable experiences|, unforgettable moments|, legendary achievements|, famous accomplishments|, well recognized contributions|, acknowledged impacts|, celebrated successes|, acclaimed performances|, honored achievements|, awarded excellence|, decorated heroes|, distinguished leaders|, illustrious careers|, prestigious positions|, reputable organizations|, respected institutions|, admired figures|, revered icons|, worshipped idols|, beloved personalities|, cherished treasures|, valued possessions|, prized collections|, precious artifacts|, dear friends|, close companions|, intimate partners|, personal connections|, individual expressions|, unique perspectives|, special talents|, one of a kind gifts|, irreplaceable values|, invaluable insights|, priceless wisdom|, worthwhile endeavors|, valuable investments|, useful tools|, beneficial resources|, helpful services|, advantageous positions|, profitable ventures|, rewarding careers|, satisfying lives|, gratifying experiences|, fulfilling purposes|, complete beings|, whole persons|, total entities|, entire systems|, full cycles|, perfect circles|, ideal forms|, ultimate goals|, best practices|, finest qualities|, supreme achievements|, excellent results|, outstanding performances|, superior outcomes|, exceptional contributions|, remarkable discoveries|, extraordinary breakthroughs|, special recognitions|, unique innovations|, distinctive designs|, memorable impacts|, impressive feats|, dramatic transformations|, powerful changes|, strong foundations|, effective actions|, efficient operations|, successful missions|, productive endeavors|, fruitful partnerships|, beneficial collaborations|, valuable connections|, helpful networks|, worthwhile projects|, rewarding adventures|, satisfying journeys|, gratifying accomplishments|, fulfilling destinies|too|as well|also|in addition|additionally|furthermore|moreover|plus|and|as well as|along with|together with|including|containing|comprising|embracing|encompassing|covering|spanning|ranging across|extending over|stretching through|reaching into|penetrating|entering|accessing|approaching|engaging with|participating in|joining|becoming part of|integrating with|merging with|combining with|uniting with|connecting to|linking with|attaching to|binding to|fastening to|securing to|anchoring to|grounding in|rooting in|planting in|growing in|developing in|evolving in|maturing in|flourishing in|thriving in|succeeding in|excelling in|achieving in|accomplishing in|completing in|finishing in|perfecting in|mastering in|winning in|triumphing in|prevailing in|leading in|guiding in|directing in|steering in|navigating in|exploring in|discovering in|finding in|locating in|identifying in|recognizing in|acknowledging in|accepting in|approving in|endorsing in|supporting in|backing in|championing in|promoting in|advocating in|recommending in|suggesting in|proposing in|offering in|presenting in|providing in|supplying in|delivering in|distributing in|sharing in|spreading in|broadcasting in|communicating in|expressing in|conveying in|transmitting in|sending in|receiving in|getting in|obtaining in|acquiring in|gaining in|earning in|deserving in|meriting in|qualifying for|entitled to|worthy of|deserving of|meriting of|qualifying for|eligible for|suitable for|fit for|perfect for|ideal for|right for|appropriate for|proper for|correct for|accurate for|true for|real for|genuine for|authentic for|legitimate for|valid for|sound for|solid for|strong for|robust for|tough for|durable for|lasting for|permanent for|enduring for|timeless for|classic for|traditional for|conventional for|standard for|regular for|normal for|typical for|usual for|common for|ordinary for|average for|mediocre for|fair for|decent for|respectable for|acceptable for|satisfactory for|adequate for|sufficient for|enough for|plentiful for|abundant for|ample for|generous for|plenty for|rich for|wealthy for|prosperous for|successful for|thriving for|flourishing for|blooming for|growing for|expanding for|developing for|improving for|better for|superior for|higher for|elevated for|advanced for|progressive for|modern for|contemporary for|current for|up to date for|latest for|new for|fresh for|novel for|innovative for|creative for|original for|unique for|different for|special for|extraordinary for|unusual for|rare for|uncommon for|exceptional for|outstanding for|remarkable for|notable for|memorable for|unforgettable for|legendary for|famous for|well known for|recognized for|acknowledged for|celebrated for|acclaimed for|honored for|awarded for|decorated for|distinguished for|illustrious for|prestigious for|reputable for|respected for|admired for|revered for|worshipped for|idolized for|beloved for|cherished for|treasured for|valued for|prized for|precious for|dear for|close for|intimate for|personal for|private for|individual for|unique for|special for|one of a kind for|irreplaceable for|invaluable for|priceless for|worthwhile for|valuable for|useful for|beneficial for|helpful for|advantageous for|profitable for|rewarding for|satisfying for|gratifying for|fulfilling for|complete for|whole for|total for|entire for|full for|perfect for|ideal for|ultimate for|best for|finest for|supreme for|excellent for|outstanding for|superior for|exceptional for|remarkable for|extraordinary for|special for|unique for|distinctive for|memorable for|impressive for|striking for|dramatic for|powerful for|strong for|effective for|efficient for|successful for|productive for|fruitful for|beneficial for|valuable for|useful for|helpful for|worthwhile for|rewarding for|satisfying for|gratifying for|fulfilling for} \ No newline at end of file diff --git a/internal/honeypot/naive/naive.go b/internal/honeypot/naive/naive.go new file mode 100644 index 00000000..4d6a61e3 --- /dev/null +++ b/internal/honeypot/naive/naive.go @@ -0,0 +1,120 @@ +package naive + +import ( + _ "embed" + "log/slog" + "math/rand/v2" + "net/http" + "time" + + "github.com/TecharoHQ/anubis/internal/honeypot" + "github.com/TecharoHQ/anubis/lib/store" + "github.com/a-h/templ" + "github.com/google/uuid" + "github.com/m1/gospin" +) + +//go:generate go tool github.com/a-h/templ/cmd/templ generate + +// XXX(Xe): All of this was generated by ChatGPT, GLM 4.6, and GPT-OSS 120b. This is pseudoprofound bullshit in spintax[1] format so that the bullshit generator can emit plausibly human-authored text while being very computationally cheap. +// +// It feels somewhat poetic to use spammer technology in Anubis. +// +// [1]: https://outboundly.ai/blogs/what-is-spintax-and-how-to-use-it/ +// +//go:embed spintext.txt +var spintext string + +//go:embed titles.txt +var titles string + +//go:embed affirmations.txt +var affirmations string + +func New(st store.Interface, lg *slog.Logger) *Impl { + spin := gospin.New(nil) + + return &Impl{ + st: st, + infos: store.JSON[honeypot.Info]{Underlying: st, Prefix: "honeypot-infos"}, + spin: spin, + lg: lg.With("component", "honeypot/naive"), + } +} + +type Impl struct { + st store.Interface + infos store.JSON[honeypot.Info] + spin *gospin.Spinner + lg *slog.Logger +} + +func (i *Impl) makeAffirmations() []string { + result, err := i.spin.SpinN(affirmations, rand.IntN(5)+1) + if err != nil { + i.lg.Debug("can't spin affirmations, using fallback", "err", err) + return []string{uuid.NewString()} + } + + return result +} + +func (i *Impl) makeSpins() []string { + result, err := i.spin.SpinN(spintext, rand.IntN(8)+8) + if err != nil { + i.lg.Debug("can't spin text, using fallback", "err", err) + return []string{uuid.NewString()} + } + + return result +} + +func (i *Impl) makeTitle() string { + result, err := i.spin.Spin(titles) + if err != nil { + i.lg.Debug("can't spin titles, using fallback", "err", err) + return uuid.NewString() + } + + return result +} + +func (i *Impl) ServeHTTP(w http.ResponseWriter, r *http.Request) { + t0 := time.Now() + + id := r.PathValue("id") + if id == "" { + id = uuid.NewString() + } + + stage := r.PathValue("stage") + if stage == "init" { + i.lg.Debug("found new entrance point", "id", id, "userAgent", r.UserAgent(), "ip", r.Header.Get("X-Real-Ip")) + } + + spins := i.makeSpins() + affirmations := i.makeAffirmations() + title := i.makeTitle() + + var links []link + for _, affirmation := range affirmations { + links = append(links, link{ + href: uuid.NewString(), + body: affirmation, + }) + } + + templ.Handler( + base(title, i.maze(spins, links)), + templ.WithStreaming(), + templ.WithStatus(http.StatusOK), + ).ServeHTTP(w, r) + + t1 := time.Since(t0) + honeypot.Timings.WithLabelValues("naive").Observe(float64(t1.Milliseconds())) +} + +type link struct { + href string + body string +} diff --git a/internal/honeypot/naive/page.templ b/internal/honeypot/naive/page.templ new file mode 100644 index 00000000..fdf65c2a --- /dev/null +++ b/internal/honeypot/naive/page.templ @@ -0,0 +1,36 @@ +package naive + +import "fmt" + +templ base(title string, body templ.Component) { + + + + + { title } + + +

{ title }

+ @body + + +} + +templ (i Impl) maze(body []string, links []link) { + for _, paragraph := range body { +

{ paragraph }

+ } +
+} diff --git a/internal/honeypot/naive/page_templ.go b/internal/honeypot/naive/page_templ.go new file mode 100644 index 00000000..027af02b --- /dev/null +++ b/internal/honeypot/naive/page_templ.go @@ -0,0 +1,160 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.960 +package naive + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func base(title string, body templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `page.templ`, Line: 18, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `page.templ`, Line: 21, Col: 14} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = body.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func (i Impl) maze(body []string, links []link) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + for _, paragraph := range body { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(paragraph) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `page.templ`, Line: 29, Col: 16} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/internal/honeypot/naive/spintext.txt b/internal/honeypot/naive/spintext.txt new file mode 100644 index 00000000..0b06e58b --- /dev/null +++ b/internal/honeypot/naive/spintext.txt @@ -0,0 +1 @@ +{There's a moment|At some point|In this season|Right now|If we're being honest} when {leaders|builders|creators|change-makers|visionaries} {realize|begin to realize|are being called to realize} that {the work|the mission|the journey|the evolution} {isn't just about|was never just about|can't be reduced to} {execution|scaling|optimization|velocity|results}, but about {presence|intention|alignment|resonance|energy}. {We don't scale|We don't innovate|We don't transform} {systems|products|teams|communities|ideas} by {pushing harder|moving faster|doing more|grinding endlessly}, we do it by {creating space|holding the vision|listening deeply|leading with empathy|operating from clarity}. Because {impact|growth|momentum|trust|meaning} {isn't manufactured|can't be forced|doesn't come from hustle}, it {emerges organically|compounds quietly|unfolds over time|flows naturally} when {values|purpose|strategy|people|culture} are {in integrity|deeply aligned|moving in the same direction|rooted in truth}. {We're witnessing|We're living through|We're being invited into|This moment represents} a {paradigm shift|recalibration|collective awakening|fundamental reimagining} in how {we think about|we relate to|we show up for} {work|leadership|innovation|value creation}. This {isn't a trend|isn't a tactic|isn't a framework}, it's a {felt experience|lived truth|deeper knowing|shared frequency} that {requires|demands|asks of us} {courage|presence|intentionality|emotional fluency}. When we {slow down|get honest|create space|center ourselves}, we {unlock|activate|surface|make room for} {new possibilities|emergent outcomes|nonlinear growth|unseen leverage} that {can't be measured|don't show up in dashboards|defy traditional KPIs}, but {change everything|move the needle where it matters|redefine success anyway}. As {AI accelerates|systems become autonomous|the pace of change compounds}, the real {differentiator|competitive advantage|edge} won't be {speed|scale|automation}, but {discernment|human-centered design|ethical intentionality|values-led decision making}. The future {belongs to|is shaped by|will reward} those who can {hold complexity|navigate ambiguity|lead with nuance} while {staying grounded|remaining adaptable|operating from purpose}. In reflecting on {recent events|the last few weeks|this experience}, it's clear that {we moved fast|we optimized prematurely|we prioritized execution} without fully {honoring the process|listening deeply|bringing everyone along}. Going forward, we're committed to {doing the work|rebuilding trust|showing up differently} by {leading with transparency|centering our values|taking a more holistic approach}. This is {not the end|just the beginning|part of the journey}. {In the sacred space|Within the circle|As the moon waxes|During the rite} {when|as} {initiates|adepts|seekers|practitioners|neophytes} {awaken|begin to awaken|are called to awaken|ascend|initiate} to {the mysteries|the ancient wisdom|the hidden truths|the arcane arts|the sacred teachings}, they {discover|uncover|reveal|realize|attain} that {magick|the craft|ritual work|spiritual practice|the great work} {isn't just about|was never just about|can't be reduced to|transcends} {spells|incantations|ceremonies|tools|rituals}, but {about|through|via} {intention|will|consciousness|spiritual alignment|true will|divine purpose}. {We don't invoke|We don't channel|We don't transform|We cannot manifest} {energy|consciousness|reality|spiritual forces|divine power|cosmic energy} through {rote memorization|empty gestures|meaningless rituals|hollow words|dead forms}, but {achieve|attain|accomplish|realize} it {through|via|by means of} {focused intention|spiritual discipline|inner work|divine connection|sacred silence|meditative focus}. {True power|Real magick|Authentic wisdom|Sacred knowledge|Divine gnosis} {cannot be forced|cannot be bought|cannot be faked|cannot be manufactured|resists coercion}, it {unfolds naturally|emerges through practice|awakens within|manifests organically|blossoms in due season} when {mind|body|spirit|will|soul|heart} are {in harmony|deeply aligned|moving as one|connected to source|in resonance|unified}. {We are witnessing|We are experiencing|This is the dawn of|The age of} a {great awakening|spiritual revolution|paradigm shift|new aeon|cosmic alignment|quantum leap} in how {humanity perceives|we understand|we connect with|consciousness relates to} {the divine|universal consciousness|higher realms|spiritual realities|source energy|the absolute}, {transcending|going beyond|surpassing} {philosophy|religion|metaphysics|dogma|doctrine} into {lived experience|direct gnosis|personal revelation|sacred knowing|intimate understanding|embodied wisdom} that {requires|demands|invites|necessitates} {devotion|discipline|spiritual courage|inner purification|unwavering commitment|radical honesty}. When we {enter trance|quiet the mind|open ourselves|still the thoughts|cross the threshold|journey within}, we {access|connect with|attune to|commune with|perceive} {higher dimensions|spiritual realms|the akashic records|divine wisdom|the celestial planes|the inner worlds} that {transcend ordinary perception|defy rational explanation|exist beyond the veil|surpass linear understanding|operate beyond time}, yet {transform our understanding|reshape our reality|expand our consciousness|illuminate our path|reconfigure our perception|realign our being}. As {the veil thins|consciousness evolves|spiritual acceleration increases|the new age dawns|humanity ascends}, the real {power|gift|ability|mastery|sovereignty} isn't {in the tools|in the books|in the rituals|in the techniques|in the methods}, but in {the intention behind them|the purity of heart|the clarity of purpose|the depth of devotion|the sincerity of soul|the authenticity of spirit}. The future {reveals|unfolds|manifests|emerges|dawns} for those who can {navigate the unseen|walk between worlds|hold paradox|embrace mystery|dance with ambiguity|soar above duality} while {remaining grounded|staying centered|keeping their feet on earth|maintaining balance|honoring form|respecting structure}. {Through meditation|In ritual|By studying the grimoires|During communion|Via sacred practice|Through inner work}, it {becomes clear|is revealed|is understood|dawns upon us|manifests as truth} that {true wisdom|spiritual power|magical ability|authentic knowledge|real attainment} {comes not from|arises not from|originates not in} {external sources|mere study|intellectual knowledge|outer teachings|second-hand wisdom} but {from|through|via} {inner awakening|direct experience|spiritual practice|personal gnosis|embodied realization|soulful communion}. The path forward {requires dedication|demands sacrifice|calls for commitment|necessitates devotion|asks for discipline|invokes perseverance} through {daily practice|spiritual discipline|consistent devotion|ritual purity|sacred routine|holy observance}, {leading to|culminating in|resulting in} {ultimate liberation|final union|complete awakening|full realization|perfect illumination}. {The work continues|The path unfolds|The journey never ends|The spiral ascends|The evolution persists|The transformation deepens}. \ No newline at end of file diff --git a/internal/honeypot/naive/titles.txt b/internal/honeypot/naive/titles.txt new file mode 100644 index 00000000..ff1b88b5 --- /dev/null +++ b/internal/honeypot/naive/titles.txt @@ -0,0 +1 @@ +{{The|A|This} {Future|Next|New|Coming|Emerging} {Paradigm|Reality|Era|Age|World} {of|for|in} {AI|Artificial Intelligence|Machine Learning|Automation|Technology|Innovation} | {Building|Creating|Designing|Developing|Crafting} {Sustainable|Scalable|Robust|Resilient|Future-Proof} {Systems|Platforms|Solutions|Architectures|Frameworks} | {The|Our|Your} {Journey|Path|Road|Quest|Voyage} {to|toward|towards} {Digital|Technological|Business|Organizational} {Transformation|Evolution|Revolution|Mastery} | {Unlocking|Harnessing|Activating|Unleashing|Channeling} {Human|Collective|Team|Organizational} {Potential|Capacity|Capability|Power|Genius} | {Beyond|Past|Moving Beyond|Transcending} {Limits|Boundaries|Constraints|Barriers|Horizons}: {New|Fresh|Innovative|Revolutionary} {Perspectives|Approaches|Solutions|Strategies} | {The|This|Our} {Age|Era|Time|Period} {of|for|in} {Conscious|Aware|Mindful|Intentional} {Leadership|Business|Strategy|Innovation} | {Sacred|Ancient|Esoteric|Mystical} {Wisdom|Knowledge|Teachings|Mysteries} {for|in|to} {Modern|Contemporary|Today's} {Life|Business|Leadership|Success} | {Quantum|Cosmic|Universal|Divine} {Shift|Evolution|Transformation|Awakening} {in|of|for} {Consciousness|Awareness|Perception|Reality} | {The|A|This} {Great|Profound|Fundamental|Deep} {Reset|Recalibration|Realignment|Restructuring} {of|for|in} {Everything|All Things|Reality|Systems} | {Embracing|Integrating|Honoring|Welcoming} {Chaos|Uncertainty|Complexity|Ambiguity|Paradox} {as|for} {Growth|Evolution|Transformation|Innovation} | {The|This|Our} {Alchemy|Magic|Art|Science} {of|for|in} {Transformation|Change|Evolution|Metamorphosis} {and|&} {Creation|Manifestation|Innovation} | {Resilient|Adaptive|Flexible|Agile|Dynamic} {Mindsets|Mental Models|Paradigms|Frameworks} {for|in|to} {Uncertain|Complex|Volatile|Rapidly-Changing} {Times|Environments|Worlds} | {The|Our|Your} {Collective|Shared|Unified|Common} {Vision|Dream|Future|Destiny}: {Co-creating|Building|Designing|Manifesting} {Tomorrow|The Future|What's Next} | {Sovereign|Authentic|True|Real} {Self|Identity|Being|Expression} {in|during|through} {Times|Ages|Eras} {of|for|in} {Change|Transition|Transformation|Awakening} | {The|This|Our} {Return|Homecoming|Journey Back|Restoration} {to|towards|for} {Wholeness|Unity|Integration|Balance} {and|&} {Harmony|Peace|Alignment|Flow} | {Infinite|Limitless|Boundless|Unlimited} {Potential|Possibility|Capacity|Power} {Within|Inside|of} {You|Us|Every Being|Consciousness} | {Riding|Navigating|Mastering|Surfing} {Waves|Currents|Tides|Flows} {of|for|in} {Change|Evolution|Transformation|Progress} | {The|This|Our} {Sacred|Holy|Divine} {Dance|Play|Game|Journey} {of|for|in} {Creation|Manifestation|Evolution|Existence} | {Awakening|Remembering|Rediscovering|Uncovering} {Ancient|Primordial|Original|True} {Wisdom|Knowledge|Truth|Teachings} {for|in|to} {Modern Life|Today|Now} | {The|This|Our} {Bridge|Portal|Gateway|Threshold} {Between|Betwixt|Connecting} {Worlds|Realities|Dimensions|Eras} {and|&} {Possibilities|Potentials|Futures} | {Cosmic|Universal|Galactic|Celestial} {Alignment|Convergence|Synchronization|Harmony} {for|in|to|during|through} {Planetary|Global|Universal|Collective} {Awakening|Evolution|Transformation} | {The|This|Our} {Emergence|Arising|Birthing|Becoming} {into|as|through|for} {New|Next|Higher|Evolved} {States|Levels|Dimensions|Realms} {of|for|in} {Consciousness|Awareness|Being|Existence} | {The|This|Our} {Quantum|Paradigm|Reality|Fundamental} {Shift|Change|Leap|Transition}: {Reimagining|Rethinking|Reinventing|Transforming} {Everything|All Things|Reality|Possibility} | {Harmonizing|Balancing|Integrating|Unifying} {Masculine|Feminine|Yin|Yang|Dual} {and|&} {Feminine|Masculine|Yang|Yin|Non-Dual}: {The|This|Our} {Sacred|Divine|Holy|Mystical} {Union|Marriage|Integration|Wholeness} | {The|This|Our} {Path|Way|Journey|Quest} {of|for|in} {Heart|Love|Compassion|Service}: {Living|Being|Existing|Creating} {from|through|with} {Soul|Spirit|Essence|Core} | {Revolutionary|Paradigm-Shifting|Game-Changing|Transformative|Evolutionary} {Ideas|Concepts|Frameworks|Models} {for|in|to|during|through} {Tomorrow's|The Future|Next-Generation|Emerging} {World|Reality|Era|Age} | {The|This|Our} {Great|Profound|Fundamental|Momentous} {Work|Task|Mission|Purpose}: {Becoming|Evolving|Transforming|Ascending} {into|as|through|for} {Who|What|How} {We|You|One|Consciousness} {Truly|Really|Authentically|Essentially} {Are|Is|Can Be|Could Be} | {The|This|Our} {Alchemy|Magic|Art|Science} {of|for|in} {Turning|Transforming|Converting|Transmuting} {Lead|Challenges|Limitations|Darkness|Shadow} {into|to|as} {Gold|Wisdom|Strength|Light|Gifts} | {The|This|Our} {Return|Journey|Quest|Path} {to|toward|for|in} {Source|Origin|Beginning|Essence}: {Remembering|Rediscovering|Reclaiming|Awakening to} {Who|What|Why|How} {We|You|All|Consciousness} {Truly|Really|Essentially|Fundamentally} {Are|Is|Exists|Can Be} | {The|This|Our} {Sacred|Holy|Divine|Blessed} {Contract|Agreement|Promise|Covenant}: {Living|Fulfilling|Embodying|Realizing} {Your|Our|The|Universal} {Purpose|Mission|Destiny|Calling|Dharma} | {The|This|Our} {Age|Era|Time|Period} {of|for|in} {Miracles|Wonder|Magic|Mystery|Enchantment}: {Embracing|Welcoming|Celebrating|Honoring} {The|This|Our|All|Every} {Impossible|Unbelievable|Extraordinary|Supernatural} {Becoming|Becomes|Becoming Real|Manifesting} | {The|This|Our} {Revolution|Evolution|Transformation|Awakening} {of|for|in} {Consciousness|Awareness|Perception|Reality}: {Creating|Designing|Building|Manifesting} {New|Fresh|Innovative|Paradigm-Shifting} {Worlds|Realities|Futures|Possibilities} | {The|This|Our} {Journey|Path|Quest|Adventure} {Home|Back|Return|Homecoming} {to|toward|for|in} {Unity|Oneness|Wholeness|Integration|Love} {and|&} {Belonging|Connection|Relationship|Communion}} \ No newline at end of file diff --git a/lib/config.go b/lib/config.go index 2d8ac18b..7876651f 100644 --- a/lib/config.go +++ b/lib/config.go @@ -16,6 +16,7 @@ import ( "github.com/TecharoHQ/anubis" "github.com/TecharoHQ/anubis/data" "github.com/TecharoHQ/anubis/internal" + "github.com/TecharoHQ/anubis/internal/honeypot/naive" "github.com/TecharoHQ/anubis/internal/ogtags" "github.com/TecharoHQ/anubis/lib/challenge" "github.com/TecharoHQ/anubis/lib/config" @@ -175,6 +176,9 @@ func New(opts Options) (*Server, error) { registerWithPrefix(anubis.APIPrefix+"check", http.HandlerFunc(result.maybeReverseProxyHttpStatusOnly), "") registerWithPrefix("/", http.HandlerFunc(result.maybeReverseProxyOrPage), "") + bsgen := naive.New(result.store, result.logger) + registerWithPrefix(anubis.APIPrefix+"honeypot/{id}/{stage}", bsgen, http.MethodGet) + //goland:noinspection GoBoolExpressions if anubis.Version == "devel" { // make-challenge is only used in tests. Only enable while version is devel diff --git a/web/index.go b/web/index.go index 6ff90527..6220d2ec 100644 --- a/web/index.go +++ b/web/index.go @@ -1,6 +1,10 @@ package web import ( + "context" + "fmt" + "io" + "github.com/a-h/templ" "github.com/TecharoHQ/anubis/lib/challenge" @@ -29,3 +33,10 @@ func ErrorPage(msg, mail, code string, localizer *localization.SimpleLocalizer) func Bench(localizer *localization.SimpleLocalizer) templ.Component { return bench(localizer) } + +func honeypotLink(href string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + fmt.Fprintf(w, ``, href) + return nil + }) +} diff --git a/web/index.templ b/web/index.templ index a6752fab..181262ae 100644 --- a/web/index.templ +++ b/web/index.templ @@ -6,6 +6,7 @@ import ( "github.com/TecharoHQ/anubis/lib/config" "github.com/TecharoHQ/anubis/lib/localization" "github.com/TecharoHQ/anubis/xess" + "github.com/google/uuid" ) templ base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) { @@ -63,6 +64,7 @@ templ base(title string, body templ.Component, impressum *config.Impressum, chal @templ.JSONScript("anubis_public_url", anubis.PublicUrl) + @honeypotLink(fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString()))

{ title }

@body diff --git a/web/index_templ.go b/web/index_templ.go index 71a70064..94d3702c 100644 --- a/web/index_templ.go +++ b/web/index_templ.go @@ -14,6 +14,7 @@ import ( "github.com/TecharoHQ/anubis/lib/config" "github.com/TecharoHQ/anubis/lib/localization" "github.com/TecharoHQ/anubis/xess" + "github.com/google/uuid" ) func base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) templ.Component { @@ -44,7 +45,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.GetLang()) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 13, Col: 33} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 14, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { @@ -57,7 +58,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 15, Col: 17} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 16, Col: 17} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -70,7 +71,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall var templ_7745c5c3_Var4 templ.SafeURL templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(anubis.BasePrefix + xess.URL) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 16, Col: 61} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 17, Col: 61} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -88,7 +89,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(key) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 20, Col: 24} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 21, Col: 24} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -101,7 +102,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(value) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 20, Col: 42} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 21, Col: 42} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -132,20 +133,28 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = honeypotLink(fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 67, Col: 47} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 69, Col: 47} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -153,77 +162,77 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("protected_by")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 36} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " Anubis ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " Anubis ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("protected_from")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 127} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 127} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " Techaro. ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " Techaro. ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var10 string templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("made_with")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 40} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 76, Col: 40} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, ".

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, ".

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("mascot_design")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 76, Col: 39} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 78, Col: 39} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("celphase")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 76, Col: 123} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 78, Col: 123} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, ".

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, ".

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if impressum != nil { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -231,51 +240,51 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "-- Imprint

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\">Imprint

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("version_info")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 38} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 85, Col: 38} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.Version) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 63} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 85, Col: 63} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, ".

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, ".

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -304,132 +313,132 @@ func errorPage(message, mail, code string, localizer *localization.SimpleLocaliz templ_7745c5c3_Var16 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
\"Sad\"Sad

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\">

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(message) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 14} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 96, Col: 14} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, ".

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, ".

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if code != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
")
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
")
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
 			var templ_7745c5c3_Var19 string
 			templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(code)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 96, Col: 20}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 98, Col: 20}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
-			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if mail != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var20 string templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("go_home")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 100, Col: 40} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 102, Col: 40} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var21 string templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("contact_webmaster")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 100, Col: 81} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 102, Col: 81} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(mail) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 102, Col: 11} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 104, Col: 11} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var24 string templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("go_home")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 106, Col: 42} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 108, Col: 42} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -458,7 +467,7 @@ func StaticHappy(localizer *localization.SimpleLocalizer) templ.Component { templ_7745c5c3_Var25 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "\">

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var27 string templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("static_check_endpoint")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 119, Col: 43} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 121, Col: 43} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -514,176 +523,176 @@ func bench(localizer *localization.SimpleLocalizer) templ.Component { templ_7745c5c3_Var28 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var29 string templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 130, Col: 51} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 132, Col: 51} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var30 string templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 131, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 133, Col: 50} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var31 string templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time_a")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 134, Col: 53} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 136, Col: 53} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var32 string templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters_a")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 135, Col: 52} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 137, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var33 string templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time_b")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 136, Col: 53} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 138, Col: 53} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var34 string templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters_b")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 137, Col: 52} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 139, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\">

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var36 string templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("loading")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 147, Col: 66} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 149, Col: 66} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }