Compare commits

...

27 Commits

Author SHA1 Message Date
Jason Cameron
978af9d5ff chore: add comments back to Challenge struct.
See #1284
and https://github.com/TecharoHQ/anubis/pull/1284#issuecomment-3784096905
2026-01-22 09:46:38 -05:00
Timon de Groot
57c0b2b22c Add IP mapped Perplexity user agents (#1393)
Perplexity has some proper documentation available for their crawlers,
with published IP addresses: https://docs.perplexity.ai/guides/bots.

Signed-off-by: Timon de Groot <timon.degroot@team.blue>
2026-01-15 19:57:31 -05:00
Thomas Arrow
186ffeb744 docs: clarify botstopper kubernetes instructions (#1404)
This makes it clear that when generating a kubernetes secret to pull the bot stopper image that:
- no email is required
- a user is required but the actual value of the username is not checked
- the GH token needs to be pasted in

Signed-off-by: Thomas Arrow <tarrow@users.noreply.github.com>
2026-01-15 11:13:10 +00:00
Xe Iaso
ff87aac4e7 fix(web): include base prefix in generated URLs (#1403)
* fix(web): include base prefix in generated URLs

Forgot to add the base prefix to these URLs. Committed a fix for this
and added a test to ensure this does not repeat. Oops!

Closes: #1402
Signed-off-by: Xe Iaso <me@xeiaso.net>

* docs: update CHANGELOG

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-01-14 23:47:44 +00:00
Anton Kesy
3c76724aeb fix: correct typos (#1398) 2026-01-12 01:23:58 +00:00
Andrew Young
1db57e5d23 fix sponsor (Databento) logo size (#1395) 2026-01-09 23:42:03 +00:00
Xe Iaso
6fc2c3c857 docs: document how to import the default config (#1392)
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-01-08 16:14:52 +00:00
dependabot[bot]
149e864786 build(deps): bump preact from 10.28.0 to 10.28.1 in the npm group (#1387)
Bumps the npm group with 1 update: [preact](https://github.com/preactjs/preact).


Updates `preact` from 10.28.0 to 10.28.1
- [Release notes](https://github.com/preactjs/preact/releases)
- [Commits](https://github.com/preactjs/preact/compare/10.28.0...10.28.1)

---
updated-dependencies:
- dependency-name: preact
  dependency-version: 10.28.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2026-01-05 21:44:28 -05:00
Jason Cameron
2aaee6c348 Revert "build(deps): bump the gomod group across 1 directory with 3 updates (…" (#1386) 2026-01-04 00:13:45 +00:00
dependabot[bot]
ebad69a4e1 build(deps): bump the gomod group across 1 directory with 3 updates (#1370)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jason Cameron <jason.cameron@stanwith.me>
2026-01-03 19:06:05 -05:00
lif
71147b4857 fix: respect Accept-Language quality factors in language detection (#1380)
The Accept-Language header parsing was not correctly handling quality
factors. When a browser sends "en-GB,de-DE;q=0.5", the expected behavior
is to prefer English (q=1.0 by default) over German (q=0.5).

The fix uses golang.org/x/text/language.ParseAcceptLanguage to properly
parse and sort language preferences by quality factor. It also adds base
language fallbacks (e.g., "en" for "en-GB") to ensure regional variants
match their parent languages when no exact match exists.

Fixes #1022

Signed-off-by: majiayu000 <1835304752@qq.com>
2026-01-02 08:01:43 -05:00
lif
cee7871ef8 fix: update SSL Labs IP addresses (#1377)
Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: Jason Cameron <jason.cameron@stanwith.me>
2026-01-01 23:21:31 -05:00
Jason Cameron
26d258fb94 Update check-spelling metadata (#1379) 2026-01-01 23:02:15 +00:00
Xe Iaso
80a8e0a8ae chore: add Databento as diamond tier sponsor
Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-30 10:56:58 -05:00
Xe Iaso
359613f35a feat: iplist2rule utility command (#1373)
* feat: iplist2rule utility command

Assisted-By: GLM 4.7 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>

* docs: update CHANGELOG

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: fix spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: fix spelling again

Signed-off-by: Xe Iaso <me@xeiaso.net>

* feat(iplist2rule): add comment describing how rule was generated

Signed-off-by: Xe Iaso <me@xeiaso.net>

* docs: add iplist2rule docs

Signed-off-by: Xe Iaso <me@xeiaso.net>

* chore: fix spelling

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-29 17:10:17 +00:00
Xe Iaso
1d8e98c5ec test(nginx): fix tests to work in GHA (#1372)
* test(nginx): fix tests to work in GHA

Closes: #1371
Signed-off-by: Xe Iaso <me@xeiaso.net>

* fix(test): does this work lol

Signed-off-by: Xe Iaso <me@xeiaso.net>

* fix(test): does this other thing work lol

Signed-off-by: Xe Iaso <me@xeiaso.net>

* fix(test): pki folder location

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2025-12-28 23:59:48 -05:00
Jason Cameron
880020095c fix(test): remove interactive flag from nginx smoke test docker run command (#1371) 2025-12-29 03:14:50 +00:00
dependabot[bot]
f5728e96a1 build(deps-dev): bump esbuild from 0.27.1 to 0.27.2 in the npm group (#1368)
Co-authored-by: Jason Cameron <git@jsn.cam>
2025-12-28 22:07:44 -05:00
dependabot[bot]
bcf525dbcf build(deps): bump the github-actions group with 3 updates (#1369)
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2025-12-28 22:04:16 -05:00
Xe Iaso
d748dc9da8 test: basic nginx smoke test (#1365)
* docs: split nginx configuration files to their own directory

Signed-off-by: Xe Iaso <me@xeiaso.net>

* test: add nginx config smoke test based on the config in the docs

Signed-off-by: Xe Iaso <me@xeiaso.net>

---------

Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-28 23:18:25 +00:00
p0008874
9b210d795e docs(known-instances): Alphabetical order + Add Valve Corporation (#1352)
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2025-12-26 01:05:26 +00:00
The Ninth
e084e5011e feat(localization): add Polish language translation (#1363)
(cherry picked from commit 1f9c2272e6)

Co-authored-by: bplajzer <b.plajzerr@gmail.com>
2025-12-25 15:14:04 -05:00
dependabot[bot]
2532478abd build(deps): bump the github-actions group with 4 updates (#1355)
Co-authored-by: Jason Cameron <git@jasoncameron.dev>
2025-12-24 01:02:48 -05:00
Xe Iaso
6d9c0abe74 chore: tag v1.24.0
Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-23 21:17:59 -05:00
Xe Iaso
a37068a423 fix(default-config): remove browser detection logic (#1360)
Looks like these rules don't work anymore.

Closes: #1353

Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-24 02:13:54 +00:00
Xe Iaso
9d9be61c24 fix(default-config): must-accept-rule on browsers only (#1350)
TIL docker clients don't include the Accept header all the time. I would
have thought they did that. Oops.

Closes: #1346

Signed-off-by: Xe Iaso <me@xeiaso.net>
2025-12-19 20:42:24 +00:00
Michael
535ed74b17 i18n(de): improve consistency and wording (#1348)
- Use consistent informal address (fix simplified_explanation)
- Translate "protected_from" ("From" → "Von")
- Standardize "Webseite" → "Website"
- Use more natural phrasing:
  - "Berechnung wird durchgeführt" → "Berechnung läuft"
  - "Zur Hauptseite" → "Zur Startseite"
  - Replace awkward "sozialen Vertrag" phrasing
- "Fingerabdruckerkennung" → "Browser-Fingerprinting" (more common)
- Improve sentence structure and punctuation

Signed-off-by: Michael <87752300+michi-onl@users.noreply.github.com>
2025-12-19 00:29:49 +00:00
67 changed files with 1708 additions and 931 deletions

View File

@@ -18,3 +18,9 @@ clampip
pseudoprofound pseudoprofound
reimagining reimagining
iocaine iocaine
admins
fout
iplist
NArg
blocklists
rififi

View File

@@ -87,10 +87,14 @@
^docs/docs/user/known-instances.md$ ^docs/docs/user/known-instances.md$
^docs/manifest/.*$ ^docs/manifest/.*$
^docs/static/\.nojekyll$ ^docs/static/\.nojekyll$
^lib/policy/config/testdata/bad/unparseable\.json$
^internal/glob/glob_test.go$ ^internal/glob/glob_test.go$
^internal/honeypot/naive/affirmations\.txt$
^internal/honeypot/naive/spintext\.txt$
^internal/honeypot/naive/titles\.txt$
^lib/config/testdata/bad/unparseable\.json$
^lib/localization/.*_test.go$
^lib/localization/locales/.*\.json$
^lib/policy/config/testdata/bad/unparseable\.json$
^test/.*$
ignore$ ignore$
robots.txt robots.txt
^lib/localization/locales/.*\.json$
^lib/localization/.*_test.go$
^test/.*$

View File

@@ -1,409 +1,406 @@
acs acs
Actorified Actorified
actorifiedstore actorifiedstore
actorify actorify
Aibrew Aibrew
alibaba alibaba
alrest alrest
amazonbot amazonbot
anthro anthro
anubis anubis
anubistest anubistest
apnic apnic
APNICRANDNETAU APNICRANDNETAU
Applebot Applebot
archlinux archlinux
arpa arpa
asnc asnc
asnchecker asnchecker
asns asns
aspirational aspirational
atuin atuin
azuretools azuretools
badregexes badregexes
bbolt bbolt
bdba bdba
berr berr
bezier bezier
bingbot bingbot
Bitcoin Bitcoin
bitrate bitrate
Bluesky Bluesky
blueskybot blueskybot
boi boi
Bokm Bokm
botnet botnet
botstopper botstopper
BPort BPort
Brightbot Brightbot
broked broked
buildah buildah
byteslice byteslice
Bytespider Bytespider
cachebuster cachebuster
cachediptoasn cachediptoasn
Caddyfile Caddyfile
caninetools caninetools
Cardyb Cardyb
celchecker celchecker
celphase celphase
cerr cerr
certresolver certresolver
cespare cespare
CGNAT CGNAT
cgr cgr
chainguard chainguard
chall chall
challengemozilla challengemozilla
challengetest challengetest
checkpath checkpath
checkresult checkresult
chibi chibi
cidranger cidranger
ckie ckie
cloudflare cloudflare
Codespaces Codespaces
confd confd
connnection connnection
containerbuild containerbuild
containerregistry containerregistry
coreutils coreutils
Cotoyogi Cotoyogi
Cromite Cromite
crt crt
Cscript Cscript
daemonizing daemonizing
dayjob databento
DDOS dayjob
Debian DDOS
debrpm Debian
decaymap debrpm
devcontainers decaymap
Diffbot devcontainers
discordapp Diffbot
discordbot discordapp
distros discordbot
dnf distros
dnsbl dnf
dnserr dnsbl
DNSTTL dnserr
domainhere DNSTTL
dracula domainhere
dronebl dracula
droneblresponse dronebl
dropin droneblresponse
dsilence dropin
duckduckbot dsilence
eerror duckduckbot
ellenjoe eerror
emacs ellenjoe
enbyware emacs
etld enbyware
everyones etld
evilbot everyones
evilsite evilbot
expressionorlist evilsite
externalagent expressionorlist
externalfetcher externalagent
extldflags externalfetcher
facebookgo extldflags
Factset facebookgo
fahedouch Factset
fastcgi fahedouch
FCr fastcgi
fcrdns FCr
fediverse fcrdns
ffprobe fediverse
financials ffprobe
finfos financials
Firecrawl finfos
flagenv Firecrawl
Fordola flagenv
forgejo Fordola
forwardauth forgejo
fsys forwardauth
fullchain fsys
gaissmai fullchain
Galvus gaissmai
geoip Galvus
geoipchecker geoip
gha geoipchecker
GHSA gha
Ghz GHSA
gipc Ghz
gitea gipc
godotenv gitea
goland GLM
gomod godotenv
goodbot goland
googlebot gomod
gopsutil goodbot
govulncheck googlebot
goyaml gopsutil
GPG govulncheck
GPT goyaml
gptbot GPG
Graphene GPT
grpcprom gptbot
grw Graphene
gzw grpcprom
Hashcash grw
hashrate gzw
headermap Hashcash
healthcheck hashrate
healthz headermap
hec healthcheck
helpdesk healthz
Hetzner hec
hmc helpdesk
homelab Hetzner
hostable hmc
htmlc homelab
htmx hostable
httpdebug htmlc
huawei htmx
hypertext httpdebug
iaskspider huawei
iaso hypertext
iat iaskspider
ifm iaso
Imagesift iat
imgproxy ifm
impressum Imagesift
inbox imgproxy
ingressed impressum
inp inbox
internets ingressed
IPTo inp
iptoasn internets
isp IPTo
iss iptoasn
isset isp
ivh iss
Jenomis isset
JGit ivh
jhjj Jenomis
joho JGit
journalctl jhjj
jshelter joho
JWTs journalctl
kagi jshelter
kagibot JWTs
Keyfunc kagi
keypair kagibot
KHTML Keyfunc
kinda keypair
KUBECONFIG KHTML
lcj kinda
ldflags KUBECONFIG
letsencrypt lcj
Lexentale ldflags
lfc letsencrypt
lgbt Lexentale
licend lfc
licstart lgbt
lightpanda licend
limsa licstart
Linting lightpanda
listor limsa
LLU Linting
loadbalancer listor
lol LLU
lominsa loadbalancer
maintainership lol
malware lominsa
mcr maintainership
memes malware
metarefresh mcr
metrix memes
mimi metarefresh
Minfilia metrix
mistralai mimi
mnt Minfilia
Mojeek mistralai
mojeekbot mnt
mozilla Mojeek
myclient mojeekbot
mymaster mozilla
mypass myclient
myuser mymaster
nbf mypass
nepeat myuser
netsurf nbf
nginx nepeat
nicksnyder netsurf
nobots nginx
NONINFRINGEMENT nicksnyder
nosleep nikandfor
nullglob nobots
oci NONINFRINGEMENT
OCOB nosleep
ogtag nullglob
oklch oci
omgili OCOB
omgilibot ogtag
openai oklch
opendns omgili
opengraph omgilibot
openrc openai
oswald opendns
pag opengraph
palemoon openrc
Pangu oswald
parseable pag
passthrough pagegen
Patreon palemoon
pgrep Pangu
phrik parseable
pidfile passthrough
pids Patreon
pipefail pgrep
pki phrik
podkova pidfile
podman pids
Postgre pipefail
poststart pki
prebaked podkova
privkey podman
promauto Postgre
promhttp poststart
proofofwork prebaked
publicsuffix privkey
purejs promauto
pwcmd promhttp
pwuser proofofwork
qualys publicsuffix
qwant purejs
qwantbot pwcmd
rac pwuser
rawler qualys
rcvar qwant
redhat qwantbot
redir rac
redirectscheme rawler
refactors rcvar
remoteip redhat
reputational redir
risc redirectscheme
ruleset refactors
runlevels remoteip
RUnlock reputational
runtimedir Rhul
runtimedirectory risc
Ryzen ruleset
sas runlevels
sasl RUnlock
screenshots runtimedir
searchbot runtimedirectory
searx Ryzen
sebest sas
secretplans sasl
Semrush screenshots
Seo searchbot
setsebool searx
shellcheck sebest
shirou secretplans
shopt Semrush
Sidetrade Seo
simprint setsebool
sitemap shellcheck
sls shirou
sni shoneypot
snipster shopt
Spambot Sidetrade
sparkline simprint
spyderbot sitemap
srv sls
stackoverflow sni
startprecmd snipster
stoppostcmd Spambot
storetest spammer
subgrid sparkline
subr spyderbot
subrequest srv
SVCNAME stackoverflow
tagline startprecmd
tarballs stoppostcmd
tarrif storetest
taviso subgrid
tbn subr
tbr subrequest
techaro SVCNAME
techarohq tagline
telegrambot tarballs
templ tarrif
templruntime taviso
testarea tbn
Thancred tbr
thoth techaro
thothmock techarohq
Tik telegrambot
Timpibot templ
TLog templruntime
traefik testarea
trunc Thancred
uberspace thoth
Unbreak thothmock
unbreakdocker Tik
unifiedjs Timpibot
unmarshal TLog
unparseable traefik
uvx trunc
UXP uberspace
valkey Unbreak
Varis unbreakdocker
Velen unifiedjs
vendored unmarshal
verify unparseable
vhosts uvx
vkbot UXP
VKE valkey
vnd Varis
VPS Velen
Vultr vendored
weblate vhosts
webmaster vkbot
webpage VKE
websecure vnd
websites VPS
Webzio Vultr
whois weblate
wildbase webmaster
withthothmock webpage
wolfbeast websecure
wordpress websites
workaround Webzio
workdir whois
wpbot wildbase
XCircle withthothmock
xeiaso wolfbeast
xeserv wordpress
xesite workaround
xess workdir
xff wpbot
XForwarded XCircle
XNG xeiaso
XOB xeserv
XOriginal xesite
XReal xess
yae xff
YAMLTo XForwarded
Yda XNG
yeet XOB
yeetfile XOriginal
yourdomain XReal
yyz Y'shtola
Zenos yae
zizmor YAMLTo
zombocom Yda
zos yeet
GLM yeetfile
iocaine yourdomain
nikandfor yyz
pagegen Zenos
pseudoprofound zizmor
reimagining zombocom
Rhul zos
shoneypot
spammer
Y'shtola

View File

@@ -68,7 +68,7 @@ jobs:
SLOG_LEVEL: debug SLOG_LEVEL: debug
- name: Generate artifact attestation - name: Generate artifact attestation
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0
with: with:
subject-name: ${{ env.IMAGE }} subject-name: ${{ env.IMAGE }}
subject-digest: ${{ steps.build.outputs.digest }} subject-digest: ${{ steps.build.outputs.digest }}

View File

@@ -22,7 +22,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log into registry - name: Log into registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
@@ -53,14 +53,14 @@ jobs:
push: true push: true
- name: Apply k8s manifests to limsa lominsa - name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@2639090a038d46a3b9b98b220ae0837676ded8b7 # v1.34.3 uses: actions-hub/kubectl@f6d776bd78f4523e36d6c74d34f9941c242b2213 # v1.35.0
env: env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }} KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with: with:
args: apply -k docs/manifest args: apply -k docs/manifest
- name: Apply k8s manifests to limsa lominsa - name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@2639090a038d46a3b9b98b220ae0837676ded8b7 # v1.34.3 uses: actions-hub/kubectl@f6d776bd78f4523e36d6c74d34f9941c242b2213 # v1.35.0
env: env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }} KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with: with:

View File

@@ -18,7 +18,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Docker meta - name: Docker meta
id: meta id: meta

View File

@@ -32,7 +32,7 @@ jobs:
go-version: '1.25.4' go-version: '1.25.4'
- name: Cache playwright binaries - name: Cache playwright binaries
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
id: playwright-cache id: playwright-cache
with: with:
path: | path: |

View File

@@ -41,7 +41,7 @@ jobs:
run: | run: |
go tool yeet go tool yeet
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with: with:
name: packages name: packages
path: var/* path: var/*

View File

@@ -23,6 +23,7 @@ jobs:
- healthcheck - healthcheck
- i18n - i18n
- log-file - log-file
- nginx
- palemoon/amd64 - palemoon/amd64
#- palemoon/i386 #- palemoon/i386
- robots_txt - robots_txt
@@ -35,10 +36,10 @@ jobs:
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with: with:
node-version: '24.11.0' node-version: "24.11.0"
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: '1.25.4' go-version: "1.25.4"
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
@@ -56,7 +57,7 @@ jobs:
run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
if: always() if: always()
with: with:
name: ${{ env.ARTIFACT_NAME }} name: ${{ env.ARTIFACT_NAME }}

View File

@@ -30,7 +30,7 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Build and push - name: Build and push
run: | run: |
cd ./test/ssh-ci cd ./test/ssh-ci

View File

@@ -21,7 +21,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Install the latest version of uv - name: Install the latest version of uv
uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
- name: Run zizmor 🌈 - name: Run zizmor 🌈
run: uvx zizmor --format sarif . > results.sarif run: uvx zizmor --format sarif . > results.sarif
@@ -29,7 +29,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file - name: Upload SARIF file
uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with: with:
sarif_file: results.sarif sarif_file: results.sarif
category: zizmor category: zizmor

View File

@@ -20,6 +20,9 @@ Anubis is brought to you by sponsors and donors like:
<a href="https://www.raptorcs.com/content/base/products.html"> <a href="https://www.raptorcs.com/content/base/products.html">
<img src="./docs/static/img/sponsors/raptor-computing-logo.webp" alt="Raptor Computing Systems" height=64 /> <img src="./docs/static/img/sponsors/raptor-computing-logo.webp" alt="Raptor Computing Systems" height=64 />
</a> </a>
<a href="https://databento.com/?utm_source=anubis&utm_medium=sponsor&utm_campaign=anubis">
<img src="./docs/static/img/sponsors/databento-logo.webp" alt="Databento" height="64" />
</a>
### Gold Tier ### Gold Tier

View File

@@ -1 +1 @@
1.24.0-pre1 1.24.0

View File

@@ -3,5 +3,6 @@
- name: qualys-ssl-labs - name: qualys-ssl-labs
action: ALLOW action: ALLOW
remote_addresses: remote_addresses:
- 64.41.200.0/24 - 69.67.183.0/24
- 2600:C02:1020:4202::/64 - 2600:C02:1020:4202::/64
- 2602:fdaa:c6:2::/64

View File

@@ -95,50 +95,6 @@ bots:
# weight: # weight:
# adjust: -10 # 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
# 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
# Generic catchall rule # Generic catchall rule
- name: generic-browser - name: generic-browser
user_agent_regex: >- user_agent_regex: >-

View File

@@ -4,5 +4,5 @@
# - Claude-User: No published IP allowlist # - Claude-User: No published IP allowlist
- name: "ai-clients" - name: "ai-clients"
user_agent_regex: >- user_agent_regex: >-
ChatGPT-User|Claude-User|MistralAI-User ChatGPT-User|Claude-User|MistralAI-User|Perplexity-User
action: DENY action: DENY

View File

@@ -0,0 +1,12 @@
# Acts on behalf of user requests
# https://docs.perplexity.ai/guides/bots
- name: perplexity-user
user_agent_regex: Perplexity-User/.+; \+https\://perplexity\.ai/perplexity-user
action: ALLOW
# https://www.perplexity.com/perplexity-user.json
remote_addresses: [
"44.208.221.197/32",
"34.193.163.52/32",
"18.97.21.0/30",
"18.97.43.80/29",
]

View File

@@ -0,0 +1,55 @@
# Assert behaviour that only genuine browsers display. This ensures that modern Chrome
# or Firefox versions will get through without a challenge.
#
# These rules have been known to be bypassed by some of the worst automated scrapers.
# Use at your own risk.
- 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
# 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
# Generic catchall rule
- name: generic-browser
user_agent_regex: >-
Mozilla|Opera
action: WEIGH
weight:
adjust: 10

View File

@@ -4,5 +4,5 @@
# - Claude-SearchBot: No published IP allowlist # - Claude-SearchBot: No published IP allowlist
- name: "ai-crawlers-search" - name: "ai-crawlers-search"
user_agent_regex: >- user_agent_regex: >-
OAI-SearchBot|Claude-SearchBot OAI-SearchBot|Claude-SearchBot|PerplexityBot
action: DENY action: DENY

View File

@@ -0,0 +1,16 @@
# Indexing for search, does not collect training data
# https://docs.perplexity.ai/guides/bots
- name: perplexitybot
user_agent_regex: PerplexityBot/.+; \+https\://perplexity\.ai/perplexitybot
action: ALLOW
# https://www.perplexity.com/perplexitybot.json
remote_addresses: [
"107.20.236.150/32",
"3.224.62.45/32",
"18.210.92.235/32",
"3.222.232.239/32",
"3.211.124.183/32",
"3.231.139.107/32",
"18.97.1.228/30",
"18.97.9.96/29",
]

View File

@@ -3,5 +3,7 @@
- import: (data)/bots/ai-catchall.yaml - import: (data)/bots/ai-catchall.yaml
- import: (data)/crawlers/ai-training.yaml - import: (data)/crawlers/ai-training.yaml
- import: (data)/crawlers/openai-searchbot.yaml - import: (data)/crawlers/openai-searchbot.yaml
- import: (data)/crawlers/perplexitybot.yaml
- import: (data)/clients/openai-chatgpt-user.yaml - import: (data)/clients/openai-chatgpt-user.yaml
- import: (data)/clients/mistral-mistralai-user.yaml - import: (data)/clients/mistral-mistralai-user.yaml
- import: (data)/clients/perplexity-user.yaml

View File

@@ -2,5 +2,7 @@
- import: (data)/bots/ai-catchall.yaml - import: (data)/bots/ai-catchall.yaml
- import: (data)/crawlers/openai-searchbot.yaml - import: (data)/crawlers/openai-searchbot.yaml
- import: (data)/crawlers/openai-gptbot.yaml - import: (data)/crawlers/openai-gptbot.yaml
- import: (data)/crawlers/perplexitybot.yaml
- import: (data)/clients/openai-chatgpt-user.yaml - import: (data)/clients/openai-chatgpt-user.yaml
- import: (data)/clients/mistral-mistralai-user.yaml - import: (data)/clients/mistral-mistralai-user.yaml
- import: (data)/clients/perplexity-user.yaml

View File

@@ -79,50 +79,6 @@
# weight: # weight:
# adjust: -10 # 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
# 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
# Generic catchall rule # Generic catchall rule
- name: generic-browser - name: generic-browser
user_agent_regex: >- user_agent_regex: >-

View File

@@ -226,7 +226,7 @@ So far Anubis supports the following languages:
- English (Simplified and Traditional) - English (Simplified and Traditional)
- French - French
- Portugese (Brazil) - Portuguese (Brazil)
- Spanish - Spanish
If you want to contribute translations, please [file an issue](https://github.com/TecharoHQ/anubis/issues/new) with your language of choice or submit a pull request to [the `lib/localization/locales` folder](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). We are about to introduce features to the translation stack, so you may want to hold off a hot minute, but we welcome any and all contributions to making Anubis useful to a global audience. If you want to contribute translations, please [file an issue](https://github.com/TecharoHQ/anubis/issues/new) with your language of choice or submit a pull request to [the `lib/localization/locales` folder](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). We are about to introduce features to the translation stack, so you may want to hold off a hot minute, but we welcome any and all contributions to making Anubis useful to a global audience.

View File

@@ -69,7 +69,7 @@ I am waiting to hear back from NLNet on if Anubis was selected for funding or no
Anubis now supports localized responses. Locales can be added in [lib/localization/locales/](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). This release includes support for the following languages: Anubis now supports localized responses. Locales can be added in [lib/localization/locales/](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). This release includes support for the following languages:
- [Brazilian Portugese](https://github.com/TecharoHQ/anubis/pull/726) - [Brazilian Portuguese](https://github.com/TecharoHQ/anubis/pull/726)
- [Chinese (Simplified)](https://github.com/TecharoHQ/anubis/pull/774) - [Chinese (Simplified)](https://github.com/TecharoHQ/anubis/pull/774)
- [Chinese (Traditional)](https://github.com/TecharoHQ/anubis/pull/759) - [Chinese (Traditional)](https://github.com/TecharoHQ/anubis/pull/759)
- [Czech](https://github.com/TecharoHQ/anubis/pull/849) - [Czech](https://github.com/TecharoHQ/anubis/pull/849)

View File

@@ -11,9 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
- Add iplist2rule tool that lets admins turn an IP address blocklist into an Anubis ruleset.
- Add Polish locale ([#1292](https://github.com/TecharoHQ/anubis/pull/1309))
- Fix honeypot and imprint links missing `BASE_PREFIX` when deployed behind a path prefix ([#1402](https://github.com/TecharoHQ/anubis/issues/1402))
<!-- This changes the project to: --> <!-- This changes the project to: -->
## v1.24.0 [pre1]: Y'shtola Rhul ## v1.24.0: Y'shtola Rhul
Anubis is back and better than ever! Lots of minor fixes with some big ones interspersed. Anubis is back and better than ever! Lots of minor fixes with some big ones interspersed.
@@ -27,6 +31,8 @@ Anubis is back and better than ever! Lots of minor fixes with some big ones inte
- Add support to simple Valkey/Redis cluster mode - Add support to simple Valkey/Redis cluster mode
- Open Graph passthrough now reuses the configured target Host/SNI/TLS settings, so metadata fetches succeed when the upstream certificate differs from the public domain. ([1283](https://github.com/TecharoHQ/anubis/pull/1283)) - Open Graph passthrough now reuses the configured target Host/SNI/TLS settings, so metadata fetches succeed when the upstream certificate differs from the public domain. ([1283](https://github.com/TecharoHQ/anubis/pull/1283))
- Stabilize the CVE-2025-24369 regression test by always submitting an invalid proof instead of relying on random POW failures. - Stabilize the CVE-2025-24369 regression test by always submitting an invalid proof instead of relying on random POW failures.
- Refine the check that ensures the presence of the Accept header to avoid breaking docker clients.
- Removed rules intended to reward actual browsers due to abuse in the wild.
### Dataset poisoning ### Dataset poisoning

View File

@@ -51,9 +51,8 @@ If you are using Kubernetes, you will need to create an image pull secret:
kubectl create secret docker-registry \ kubectl create secret docker-registry \
techarohq-botstopper \ techarohq-botstopper \
--docker-server ghcr.io \ --docker-server ghcr.io \
--docker-username your-username \ --docker-username any-username \
--docker-password your-access-token \ --docker-password <your-access-token> \
--docker-email your@email.address
``` ```
Then attach it to your Deployment: Then attach it to your Deployment:
@@ -85,7 +84,7 @@ Follow [the upstream Docker compose directions](https://anubis.techaro.lol/docs/
OG_EXPIRY_TIME: "24h" OG_EXPIRY_TIME: "24h"
+ # botstopper config here + # botstopper config here
+ CHALLENGE_TITLE: "Doing math for your connnection!" + CHALLENGE_TITLE: "Doing math for your connection!"
+ ERROR_TITLE: "Something went wrong!" + ERROR_TITLE: "Something went wrong!"
+ OVERLAY_FOLDER: /assets + OVERLAY_FOLDER: /assets
+ volumes: + volumes:

View File

@@ -13,6 +13,8 @@ bots:
- # This correlates to data/bots/ai-catchall.yaml in the source tree - # This correlates to data/bots/ai-catchall.yaml in the source tree
import: (data)/bots/ai-catchall.yaml import: (data)/bots/ai-catchall.yaml
- import: (data)/bots/cloudflare-workers.yaml - import: (data)/bots/cloudflare-workers.yaml
# Import all the rules in the default configuration
- import: (data)/meta/default-config.yaml
``` ```
Of note, a bot rule can either have inline bot configuration or import a bot config snippet. You cannot do both in a single bot rule. Of note, a bot rule can either have inline bot configuration or import a bot config snippet. You cannot do both in a single bot rule.
@@ -35,6 +37,33 @@ config.BotOrImport: rule definition is invalid, you must set either bot rules or
Paths can either be prefixed with `(data)` to import from the [the data folder in the Anubis source tree](https://github.com/TecharoHQ/anubis/tree/main/data) or anywhere on the filesystem. If you don't have access to the Anubis source tree, check /usr/share/docs/anubis/data or in the tarball you extracted Anubis from. Paths can either be prefixed with `(data)` to import from the [the data folder in the Anubis source tree](https://github.com/TecharoHQ/anubis/tree/main/data) or anywhere on the filesystem. If you don't have access to the Anubis source tree, check /usr/share/docs/anubis/data or in the tarball you extracted Anubis from.
## Importing the default configuration
If you want to base your configuration off of the default configuration, import `(data)/meta/default-config.yaml`:
```yaml
bots:
- import: (data)/meta/default-config.yaml
# Write your rules here
```
This will keep your configuration up to date as Anubis adapts to emerging threats.
## How do I exempt most modern browsers from Anubis challenges?
If you want to exempt most modern browsers from Anubis challenges, import `(data)/common/acts-like-browser.yaml`:
```yaml
bots:
- import: (data)/meta/default-config.yaml
- import: (data)/common/acts-like-browser.yaml
# Write your rules here
```
These rules will allow traffic that "looks like" it's from a modern copy of Edge, Safari, Chrome, or Firefox. These rules used to be enabled by default, however user reports have suggested that AI scraper bots have adapted to conform to these rules to scrape without regard for the infrastructure they are attacking.
Use these rules at your own risk.
## Importing from imports ## Importing from imports
You can also import from an imported file in case you want to import an entire folder of rules at once. You can also import from an imported file in case you want to import an entire folder of rules at once.

View File

@@ -1,5 +1,7 @@
# Nginx # Nginx
import CodeBlock from "@theme/CodeBlock";
Anubis is intended to be a filter proxy. The way to integrate this with nginx is to break your configuration up into two parts: TLS termination and then HTTP routing. Consider this diagram: Anubis is intended to be a filter proxy. The way to integrate this with nginx is to break your configuration up into two parts: TLS termination and then HTTP routing. Consider this diagram:
```mermaid ```mermaid
@@ -36,110 +38,26 @@ These examples assume that you are using a setup where your nginx configuration
Assuming that we are protecting `anubistest.techaro.lol`, here's what the server configuration file would look like: Assuming that we are protecting `anubistest.techaro.lol`, here's what the server configuration file would look like:
```nginx import anubisTest from "!!raw-loader!./nginx/server-anubistest-techaro-lol.conf";
# /etc/nginx/conf.d/server-anubistest-techaro-lol.conf
# HTTP - Redirect all HTTP traffic to HTTPS <CodeBlock language="nginx">{anubisTest}</CodeBlock>
server {
listen 80;
listen [::]:80;
server_name anubistest.techaro.lol;
location / {
return 301 https://$host$request_uri;
}
}
# TLS termination server, this will listen over TLS (https) and then
# proxy all traffic to the target via Anubis.
server {
# Listen on TCP port 443 with TLS (https) and HTTP/2
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Http-Version $server_protocol;
proxy_pass http://anubis;
}
server_name anubistest.techaro.lol;
ssl_certificate /path/to/your/certs/anubistest.techaro.lol.crt;
ssl_certificate_key /path/to/your/certs/anubistest.techaro.lol.key;
}
# Backend server, this is where your webapp should actually live.
server {
listen unix:/run/nginx/nginx.sock;
server_name anubistest.techaro.lol;
root "/srv/http/anubistest.techaro.lol";
index index.html;
# Get the visiting IP from the TLS termination server
set_real_ip_from unix:;
real_ip_header X-Real-IP;
# Your normal configuration can go here
# location .php { fastcgi...} etc.
}
```
:::tip :::tip
You can copy the `location /` block into a separate file named something like `conf-anubis.inc` and then include it inline to other `server` blocks: You can copy the `location /` block into a separate file named something like `conf-anubis.inc` and then include it inline to other `server` blocks:
```nginx import anubisInclude from "!!raw-loader!./nginx/conf-anubis.inc";
# /etc/nginx/conf.d/conf-anubis.inc
# Forward to anubis <CodeBlock language="nginx">{anubisInclude}</CodeBlock>
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://anubis;
}
```
Then in a server block: Then in a server block:
<details> <details>
<summary>Full nginx config</summary> <summary>Full nginx config</summary>
```nginx import mimiTecharoLol from "!!raw-loader!./nginx/server-mimi-techaro-lol.conf";
# /etc/nginx/conf.d/server-mimi-techaro-lol.conf
server { <CodeBlock language="nginx">{mimiTecharoLol}</CodeBlock>
# Listen on 443 with SSL
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# Slipstream via Anubis
include "conf-anubis.inc";
server_name mimi.techaro.lol;
ssl_certificate /path/to/your/certs/mimi.techaro.lol.crt;
ssl_certificate_key /path/to/your/certs/mimi.techaro.lol.key;
}
server {
listen unix:/run/nginx/nginx.sock;
server_name mimi.techaro.lol;
port_in_redirect off;
root "/srv/http/mimi.techaro.lol";
index index.html;
# Your normal configuration can go here
# location .php { fastcgi...} etc.
}
```
</details> </details>
@@ -147,24 +65,9 @@ server {
Create an upstream for Anubis. Create an upstream for Anubis.
```nginx import anubisUpstream from "!!raw-loader!./nginx/upstream-anubis.conf";
# /etc/nginx/conf.d/upstream-anubis.conf
upstream anubis { <CodeBlock language="nginx">{anubisUpstream}</CodeBlock>
# Make sure this matches the values you set for `BIND` and `BIND_NETWORK`.
# If this does not match, your services will not be protected by Anubis.
# Try anubis first over a UNIX socket
server unix:/run/anubis/nginx.sock;
#server 127.0.0.1:8923;
# Optional: fall back to serving the websites directly. This allows your
# websites to be resilient against Anubis failing, at the risk of exposing
# them to the raw internet without protection. This is a tradeoff and can
# be worth it in some edge cases.
#server unix:/run/nginx.sock backup;
}
```
This can be repeated for multiple sites. Anubis does not care about the HTTP `Host` header and will happily cope with multiple websites via the same instance. This can be repeated for multiple sites. Anubis does not care about the HTTP `Host` header and will happily cope with multiple websites via the same instance.

View File

@@ -0,0 +1,8 @@
# /etc/nginx/conf-anubis.inc
# Forward to anubis
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://anubis;
}

View File

@@ -0,0 +1,50 @@
# /etc/nginx/conf.d/server-anubistest-techaro-lol.conf
# HTTP - Redirect all HTTP traffic to HTTPS
server {
listen 80;
listen [::]:80;
server_name anubistest.techaro.lol;
location / {
return 301 https://$host$request_uri;
}
}
# TLS termination server, this will listen over TLS (https) and then
# proxy all traffic to the target via Anubis.
server {
# Listen on TCP port 443 with TLS (https) and HTTP/2
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Http-Version $server_protocol;
proxy_pass http://anubis;
}
server_name anubistest.techaro.lol;
ssl_certificate /path/to/your/certs/anubistest.techaro.lol.crt;
ssl_certificate_key /path/to/your/certs/anubistest.techaro.lol.key;
}
# Backend server, this is where your webapp should actually live.
server {
listen unix:/run/nginx/nginx.sock;
server_name anubistest.techaro.lol;
root "/srv/http/anubistest.techaro.lol";
index index.html;
# Get the visiting IP from the TLS termination server
set_real_ip_from unix:;
real_ip_header X-Real-IP;
# Your normal configuration can go here
# location .php { fastcgi...} etc.
}

View File

@@ -0,0 +1,29 @@
# /etc/nginx/conf.d/server-mimi-techaro-lol.conf
server {
# Listen on 443 with SSL
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# Slipstream via Anubis
include "conf-anubis.inc";
server_name mimi.techaro.lol;
ssl_certificate /path/to/your/certs/mimi.techaro.lol.crt;
ssl_certificate_key /path/to/your/certs/mimi.techaro.lol.key;
}
server {
listen unix:/run/nginx/nginx.sock;
server_name mimi.techaro.lol;
port_in_redirect off;
root "/srv/http/mimi.techaro.lol";
index index.html;
# Your normal configuration can go here
# location .php { fastcgi...} etc.
}

View File

@@ -0,0 +1,16 @@
# /etc/nginx/conf.d/upstream-anubis.conf
upstream anubis {
# Make sure this matches the values you set for `BIND` and `BIND_NETWORK`.
# If this does not match, your services will not be protected by Anubis.
# Try anubis first over a UNIX socket
server unix:/run/anubis/nginx.sock;
#server 127.0.0.1:8923;
# Optional: fall back to serving the websites directly. This allows your
# websites to be resilient against Anubis failing, at the risk of exposing
# them to the raw internet without protection. This is a tradeoff and can
# be worth it in some edge cases.
#server unix:/run/nginx.sock backup;
}

View File

@@ -0,0 +1,50 @@
---
title: iplist2rule CLI tool
---
The `iplist2rule` tool converts IP blocklists into Anubis challenge policies. It reads common IP block list formats and generates the appropriate Anubis policy file for IP address filtering.
## Installation
Install directly with Go
```bash
go install github.com/TecharoHQ/anubis/utils/cmd/iplist2rule@latest
```
## Usage
Basic conversion from URL:
```bash
iplist2rule https://raw.githubusercontent.com/7c/torfilter/refs/heads/main/lists/txt/torfilter-1m-flat.txt filter-tor.yaml
```
Explicitly allow every IP address on a list:
```bash
iplist2rule --action ALLOW https://raw.githubusercontent.com/7c/torfilter/refs/heads/main/lists/txt/torfilter-1m-flat.txt filter-tor.yaml
```
Add weight to requests matching IP addresses on a list:
```bash
iplist2rule --action WEIGH --weight 20 https://raw.githubusercontent.com/7c/torfilter/refs/heads/main/lists/txt/torfilter-1m-flat.txt filter-tor.yaml
```
## Options
| Flag | Description | Default |
| :------------ | :----------------------------------------------------------------------------------------------- | :-------------------------------- |
| `--action` | The Anubis action to take for the IP address in question, must be in ALL CAPS. | `DENY` (forbids traffic) |
| `--rule-name` | The name for the generated Anubis rule, should be in kebab-case. | (not set, inferred from filename) |
| `--weight` | When `--action=WEIGH`, how many weight points should be added or removed from matching requests? | 0 (not set) |
## Using the Generated Policy
Save the output and import it in your main policy file:
```yaml
bots:
- import: "./filter-tor.yaml"
```

View File

@@ -12,6 +12,7 @@ Install directly with Go:
```bash ```bash
go install github.com/TecharoHQ/anubis/cmd/robots2policy@latest go install github.com/TecharoHQ/anubis/cmd/robots2policy@latest
``` ```
## Usage ## Usage
Basic conversion from URL: Basic conversion from URL:
@@ -35,8 +36,8 @@ robots2policy -input robots.txt -action DENY -format json
## Options ## Options
| Flag | Description | Default | | Flag | Description | Default |
|-----------------------|--------------------------------------------------------------------|---------------------| | --------------------- | ------------------------------------------------------------------ | ------------------- |
| `-input` | robots.txt file path or URL (use `-` for stdin) | *required* | | `-input` | robots.txt file path or URL (use `-` for stdin) | _required_ |
| `-output` | Output file (use `-` for stdout) | stdout | | `-output` | Output file (use `-` for stdout) | stdout |
| `-format` | Output format: `yaml` or `json` | `yaml` | | `-format` | Output format: `yaml` or `json` | `yaml` |
| `-action` | Action for disallowed paths: `ALLOW`, `DENY`, `CHALLENGE`, `WEIGH` | `CHALLENGE` | | `-action` | Action for disallowed paths: `ALLOW`, `DENY`, `CHALLENGE`, `WEIGH` | `CHALLENGE` |
@@ -47,6 +48,7 @@ robots2policy -input robots.txt -action DENY -format json
## Example ## Example
Input robots.txt: Input robots.txt:
```txt ```txt
User-agent: * User-agent: *
Disallow: /admin/ Disallow: /admin/
@@ -57,6 +59,7 @@ Disallow: /
``` ```
Generated policy: Generated policy:
```yaml ```yaml
- name: robots-txt-policy-disallow-1 - name: robots-txt-policy-disallow-1
action: CHALLENGE action: CHALLENGE
@@ -77,8 +80,8 @@ Generated policy:
Save the output and import it in your main policy file: Save the output and import it in your main policy file:
```yaml ```yaml
import: bots:
- path: "./robots-policy.yaml" - import: "./robots-policy.yaml"
``` ```
The tool handles wildcard patterns, user-agent specific rules, and blacklisted bots automatically. The tool handles wildcard patterns, user-agent specific rules, and blacklisted bots automatically.

View File

@@ -29,6 +29,9 @@ Anubis is brought to you by sponsors and donors like:
height="64" height="64"
/> />
</a> </a>
<a href="https://databento.com/?utm_source=anubis&utm_medium=sponsor&utm_campaign=anubis">
<img src="/img/sponsors/databento-logo.webp" alt="Databento" height="64" />
</a>
### Gold Tier ### Gold Tier

View File

@@ -4,67 +4,83 @@ title: List of known websites using Anubis
This page contains a non-exhaustive list with all websites using Anubis. This page contains a non-exhaustive list with all websites using Anubis.
- <details> - https://azurlane.koumakan.jp/
<summary>The Linux Foundation</summary>
- https://git.kernel.org/
- https://lore.kernel.org/
</details>
- https://gitlab.gnome.org/
- https://scioly.org/
- https://bugs.winehq.org/ - https://bugs.winehq.org/
- https://bugzilla.proxmox.com
- https://canine.tools/
- https://clew.se/
- https://code.hackerspace.pl/
- https://codeberg.org/
- https://dev.haiku-os.org
- https://dev.sanctum.geek.nz/
- https://ebird.org/
- https://extensions.typo3.org/
- https://fabulous.systems/
- https://git.aya.so/
- https://git.devuan.org/
- https://git.enlightenment.org/
- https://gitea.com/
- https://gitlab.freedesktop.org/
- https://gitlab.gnome.org/
- https://gitlab.postmarketos.org/
- https://hosted.weblate.org/
- https://hydra.nixos.org/
- https://lab.civicrm.org/
- https://marginalia-search.com/
- https://mozillazine.org/
- https://openwrt.org/
- https://pluralpedia.org/
- https://reddit.nerdvpn.de/
- https://repositorio.ufrn.br/home/
- https://rpmfusion.org/
- https://scioly.org/
- https://source.puri.sm/
- https://squirreljme.cc/
- https://superlove.sayitditto.net/
- https://svnweb.freebsd.org/ - https://svnweb.freebsd.org/
- https://trac.ffmpeg.org/ - https://trac.ffmpeg.org/
- https://xeiaso.net/
- https://source.puri.sm/
- https://git.enlightenment.org/
- https://superlove.sayitditto.net/
- https://linktaco.com/
- https://jaredallard.dev/
- https://dev.sanctum.geek.nz/
- https://canine.tools/
- https://git.lupancham.net/
- https://dev.haiku-os.org
- http://code.hackerspace.pl/
- https://wiki.archlinux.org/
- https://git.devuan.org/
- https://hydra.nixos.org/
- https://codeberg.org/
- https://www.cfaarchive.org/
- https://gitlab.freedesktop.org/
- https://bugzilla.proxmox.com
- https://hofstede.io/
- https://www.indiemag.fr/
- https://reddit.nerdvpn.de/
- https://hosted.weblate.org/
- https://gitea.com/
- https://openwrt.org/
- https://minihoot.site
- https://catgirl.click/
- https://wiki.dolphin-emu.org/
- https://squirreljme.cc/
- https://gitlab.postmarketos.org/
- https://wiki.koha-community.org/
- https://extensions.typo3.org/
- https://ebird.org/
- https://fabulous.systems/
- https://coinhoards.org/
- https://pluralpedia.org/
- https://git.aya.so/
- https://marginalia-search.com/
- https://repositorio.ufrn.br/home/
- https://mozillazine.org/
- https://clew.se/
- https://tumfatig.net/ - https://tumfatig.net/
- https://rpmfusion.org/ - https://wiki.archlinux.org/
- https://wiki.dolphin-emu.org/
- https://wiki.freepascal.org/ - https://wiki.freepascal.org/
- https://azurlane.koumakan.jp/ - https://wiki.koha-community.org/
- https://lab.civicrm.org/ - https://www.cfaarchive.org/
- https://git.door43.org/ - https://www.indiemag.fr/
- https://xeiaso.net/
- <details>
<summary>archlinux32.org</summary>
- https://www.archlinux32.org/packages/
- https://bbs.archlinux32.org/
- https://bugs.archlinux32.org/
</details>
- <details>
<summary>Duke University</summary>
- https://repository.duke.edu/
- https://archives.lib.duke.edu/
- https://find.library.duke.edu/
- https://nicholas.duke.edu/
</details>
- <details>
<summary>Forschungszentrum Jülich</summary>
- https://juser.fz-juelich.de/
</details>
- <details> - <details>
<summary>FreeCAD</summary> <summary>FreeCAD</summary>
- https://forum.freecad.org/ - https://forum.freecad.org/
- https://wiki.freecad.org/ - https://wiki.freecad.org/
</details> </details>
- <details>
<summary>HackLab.TO</summary>
- https://hacklab.to/
- https://knowledge.hacklab.to/
</details>
- <details>
<summary>hebis (Alliance of Hessian Libraries)</summary>
- https://ubmr.hds.hebis.de/
- https://tufind.hds.hebis.de/
- https://karla.hds.hebis.de/
- and many more (see https://www.hebis.de/dienste/hebis-discovery-system/)
</details>
- <details> - <details>
<summary>ReactOS</summary> <summary>ReactOS</summary>
- https://reactos.org/forum - https://reactos.org/forum
@@ -77,6 +93,11 @@ This page contains a non-exhaustive list with all websites using Anubis.
- https://forums.scummvm.org/ - https://forums.scummvm.org/
- https://wiki.scummvm.org/ - https://wiki.scummvm.org/
</details> </details>
- <details>
<summary>Slackware</summary>
- https://git.slackware.nl/
- https://git.liveslak.org/
</details>
- <details> - <details>
<summary>Sourceware</summary> <summary>Sourceware</summary>
- https://sourceware.org/cgit - https://sourceware.org/cgit
@@ -86,41 +107,16 @@ This page contains a non-exhaustive list with all websites using Anubis.
- https://gcc.gnu.org/bugzilla/ - https://gcc.gnu.org/bugzilla/
- https://gcc.gnu.org/cgit - https://gcc.gnu.org/cgit
</details> </details>
- <details>
<summary>The Linux Foundation</summary>
- https://git.kernel.org/
- https://lore.kernel.org/
</details>
- <details> - <details>
<summary>The United Nations</summary> <summary>The United Nations</summary>
- https://policytoolbox.iiep.unesco.org/ - https://policytoolbox.iiep.unesco.org/
</details> </details>
- <details> - <details>
<summary>hebis (Alliance of Hessian Libraries)</summary> <summary>Valve Corporation</summary>
- https://ubmr.hds.hebis.de/ - https://developer.valvesoftware.com/wiki/Main_Page
- https://tufind.hds.hebis.de/
- https://karla.hds.hebis.de/
- and many more (see https://www.hebis.de/dienste/hebis-discovery-system/)
</details>
- <details>
<summary>Duke University</summary>
- https://repository.duke.edu/
- https://archives.lib.duke.edu/
- https://find.library.duke.edu/
- https://nicholas.duke.edu/
</details>
- <details>
<summary>Forschungszentrum Jülich</summary>
- https://juser.fz-juelich.de/
</details>
- <details>
<summary>archlinux32.org</summary>
- https://www.archlinux32.org/packages/
- https://bbs.archlinux32.org/
- https://bugs.archlinux32.org/
</details>
- <details>
<summary>HackLab.TO</summary>
- https://hacklab.to/
- https://knowledge.hacklab.to/
</details>
- <details>
<summary>Slackware</summary>
- https://git.slackware.nl/
- https://git.liveslak.org/
</details> </details>

View File

@@ -160,7 +160,7 @@ impressum:
<h2>How the Information is used</h2> <h2>How the Information is used</h2>
<p>The information is used to enhance the vistor's experience when using the website to display personalised content and possibly advertising.</p> <p>The information is used to enhance the visitor's experience when using the website to display personalised content and possibly advertising.</p>
<p>E-mail addresses will not be sold, rented or leased to 3rd parties.</p> <p>E-mail addresses will not be sold, rented or leased to 3rd parties.</p>

100
docs/package-lock.json generated
View File

@@ -14,6 +14,7 @@
"@mdx-js/react": "^3.0.0", "@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0", "prism-react-renderer": "^2.3.0",
"raw-loader": "^4.0.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0"
}, },
@@ -161,6 +162,7 @@
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.29.0.tgz", "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.29.0.tgz",
"integrity": "sha512-cZ0Iq3OzFUPpgszzDr1G1aJV5UMIZ4VygJ2Az252q4Rdf5cQMhYEIKArWY/oUjMhQmosM8ygOovNq7gvA9CdCg==", "integrity": "sha512-cZ0Iq3OzFUPpgszzDr1G1aJV5UMIZ4VygJ2Az252q4Rdf5cQMhYEIKArWY/oUjMhQmosM8ygOovNq7gvA9CdCg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@algolia/client-common": "5.29.0", "@algolia/client-common": "5.29.0",
"@algolia/requester-browser-xhr": "5.29.0", "@algolia/requester-browser-xhr": "5.29.0",
@@ -308,6 +310,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3", "@babel/generator": "^7.28.3",
@@ -2145,6 +2148,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
}, },
@@ -2167,6 +2171,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -2247,6 +2252,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@@ -2610,6 +2616,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@@ -3523,6 +3530,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.1.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.1.tgz",
"integrity": "sha512-oByRkSZzeGNQByCMaX+kif5Nl2vmtj2IHQI2fWjCfCootsdKZDPFLonhIp5s3IGJO7PLUfe0POyw0Xh/RrGXJA==", "integrity": "sha512-oByRkSZzeGNQByCMaX+kif5Nl2vmtj2IHQI2fWjCfCootsdKZDPFLonhIp5s3IGJO7PLUfe0POyw0Xh/RrGXJA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@docusaurus/core": "3.8.1", "@docusaurus/core": "3.8.1",
"@docusaurus/logger": "3.8.1", "@docusaurus/logger": "3.8.1",
@@ -4246,6 +4254,7 @@
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz",
"integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/mdx": "^2.0.0" "@types/mdx": "^2.0.0"
}, },
@@ -4558,6 +4567,7 @@
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/core": "^7.21.3", "@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0", "@svgr/babel-preset": "8.1.0",
@@ -5200,6 +5210,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz",
"integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
@@ -5539,6 +5550,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -5594,6 +5606,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1", "fast-uri": "^3.0.1",
@@ -5639,6 +5652,7 @@
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.29.0.tgz", "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.29.0.tgz",
"integrity": "sha512-E2l6AlTWGznM2e7vEE6T6hzObvEyXukxMOlBmVlMyixZyK1umuO/CiVc6sDBbzVH0oEviCE5IfVY1oZBmccYPQ==", "integrity": "sha512-E2l6AlTWGznM2e7vEE6T6hzObvEyXukxMOlBmVlMyixZyK1umuO/CiVc6sDBbzVH0oEviCE5IfVY1oZBmccYPQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@algolia/client-abtesting": "5.29.0", "@algolia/client-abtesting": "5.29.0",
"@algolia/client-analytics": "5.29.0", "@algolia/client-analytics": "5.29.0",
@@ -6092,6 +6106,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001737", "caniuse-lite": "^1.0.30001737",
"electron-to-chromium": "^1.5.211", "electron-to-chromium": "^1.5.211",
@@ -6375,6 +6390,7 @@
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
"integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/cst-dts-gen": "11.0.3",
"@chevrotain/gast": "11.0.3", "@chevrotain/gast": "11.0.3",
@@ -7079,6 +7095,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@@ -7398,6 +7415,7 @@
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz", "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz",
"integrity": "sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==", "integrity": "sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10" "node": ">=0.10"
} }
@@ -7819,6 +7837,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC", "license": "ISC",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
@@ -8977,6 +8996,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -13596,6 +13616,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -14170,6 +14191,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@@ -15073,6 +15095,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@@ -15845,6 +15868,76 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/raw-loader": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
"integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
"license": "MIT",
"dependencies": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
}
},
"node_modules/raw-loader/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/raw-loader/node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"license": "MIT",
"peerDependencies": {
"ajv": "^6.9.1"
}
},
"node_modules/raw-loader/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"license": "MIT"
},
"node_modules/raw-loader/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/rc": { "node_modules/rc": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -15874,6 +15967,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -15883,6 +15977,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
"integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.25.0" "scheduler": "^0.25.0"
}, },
@@ -15938,6 +16033,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz",
"integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
}, },
@@ -15966,6 +16062,7 @@
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.13", "@babel/runtime": "^7.12.13",
"history": "^4.9.0", "history": "^4.9.0",
@@ -17804,6 +17901,7 @@
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -18151,6 +18249,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -18398,6 +18497,7 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz",
"integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/eslint-scope": "^3.7.7", "@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6", "@types/estree": "^1.0.6",

View File

@@ -21,6 +21,7 @@
"@mdx-js/react": "^3.0.0", "@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0", "prism-react-renderer": "^2.3.0",
"raw-loader": "^4.0.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0"
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -4,12 +4,12 @@ import "time"
// Challenge is the metadata about a single challenge issuance. // Challenge is the metadata about a single challenge issuance.
type Challenge struct { type Challenge struct {
IssuedAt time.Time `json:"issuedAt"` IssuedAt time.Time `json:"issuedAt"` // When the challenge was issued
Metadata map[string]string `json:"metadata"` Metadata map[string]string `json:"metadata"` // Challenge metadata such as IP address and user agent
ID string `json:"id"` ID string `json:"id"` // UUID identifying the challenge
Method string `json:"method"` Method string `json:"method"` // Challenge method
RandomData string `json:"randomData"` RandomData string `json:"randomData"` // The random data the client processes
PolicyRuleHash string `json:"policyRuleHash,omitempty"` PolicyRuleHash string `json:"policyRuleHash,omitempty"` // Hash of the policy rule that issued this challenge
Difficulty int `json:"difficulty,omitempty"` Difficulty int `json:"difficulty,omitempty"` // Difficulty that was in effect when issued
Spent bool `json:"spent"` Spent bool `json:"spent"` // Has the challenge already been solved?
} }

View File

@@ -52,7 +52,7 @@ func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *challenge.Validate
wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 800 * time.Millisecond) wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 800 * time.Millisecond)
if time.Now().Before(wantTime) { if time.Now().Before(wantTime) {
return challenge.NewError("validate", "insufficent time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339))) return challenge.NewError("validate", "insufficient time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339)))
} }
gotChallenge := r.FormValue("challenge") gotChallenge := r.FormValue("challenge")

View File

@@ -60,7 +60,7 @@ func (i *impl) Validate(r *http.Request, lg *slog.Logger, in *challenge.Validate
wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 80 * time.Millisecond) wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 80 * time.Millisecond)
if time.Now().Before(wantTime) { if time.Now().Before(wantTime) {
return challenge.NewError("validate", "insufficent time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339))) return challenge.NewError("validate", "insufficient time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339)))
} }
got := r.FormValue("result") got := r.FormValue("result")

View File

@@ -15,7 +15,7 @@ var (
type Logging struct { type Logging struct {
Sink string `json:"sink"` // Logging sink, either "stdio" or "file" Sink string `json:"sink"` // Logging sink, either "stdio" or "file"
Level *slog.Level `json:"level"` // Log level, if set supercedes the level in flags Level *slog.Level `json:"level"` // Log level, if set supersedes the level in flags
Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future
} }

View File

@@ -2,20 +2,21 @@
"loading": "Ladevorgang...", "loading": "Ladevorgang...",
"why_am_i_seeing": "Warum sehe ich diese Seite?", "why_am_i_seeing": "Warum sehe ich diese Seite?",
"protected_by": "Geschützt durch", "protected_by": "Geschützt durch",
"protected_from": "From", "protected_from": "Von",
"made_with": "Mit ❤️ gemacht in 🇨🇦", "made_with": "Mit ❤️ entwickelt in 🇨🇦",
"mascot_design": "Maskottchen erstellt von", "mascot_design": "Maskottchen erstellt von",
"ai_companies_explanation": "Diese Seite wird angezeigt, da der Betreiber der Webseite Anubis eingerichtet hat, um sie vor aggressiven KI-Website-Scrapern zu schützen. Diese können Ausfälle der Webseite verursachen, wodurch die Webseite für niemanden erreichbar ist.", "ai_companies_explanation": "Diese Seite wird angezeigt, da der Betreiber der Website Anubis eingerichtet hat, um sie vor aggressiven Webcrawlern von KI-Unternehmen zu schützen. Diese können Ausfälle verursachen, wodurch die Website für niemanden erreichbar ist.",
"anubis_compromise": "Anubis stellt einen Kompromiss dar. Es verwendet eine Proof-of-Work-Methode nach Hashcash, die ursprünglich zur Bekämpfung von E-Mail-Spam entwickelt wurde. Die Idee dahinter ist, dass ein legitimer Besucher die Webseite mit einer vernachlässigbaren Verzögerung erreichen kann. Massenhaftes Scraping wird dadurch jedoch aufwändig und teuer.", "anubis_compromise": "Anubis stellt einen Kompromiss dar. Es verwendet eine Proof-of-Work-Methode nach dem Hashcash-Prinzip, das ursprünglich zur Bekämpfung von E-Mail-Spam entwickelt wurde. Die Idee dahinter: Für einen einzelnen Besucher ist die Verzögerung vernachlässigbar, aber massenhaftes Scraping wird dadurch aufwändig und teuer.",
"hack_purpose": "Letztendlich ist dies eine Platzhalterlösung, damit mehr Zeit für die Fingerabdruckerkennung und Identifizierung von Headless-Browsern (z. B. anhand ihrer Schriftwiedergabe) aufgewendet werden kann, sodass die Proof-of-Work-Seite nicht Benutzern präsentiert werden muss, die viel wahrscheinlicher legitim sind.", "hack_purpose": "Letztendlich ist dies eine Übergangslösung, um mehr Zeit für Browser-Fingerprinting und die Identifizierung von Headless-Browsern (z. B. anhand ihrer Schriftwiedergabe) zu gewinnen. So muss die Proof-of-Work-Seite nicht Nutzern angezeigt werden, die sehr wahrscheinlich legitim sind.",
"jshelter_note": "Anubis benötigt moderne JavaScript-Features, welche von Plugins wie JShelter deaktiviert werden. Bitte deaktiviere JShelter oder ähnliche Plugins für diese Domain.", "simplified_explanation": "Dies ist eine Maßnahme gegen Bots und bösartige Anfragen, ähnlich einem CAPTCHA. Anstatt jedoch selbst arbeiten zu müssen, erhält dein Browser eine Rechenaufgabe, um sicherzustellen, dass es sich um einen gültigen Client handelt. Dieses Konzept nennt sich <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Proof of Work</a>. Die Aufgabe wird in wenigen Sekunden berechnet und du erhältst Zugriff auf die Website. Danke für deine Geduld.",
"version_info": "Diese Webseite läuft mit der Anubis-Version", "jshelter_note": "Anubis benötigt moderne JavaScript-Features, die von Plugins wie JShelter deaktiviert werden. Bitte deaktiviere JShelter oder ähnliche Plugins für diese Domain.",
"version_info": "Diese Website läuft mit Anubis-Version",
"try_again": "Erneut versuchen", "try_again": "Erneut versuchen",
"go_home": "Zur Hauptseite", "go_home": "Zur Startseite",
"contact_webmaster": "oder wenn Du glaubst, dass es sich hierbei um einen Fehler handelt, kontaktiere bitte den Administrator der Webseite unter", "contact_webmaster": "Falls du glaubst, dass es sich um einen Fehler handelt, kontaktiere bitte den Administrator unter",
"connection_security": "Bitte warte einen Moment, während wir sicherstellen, dass eine sichere Verbindung verwendet wird.", "connection_security": "Bitte warte einen Moment, während wir die Sicherheit deiner Verbindung prüfen.",
"javascript_required": "Du musst JavaScript aktivieren, um diese Prüfung durchführen zu können. Dies ist notwendig, da KI-Unternehmen den sozialen Vertrag bezüglich des Hostings von Webseiten gebrochen haben. Eine Lösung ohne JavaScript ist in Entwicklung.", "javascript_required": "Du musst JavaScript aktivieren, um diese Prüfung durchführen zu können. Dies ist notwendig, da KI-Unternehmen die bisherigen Regeln für das Hosting von Websites nicht mehr respektieren. Eine Lösung ohne JavaScript ist in Entwicklung.",
"benchmark_requires_js": "Für die Nutzung des Benchmark-Tools muss JavaScript aktiviert werden.", "benchmark_requires_js": "Für die Nutzung des Benchmark-Tools muss JavaScript aktiviert sein.",
"difficulty": "Schwierigkeit:", "difficulty": "Schwierigkeit:",
"algorithm": "Algorithmus:", "algorithm": "Algorithmus:",
"compare": "Vergleich:", "compare": "Vergleich:",
@@ -25,42 +26,41 @@
"iters_a": "Iterationen A", "iters_a": "Iterationen A",
"time_b": "Zeit B", "time_b": "Zeit B",
"iters_b": "Iterationen B", "iters_b": "Iterationen B",
"static_check_endpoint": "Dies ist nur ein Endpunkt, der von einem Reverse-Proxy geprüft werden kann.", "static_check_endpoint": "Dies ist ein Endpunkt zur Prüfung durch einen Reverse-Proxy.",
"authorization_required": "Zugriffserlaubnis benötigt", "authorization_required": "Autorisierung erforderlich",
"cookies_disabled": "Cookies sind in deinem Browser deaktiviert. Anubis benötigt Cookies, um sicherzustellen, dass es sich hierbei um einen legitimen Zugriff handelt. Bitte aktiviere Cookies für diese Domain.", "cookies_disabled": "Cookies sind in deinem Browser deaktiviert. Anubis benötigt Cookies, um sicherzustellen, dass es sich um einen legitimen Zugriff handelt. Bitte aktiviere Cookies für diese Domain.",
"access_denied": "Zugriff verweigert: Fehlercode", "access_denied": "Zugriff verweigert Fehlercode",
"dronebl_entry": "Eintrag in DroneBL", "dronebl_entry": "Eintrag in DroneBL",
"see_dronebl_lookup": "anzeigen", "see_dronebl_lookup": "anzeigen",
"internal_server_error": "Interner Server-Fehler: Der Administrator hat Anubis fehlerhaft konfiguriert. Bitte kontaktiere den Administrator und bitte ihn, die Logs zu prüfen.", "internal_server_error": "Interner Serverfehler: Der Administrator hat Anubis fehlerhaft konfiguriert. Bitte kontaktiere den Administrator und bitte ihn, die Logs zu prüfen.",
"invalid_redirect": "Ungültige Weiterleitung", "invalid_redirect": "Ungültige Weiterleitung",
"redirect_not_parseable": "URL der Weiterleitung kann nicht verarbeitet werden", "redirect_not_parseable": "Weiterleitungs-URL kann nicht verarbeitet werden",
"redirect_domain_not_allowed": "Domain der Weiterleitung nicht erlaubt", "redirect_domain_not_allowed": "Weiterleitungs-Domain nicht erlaubt",
"missing_required_forwarded_headers": "Erforderliche X-Forwarded-*-Header fehlen",
"failed_to_sign_jwt": "JWT konnte nicht signiert werden", "failed_to_sign_jwt": "JWT konnte nicht signiert werden",
"invalid_invocation": "Ungültiger Aufruf von MakeChallenge", "invalid_invocation": "Ungültiger Aufruf von MakeChallenge",
"client_error_browser": "Client-Fehler: Bitte stelle sicher, dass dein Browser aktuell ist und versuche es später erneut.", "client_error_browser": "Client-Fehler: Bitte stelle sicher, dass dein Browser aktuell ist, und versuche es später erneut.",
"oh_noes": "Oh nein!", "oh_noes": "Oh nein!",
"benchmarking_anubis": "Benchmark wird durchgeführt!", "benchmarking_anubis": "Benchmark wird durchgeführt!",
"you_are_not_a_bot": "Du bist kein Bot!", "you_are_not_a_bot": "Du bist kein Bot!",
"making_sure_not_bot": "Dein Browser wird geprüft!", "making_sure_not_bot": "Dein Browser wird geprüft!",
"celphase": "CELPHASE", "celphase": "CELPHASE",
"js_web_crypto_error": "Dein Browser hat kein funktionierendes web.crypto Element. Wird eine sichere Verbindung verwendet?", "js_web_crypto_error": "Dein Browser verfügt nicht über ein funktionierendes web.crypto-Element. Wird eine sichere Verbindung verwendet?",
"js_web_workers_error": "Dein Browser unterstützt keine Web-Worker (Anubis verwendet diese, damit der Browser nicht einfriert). Ist ein Plugin wie JShelter installiert?", "js_web_workers_error": "Dein Browser unterstützt keine Web-Worker (Anubis verwendet diese, damit der Browser nicht einfriert). Ist ein Plugin wie JShelter installiert?",
"js_cookies_error": "Dein Browser speichert keine Cookies. Anubis verwendet Cookies, um nach bestandener Prüfung ein signiertes Token abzulegen. Bitte aktiviere Cookies für diese Domain. Die Cookie-Namen von Anubis könnten sich jederzeit ändern. Cookie-Namen und die gespeicherten Werte sind kein Teil der öffentlichen API.", "js_cookies_error": "Dein Browser speichert keine Cookies. Anubis verwendet Cookies, um nach bestandener Prüfung ein signiertes Token abzulegen. Bitte aktiviere Cookies für diese Domain. Die Cookie-Namen von Anubis können sich jederzeit ändern. Cookie-Namen und gespeicherte Werte sind nicht Teil der öffentlichen API.",
"js_context_not_secure": "Diese Verbindung ist nicht sicher!", "js_context_not_secure": "Diese Verbindung ist nicht sicher!",
"js_context_not_secure_msg": "Bitte versuche, dich via HTTPS zu verbinden oder weise den Administrator darauf hin, HTTPS einzurichten. Mehr Informationen unter: <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.", "js_context_not_secure_msg": "Bitte versuche, dich über HTTPS zu verbinden, oder weise den Administrator darauf hin, HTTPS einzurichten. Mehr Informationen: <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
"js_calculating": "Berechnung wird durchgeführt...", "js_calculating": "Berechnung läuft...",
"js_missing_feature": "Fehlendes Feature", "js_missing_feature": "Fehlendes Feature",
"js_challenge_error": "Prüfung fehlgeschlagen!", "js_challenge_error": "Prüfung fehlgeschlagen!",
"js_challenge_error_msg": "Der Prüf-Algorithmus konnte nicht geladen werden. Bitte lade diese Seite erneut.", "js_challenge_error_msg": "Der Prüf-Algorithmus konnte nicht geladen werden. Bitte lade die Seite neu.",
"js_calculating_difficulty": "Berechnung wird durchgeführt...<br/>Schwierigkeit:", "js_calculating_difficulty": "Berechnung läuft...<br/>Schwierigkeit:",
"js_speed": "Geschwindigkeit:", "js_speed": "Geschwindigkeit:",
"js_verification_longer": "Die Prüfung benötigt länger als erwartet. Bitte bleibe auf der Seite und lade diese nicht neu.", "js_verification_longer": "Die Prüfung dauert länger als erwartet. Bitte warte und lade die Seite nicht neu.",
"js_success": "Erfolgreich!", "js_success": "Erfolgreich!",
"js_done_took": "Fertig! Dauer:", "js_done_took": "Fertig! Dauer:",
"js_iterations": "Iterationen", "js_iterations": "Iterationen",
"js_finished_reading": "Fertig gelesen, weiter zur Seite →", "js_finished_reading": "Fertig gelesen weiter zur Seite →",
"js_calculation_error": "Berechnung fehlgeschlagen!", "js_calculation_error": "Berechnungsfehler!",
"js_calculation_error_msg": "Fehler bei der Berechnung der Prüfung:", "js_calculation_error_msg": "Fehler bei der Berechnung der Prüfung:"
"missing_required_forwarded_headers": "Fehlende erforderliche X-Forwarded-* Header", }
"simplified_explanation": "Dies ist eine Maßnahme gegen Bots und bösartige Anfragen, ähnlich einem CAPTCHA. Anstatt jedoch selbst arbeiten zu müssen, erhält Ihr Browser eine Berechnungsaufgabe, die er lösen muss, um sicherzustellen, dass es sich um einen gültigen Client handelt. Dieses Konzept wird als <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Proof of Work</a> bezeichnet. Die Aufgabe wird in wenigen Sekunden berechnet und Sie erhalten Zugriff auf die Website. Vielen Dank für Ihr Verständnis und Ihre Geduld."
}

View File

@@ -15,6 +15,7 @@
"nb", "nb",
"nl", "nl",
"nn", "nn",
"pl",
"pt-BR", "pt-BR",
"ru", "ru",
"tr", "tr",

View File

@@ -0,0 +1,66 @@
{
"loading": "Ładowanie...",
"why_am_i_seeing": "Dlaczego to widzę?",
"protected_by": "Chronione przez",
"protected_from": "Przed",
"made_with": "Stworzone z ❤️ w 🇨🇦",
"mascot_design": "Projekt maskotki:",
"ai_companies_explanation": "Widzisz to, ponieważ administrator tej strony skonfigurował Anubisa, aby chronić serwer przed masowym skanowaniem treści przez firmy tworzące AI. Powoduje to obciążenie i przestoje, przez co zasoby strony stają się niedostępne dla wszystkich.",
"anubis_compromise": "Anubis jest kompromisem. Używa mechanizmu Proof-of-Work w stylu Hashcash — proponowanego systemu ograniczania spamu e-mail. Pomysł polega na tym, że dla indywidualnych użytkowników dodatkowe obciążenie jest niezauważalne, ale w skali masowego skanowania koszt szybko rośnie.",
"hack_purpose": "Docelowo jest to rozwiązanie tymczasowe, aby zyskać czas na ulepszenie metod identyfikacji przeglądarek bez interfejsu graficznego (np. poprzez analizę renderowania czcionek), by w przyszłości nie musieć wyświetlać strony z zadaniem Proof-of-Work użytkownikom, którzy najprawdopodobniej są prawidłowi.",
"simplified_explanation": "To zabezpieczenie przed botami i złośliwymi żądaniami, podobne do CAPTCHA. Jednak zamiast wykonywać zadanie samodzielnie, przeglądarka otrzymuje obliczenie do wykonania, aby potwierdzić, że jest prawidłowym klientem. Ten mechanizm to <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Proof of Work</a>. Zadanie trwa kilka sekund i uzyskujesz dostęp do strony. Dziękujemy za cierpliwość.",
"jshelter_note": "Uwaga: Anubis wymaga nowoczesnych funkcji JavaScript, które wtyczki typu JShelter mogą blokować. Wyłącz JShelter lub podobne dodatki dla tej domeny.",
"version_info": "Ta strona działa na Anubis w wersji",
"try_again": "Spróbuj ponownie",
"go_home": "Wróć na stronę główną",
"contact_webmaster": "lub jeśli uważasz, że nie powinieneś być blokowany, skontaktuj się z administratorem pod adresem",
"connection_security": "Poczekaj chwilę, sprawdzamy bezpieczeństwo Twojego połączenia.",
"javascript_required": "Niestety, aby przejść tę próbę, musisz włączyć obsługę JavaScript. Jest to konieczne, ponieważ firmy zajmujące się sztuczną inteligencją zmieniły umowę społeczną dotyczącą funkcjonowania hostingu stron internetowych. Rozwiązanie bez obsługi JavaScript jest w trakcie opracowywania.",
"benchmark_requires_js": "Uruchomienie narzędzia testowego wymaga włączonego JavaScript.",
"difficulty": "Trudność:",
"algorithm": "Algorytm:",
"compare": "Porównaj:",
"time": "Czas",
"iters": "Iteracje",
"time_a": "Czas A",
"iters_a": "Iteracje A",
"time_b": "Czas B",
"iters_b": "Iteracje B",
"static_check_endpoint": "To jedynie punkt kontrolny do użytku przez Twój reverse proxy.",
"authorization_required": "Wymagane uwierzytelnienie",
"cookies_disabled": "Twoja przeglądarka blokuje ciasteczka. Anubis wymaga ich, aby potwierdzić, że jesteś prawidłowym klientem. Włącz ciasteczka dla tej domeny.",
"access_denied": "Brak dostępu: kod błędu",
"dronebl_entry": "DroneBL zgłosił wpis",
"see_dronebl_lookup": "zobacz",
"internal_server_error": "Błąd wewnętrzny serwera: administrator błędnie skonfigurował Anubis. Skontaktuj się z administratorem i poproś o sprawdzenie logów",
"invalid_redirect": "Nieprawidłowe przekierowanie",
"redirect_not_parseable": "Nie można odczytać adresu przekierowania",
"redirect_domain_not_allowed": "Domena przekierowania niedozwolona",
"missing_required_forwarded_headers": "Brak wymaganych nagłówków X-Forwarded-*",
"failed_to_sign_jwt": "Nie udało się podpisać JWT",
"invalid_invocation": "Nieprawidłowe wywołanie MakeChallenge",
"client_error_browser": "Błąd klienta: upewnij się, że Twoja przeglądarka jest aktualna i spróbuj ponownie później.",
"oh_noes": "O nie!",
"benchmarking_anubis": "Testowanie wydajności Anubis!",
"you_are_not_a_bot": "Nie jesteś botem!",
"making_sure_not_bot": "Sprawdzamy, czy nie jesteś botem!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Twoja przeglądarka nie obsługuje web.crypto. Czy korzystasz z bezpiecznego połączenia?",
"js_web_workers_error": "Twoja przeglądarka nie obsługuje web workers (Anubis ich używa, by nie zawieszać przeglądarki). Czy masz zainstalowaną wtyczkę typu JShelter?",
"js_cookies_error": "Twoja przeglądarka nie zapisuje ciasteczek. Anubis używa ich do przechowywania podpisanego tokenu potwierdzającego przejście zabezpieczenia. Włącz zapis ciasteczek dla tej domeny. Nazwy ciasteczek mogą zmieniać się bez zapowiedzi. Nazwy oraz zawartość ciasteczek nie są cześcią publicznego API.",
"js_context_not_secure": "Kontekst nie jest bezpieczny!",
"js_context_not_secure_msg": "Spróbuj połączyć się przez HTTPS lub poinformuj administratora, by skonfigurował HTTPS. Więcej informacji na <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
"js_calculating": "Obliczanie...",
"js_missing_feature": "Brakująca funkcja",
"js_challenge_error": "Błąd wyzwania!",
"js_challenge_error_msg": "Nie udało się ustalić algorytmu sprawdzającego. Możesz spróbować odświeżyć stronę.",
"js_calculating_difficulty": "Obliczanie...<br/>Trudność:",
"js_speed": "Prędkość:",
"js_verification_longer": "Weryfikacja trwa dłużej niż zwykle. Proszę nie odświeżać strony.",
"js_success": "Sukces!",
"js_done_took": "Gotowe! Zajęło to",
"js_iterations": "iteracji",
"js_finished_reading": "Skończyłem czytać, kontynuuj →",
"js_calculation_error": "Błąd obliczeń!",
"js_calculation_error_msg": "Nie udało się obliczyć zadania:"
}

View File

@@ -81,7 +81,28 @@ func (ls *LocalizationService) GetLocalizerFromRequest(r *http.Request) *i18n.Lo
return i18n.NewLocalizer(bundle, "en") return i18n.NewLocalizer(bundle, "en")
} }
acceptLanguage := r.Header.Get("Accept-Language") acceptLanguage := r.Header.Get("Accept-Language")
return i18n.NewLocalizer(ls.bundle, acceptLanguage, "en")
// Parse Accept-Language header to properly handle quality factors
// The language.ParseAcceptLanguage function returns tags sorted by quality
tags, _, err := language.ParseAcceptLanguage(acceptLanguage)
if err != nil || len(tags) == 0 {
return i18n.NewLocalizer(ls.bundle, "en")
}
// Convert parsed tags to strings for the localizer
// We include both the full tag and base language to ensure proper matching
langs := make([]string, 0, len(tags)*2+1)
for _, tag := range tags {
langs = append(langs, tag.String())
// Also add base language (e.g., "en" for "en-GB") to help matching
base, _ := tag.Base()
if base.String() != tag.String() {
langs = append(langs, base.String())
}
}
langs = append(langs, "en") // Always include English as fallback
return i18n.NewLocalizer(ls.bundle, langs...)
} }
// SimpleLocalizer wraps i18n.Localizer with a more convenient API // SimpleLocalizer wraps i18n.Localizer with a more convenient API

View File

@@ -3,6 +3,7 @@ package localization
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http/httptest"
"sort" "sort"
"testing" "testing"
@@ -24,6 +25,7 @@ func TestLocalizationService(t *testing.T) {
"nb": "Laster inn...", "nb": "Laster inn...",
"nl": "Laden...", "nl": "Laden...",
"nn": "Lastar inn...", "nn": "Lastar inn...",
"pl": "Ładowanie...",
"pt-BR": "Carregando...", "pt-BR": "Carregando...",
"tr": "Yükleniyor...", "tr": "Yükleniyor...",
"ru": "Загрузка...", "ru": "Загрузка...",
@@ -137,3 +139,40 @@ func TestComprehensiveTranslations(t *testing.T) {
}) })
} }
} }
func TestAcceptLanguageQualityFactors(t *testing.T) {
service := NewLocalizationService()
testCases := []struct {
name string
acceptLanguage string
expectedLang string
}{
{"simple_en", "en", "en"},
{"simple_de", "de", "de"},
{"en_GB_with_lower_priority_de", "en-GB,de-DE;q=0.5", "en"},
{"en_GB_only", "en-GB", "en"},
{"de_with_lower_priority_en", "de,en;q=0.5", "de"},
{"de_DE_with_lower_priority_en", "de-DE,en;q=0.5", "de"},
{"fr_with_lower_priority_de", "fr,de;q=0.5", "fr"},
{"zh_CN_regional", "zh-CN", "zh-CN"},
{"zh_TW_regional", "zh-TW", "zh-TW"},
{"pt_BR_regional", "pt-BR", "pt-BR"},
{"complex_header", "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7,de;q=0.5", "fr"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Accept-Language", tc.acceptLanguage)
localizer := service.GetLocalizerFromRequest(req)
sl := &SimpleLocalizer{Localizer: localizer}
gotLang := sl.GetLang()
if gotLang != tc.expectedLang {
t.Errorf("Accept-Language %q: expected %s, got %s", tc.acceptLanguage, tc.expectedLang, gotLang)
}
})
}
}

228
package-lock.json generated
View File

@@ -1,21 +1,21 @@
{ {
"name": "@techaro/anubis", "name": "@techaro/anubis",
"version": "1.24.0-pre1", "version": "1.24.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@techaro/anubis", "name": "@techaro/anubis",
"version": "1.24.0-pre1", "version": "1.24.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/sha256-js": "^5.2.0",
"preact": "^10.28.0" "preact": "^10.28.1"
}, },
"devDependencies": { "devDependencies": {
"cssnano": "^7.1.2", "cssnano": "^7.1.2",
"cssnano-preset-advanced": "^7.0.10", "cssnano-preset-advanced": "^7.0.10",
"esbuild": "^0.27.1", "esbuild": "^0.27.2",
"playwright": "^1.52.0", "playwright": "^1.52.0",
"postcss-cli": "^11.0.1", "postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1", "postcss-import": "^16.1.1",
@@ -62,9 +62,9 @@
} }
}, },
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
"integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -79,9 +79,9 @@
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
"integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -96,9 +96,9 @@
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
"integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -113,9 +113,9 @@
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
"integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -130,9 +130,9 @@
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
"integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -147,9 +147,9 @@
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
"integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -164,9 +164,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
"integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -181,9 +181,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
"integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -198,9 +198,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
"integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -215,9 +215,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
"integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -232,9 +232,9 @@
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
"integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -249,9 +249,9 @@
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
"integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -266,9 +266,9 @@
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
"integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@@ -283,9 +283,9 @@
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
"integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -300,9 +300,9 @@
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
"integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -317,9 +317,9 @@
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
"integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -334,9 +334,9 @@
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
"integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -351,9 +351,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-arm64": { "node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
"integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -368,9 +368,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
"integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -385,9 +385,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-arm64": { "node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
"integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -402,9 +402,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
"integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -419,9 +419,9 @@
} }
}, },
"node_modules/@esbuild/openharmony-arm64": { "node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
"integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -436,9 +436,9 @@
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
"integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -453,9 +453,9 @@
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
"integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -470,9 +470,9 @@
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
"integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -487,9 +487,9 @@
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
"integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1156,9 +1156,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.27.1", "version": "0.27.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
"integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
@@ -1169,32 +1169,32 @@
"node": ">=18" "node": ">=18"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.1", "@esbuild/aix-ppc64": "0.27.2",
"@esbuild/android-arm": "0.27.1", "@esbuild/android-arm": "0.27.2",
"@esbuild/android-arm64": "0.27.1", "@esbuild/android-arm64": "0.27.2",
"@esbuild/android-x64": "0.27.1", "@esbuild/android-x64": "0.27.2",
"@esbuild/darwin-arm64": "0.27.1", "@esbuild/darwin-arm64": "0.27.2",
"@esbuild/darwin-x64": "0.27.1", "@esbuild/darwin-x64": "0.27.2",
"@esbuild/freebsd-arm64": "0.27.1", "@esbuild/freebsd-arm64": "0.27.2",
"@esbuild/freebsd-x64": "0.27.1", "@esbuild/freebsd-x64": "0.27.2",
"@esbuild/linux-arm": "0.27.1", "@esbuild/linux-arm": "0.27.2",
"@esbuild/linux-arm64": "0.27.1", "@esbuild/linux-arm64": "0.27.2",
"@esbuild/linux-ia32": "0.27.1", "@esbuild/linux-ia32": "0.27.2",
"@esbuild/linux-loong64": "0.27.1", "@esbuild/linux-loong64": "0.27.2",
"@esbuild/linux-mips64el": "0.27.1", "@esbuild/linux-mips64el": "0.27.2",
"@esbuild/linux-ppc64": "0.27.1", "@esbuild/linux-ppc64": "0.27.2",
"@esbuild/linux-riscv64": "0.27.1", "@esbuild/linux-riscv64": "0.27.2",
"@esbuild/linux-s390x": "0.27.1", "@esbuild/linux-s390x": "0.27.2",
"@esbuild/linux-x64": "0.27.1", "@esbuild/linux-x64": "0.27.2",
"@esbuild/netbsd-arm64": "0.27.1", "@esbuild/netbsd-arm64": "0.27.2",
"@esbuild/netbsd-x64": "0.27.1", "@esbuild/netbsd-x64": "0.27.2",
"@esbuild/openbsd-arm64": "0.27.1", "@esbuild/openbsd-arm64": "0.27.2",
"@esbuild/openbsd-x64": "0.27.1", "@esbuild/openbsd-x64": "0.27.2",
"@esbuild/openharmony-arm64": "0.27.1", "@esbuild/openharmony-arm64": "0.27.2",
"@esbuild/sunos-x64": "0.27.1", "@esbuild/sunos-x64": "0.27.2",
"@esbuild/win32-arm64": "0.27.1", "@esbuild/win32-arm64": "0.27.2",
"@esbuild/win32-ia32": "0.27.1", "@esbuild/win32-ia32": "0.27.2",
"@esbuild/win32-x64": "0.27.1" "@esbuild/win32-x64": "0.27.2"
} }
}, },
"node_modules/escalade": { "node_modules/escalade": {
@@ -2339,9 +2339,9 @@
} }
}, },
"node_modules/preact": { "node_modules/preact": {
"version": "10.28.0", "version": "10.28.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.28.0.tgz", "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.1.tgz",
"integrity": "sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==", "integrity": "sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@techaro/anubis", "name": "@techaro/anubis",
"version": "1.24.0-pre1", "version": "1.24.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@@ -20,7 +20,7 @@
"devDependencies": { "devDependencies": {
"cssnano": "^7.1.2", "cssnano": "^7.1.2",
"cssnano-preset-advanced": "^7.0.10", "cssnano-preset-advanced": "^7.0.10",
"esbuild": "^0.27.1", "esbuild": "^0.27.2",
"playwright": "^1.52.0", "playwright": "^1.52.0",
"postcss-cli": "^11.0.1", "postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1", "postcss-import": "^16.1.1",
@@ -29,6 +29,6 @@
}, },
"dependencies": { "dependencies": {
"@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/sha256-js": "^5.2.0",
"preact": "^10.28.0" "preact": "^10.28.1"
} }
} }

View File

@@ -14,7 +14,7 @@ services:
ports: ports:
- 3004:3004 - 3004:3004
volumes: volumes:
- ../pki/registry.local.cetacean.club:/etc/techaro/pki/registry.local.cetacean.club - ./pki/registry.local.cetacean.club:/etc/techaro/pki/registry.local.cetacean.club
anubis: anubis:
image: ko.local/anubis image: ko.local/anubis

View File

@@ -1,53 +1,56 @@
REPO_ROOT=$(git rev-parse --show-toplevel) REPO_ROOT=$(git rev-parse --show-toplevel)
(cd $REPO_ROOT && go install ./utils/cmd/...) (cd $REPO_ROOT && go install ./utils/cmd/...)
mkdir -p pki
echo '*' >>./pki/.gitignore
function cleanup() { function cleanup() {
set +e set +e
pkill -P $$ pkill -P $$
if [ -f "docker-compose.yaml" ]; then if [ -f "docker-compose.yaml" ]; then
docker compose down -t 1 || : docker compose down -t 1 || :
docker compose rm -f || : docker compose rm -f || :
fi fi
} }
trap cleanup EXIT SIGINT trap cleanup EXIT SIGINT
function build_anubis_ko() { function build_anubis_ko() {
( (
cd $REPO_ROOT && npm ci && npm run assets cd $REPO_ROOT && npm ci && npm run assets
) )
( (
cd $REPO_ROOT && cd $REPO_ROOT &&
VERSION=devel ko build \ VERSION=devel ko build \
--platform=all \ --platform=all \
--base-import-paths \ --base-import-paths \
--tags="latest" \ --tags="latest" \
--image-user=1000 \ --image-user=1000 \
--image-annotation="" \ --image-annotation="" \
--image-label="" \ --image-label="" \
./cmd/anubis \ ./cmd/anubis \
--local --local
) )
} }
function mint_cert() { function mint_cert() {
if [ "$#" -ne 1 ]; then if [ "$#" -ne 1 ]; then
echo "Usage: mint_cert <domain.name>" echo "Usage: mint_cert <domain.name>"
fi fi
domainName="$1" domainName="$1"
# If the transient local TLS certificate doesn't exist, mint a new one # If the transient local TLS certificate doesn't exist, mint a new one
if [ ! -f "${REPO_ROOT}/test/pki/${domainName}/cert.pem" ]; then if [ ! -f "./pki/${domainName}/cert.pem" ]; then
# Subshell to contain the directory change # Subshell to contain the directory change
( (
cd ${REPO_ROOT}/test/pki && cd ./pki &&
mkdir -p "${domainName}" && mkdir -p "${domainName}" &&
go tool minica -domains "${domainName}" && go tool minica -domains "${domainName}" &&
cd "${domainName}" && cd "${domainName}" &&
chmod 666 * chmod 666 *
) )
fi fi
} }

View File

@@ -0,0 +1,8 @@
# /etc/nginx/conf-anubis.inc
# Forward to anubis
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://anubis;
}

View File

@@ -0,0 +1,29 @@
# /etc/nginx/conf.d/server-mimi-techaro-lol.conf
server {
# Listen on 443 with SSL
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
# Slipstream via Anubis
include "conf-anubis.inc";
server_name mimi.techaro.lol;
ssl_certificate /techaro/pki/mimi.techaro.lol/cert.pem;
ssl_certificate_key /techaro/pki/mimi.techaro.lol/key.pem;
}
server {
listen unix:/tmp/nginx.sock;
server_name mimi.techaro.lol;
port_in_redirect off;
root "/srv/http/mimi.techaro.lol";
index index.html;
# Your normal configuration can go here
# location .php { fastcgi...} etc.
}

View File

@@ -0,0 +1,17 @@
# /etc/nginx/conf.d/upstream-anubis.conf
upstream anubis {
zone anubis_zone 64k;
# Make sure this matches the values you set for `BIND` and `BIND_NETWORK`.
# If this does not match, your services will not be protected by Anubis.
# Try anubis first over a UNIX socket
#server unix:/run/anubis/nginx.sock;
server anubis:3000 resolve;
# Optional: fall back to serving the websites directly. This allows your
# websites to be resilient against Anubis failing, at the risk of exposing
# them to the raw internet without protection. This is a tradeoff and can
# be worth it in some edge cases.
#server unix:/run/nginx.sock backup;
}

View File

@@ -0,0 +1,99 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/avif avif;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/wasm wasm;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@@ -0,0 +1,32 @@
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
resolver 169.254.42.1 valid=300s ipv6=on;
resolver_timeout 10s;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

17
test/nginx/test.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
source ../lib/lib.sh
export KO_DOCKER_REPO=ko.local
set -euo pipefail
mint_cert mimi.techaro.lol
docker run --rm \
-v $PWD/conf/nginx:/etc/nginx:ro \
-v $PWD/pki:/techaro/pki:ro \
nginx \
nginx -t
exit 0

View File

@@ -26,7 +26,7 @@ services:
KEY_FNAME: key.pem KEY_FNAME: key.pem
PROXY_TO: http://anubis:3000 PROXY_TO: http://anubis:3000
volumes: volumes:
- ../../pki/relayd:/techaro/pki:ro - ./pki/relayd:/techaro/pki:ro
# novnc: # novnc:
# image: geek1011/easy-novnc # image: geek1011/easy-novnc
@@ -42,7 +42,7 @@ services:
environment: environment:
DISPLAY: display:0 DISPLAY: display:0
volumes: volumes:
- ../../pki:/usr/local/share/ca-certificates/minica:ro - ./pki:/usr/local/share/ca-certificates/minica:ro
- ../scripts:/hack/scripts:ro - ../scripts:/hack/scripts:ro
depends_on: depends_on:
- anubis - anubis

View File

@@ -24,7 +24,7 @@ services:
KEY_FNAME: key.pem KEY_FNAME: key.pem
PROXY_TO: http://anubis:3000 PROXY_TO: http://anubis:3000
volumes: volumes:
- ../../pki/relayd:/techaro/pki:ro - ./pki/relayd:/techaro/pki:ro
# novnc: # novnc:
# image: geek1011/easy-novnc # image: geek1011/easy-novnc
@@ -40,5 +40,5 @@ services:
environment: environment:
DISPLAY: display:0 DISPLAY: display:0
volumes: volumes:
- ../../pki:/usr/local/share/ca-certificates/minica:ro - ./pki:/usr/local/share/ca-certificates/minica:ro
- ../scripts:/hack/scripts:ro - ../scripts:/hack/scripts:ro

View File

@@ -0,0 +1,57 @@
package main
import (
"bufio"
"fmt"
"io"
"net/http"
"net/netip"
"strings"
)
// FetchBlocklist reads the blocklist over HTTP and returns every non-commented
// line parsed as an IP address in CIDR notation. IPv4 addresses are returned as
// /32, IPv6 addresses as /128.
//
// This function was generated with GLM 4.7.
func FetchBlocklist(url string) ([]string, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP request failed with status: %s", resp.Status)
}
var lines []string
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
// Skip empty lines and comments (lines starting with #)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
addr, err := netip.ParseAddr(line)
if err != nil {
// Skip lines that aren't valid IP addresses
continue
}
var cidr string
if addr.Is4() {
cidr = fmt.Sprintf("%s/32", addr.String())
} else {
cidr = fmt.Sprintf("%s/128", addr.String())
}
lines = append(lines, cidr)
}
if err := scanner.Err(); err != nil && err != io.EOF {
return nil, err
}
return lines, nil
}

View File

@@ -0,0 +1,103 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/facebookgo/flagenv"
"sigs.k8s.io/yaml"
)
type Rule struct {
Name string `yaml:"name" json:"name"`
Action config.Rule `yaml:"action" json:"action"`
RemoteAddr []string `json:"remote_addresses,omitempty" yaml:"remote_addresses,omitempty"`
Weight *config.Weight `json:"weight,omitempty" yaml:"weight,omitempty"`
}
func init() {
flag.Usage = func() {
fmt.Printf(`Usage of %[1]s:
%[1]s [flags] <blocklist-url> <filename>
Grabs the contents of the blocklist, converts it to an Anubis ruleset, and writes it to filename.
Flags:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
var (
action = flag.String("action", "DENY", "Anubis action to take (ALLOW / DENY / WEIGH)")
manualRuleName = flag.String("rule-name", "", "If set, prefer this name over inferring from filename")
weight = flag.Int("weight", 0, "If set to any number, add/subtract this many weight points when --action=WEIGH")
)
func main() {
flagenv.Parse()
flag.Parse()
if flag.NArg() != 2 {
flag.Usage()
os.Exit(2)
}
blocklistURL := flag.Arg(0)
foutName := flag.Arg(1)
ruleName := strings.TrimSuffix(foutName, filepath.Ext(foutName))
if *manualRuleName != "" {
ruleName = *manualRuleName
}
ruleAction := config.Rule(*action)
if err := ruleAction.Valid(); err != nil {
log.Fatalf("--action=%q is invalid: %v", *action, err)
}
result := &Rule{
Name: ruleName,
Action: ruleAction,
}
if *weight != 0 {
if ruleAction != config.RuleWeigh {
log.Fatalf("used --weight=%d but --action=%s", *weight, *action)
}
result.Weight = &config.Weight{
Adjust: *weight,
}
}
ips, err := FetchBlocklist(blocklistURL)
if err != nil {
log.Fatalf("can't fetch blocklist %s: %v", blocklistURL, err)
}
result.RemoteAddr = ips
fout, err := os.Create(foutName)
if err != nil {
log.Fatalf("can't create output file %q: %v", foutName, err)
}
defer fout.Close()
fmt.Fprintf(fout, "# Generated by %s on %s from %s\n\n", filepath.Base(os.Args[0]), time.Now().Format(time.RFC3339), blocklistURL)
data, err := yaml.Marshal([]*Rule{result})
if err != nil {
log.Fatalf("can't marshal yaml")
}
fout.Write(data)
}

View File

@@ -64,7 +64,7 @@ templ base(title string, body templ.Component, impressum *config.Impressum, chal
@templ.JSONScript("anubis_public_url", anubis.PublicUrl) @templ.JSONScript("anubis_public_url", anubis.PublicUrl)
</head> </head>
<body id="top"> <body id="top">
@honeypotLink(fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())) @honeypotLink(anubis.BasePrefix + fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString()))
<main> <main>
<h1 id="title" class="centered-div">{ title }</h1> <h1 id="title" class="centered-div">{ title }</h1>
@body @body
@@ -79,7 +79,7 @@ templ base(title string, body templ.Component, impressum *config.Impressum, chal
if impressum != nil { if impressum != nil {
<p> <p>
@templ.Raw(impressum.Footer) @templ.Raw(impressum.Footer)
-- <a href={ templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a> -- <a href={ templ.SafeURL(anubis.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a>
</p> </p>
} }
<p>{ localizer.T("version_info") } <code>{ anubis.Version }</code>.</p> <p>{ localizer.T("version_info") } <code>{ anubis.Version }</code>.</p>

6
web/index_templ.go generated
View File

@@ -137,7 +137,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = honeypotLink(fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())).Render(ctx, templ_7745c5c3_Buffer) templ_7745c5c3_Err = honeypotLink(anubis.BasePrefix+fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -245,9 +245,9 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var13 templ.SafeURL var templ_7745c5c3_Var13 templ.SafeURL
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix))) templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(anubis.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 82, Col: 78} return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 82, Col: 98}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

81
web/index_test.go Normal file
View File

@@ -0,0 +1,81 @@
package web
import (
"context"
"net/http/httptest"
"strings"
"testing"
"github.com/TecharoHQ/anubis"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/localization"
"github.com/a-h/templ"
)
func TestBasePrefixInLinks(t *testing.T) {
tests := []struct {
name string
basePrefix string
wantInLink string
}{
{
name: "no prefix",
basePrefix: "",
wantInLink: "/.within.website/x/cmd/anubis/api/",
},
{
name: "with rififi prefix",
basePrefix: "/rififi",
wantInLink: "/rififi/.within.website/x/cmd/anubis/api/",
},
{
name: "with myapp prefix",
basePrefix: "/myapp",
wantInLink: "/myapp/.within.website/x/cmd/anubis/api/",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save original BasePrefix and restore after test
origPrefix := anubis.BasePrefix
defer func() { anubis.BasePrefix = origPrefix }()
anubis.BasePrefix = tt.basePrefix
// Create test impressum
impressum := &config.Impressum{
Footer: "<p>Test footer</p>",
Page: config.ImpressumPage{
Title: "Test Imprint",
Body: "<p>Test imprint body</p>",
},
}
// Create localizer using a dummy request
req := httptest.NewRequest("GET", "/", nil)
localizer := &localization.SimpleLocalizer{}
localizer.Localizer = localization.NewLocalizationService().GetLocalizerFromRequest(req)
// Render the base template to a buffer
var buf strings.Builder
component := base(tt.name, templ.NopComponent, impressum, nil, nil, localizer)
err := component.Render(context.Background(), &buf)
if err != nil {
t.Fatalf("failed to render template: %v", err)
}
output := buf.String()
// Check that honeypot link includes the base prefix
if !strings.Contains(output, `href="`+tt.wantInLink+`honeypot/`) {
t.Errorf("honeypot link does not contain base prefix %q\noutput: %s", tt.wantInLink, output)
}
// Check that imprint link includes the base prefix
if !strings.Contains(output, `href="`+tt.wantInLink+`imprint`) {
t.Errorf("imprint link does not contain base prefix %q\noutput: %s", tt.wantInLink, output)
}
})
}
}