mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-14 04:28:49 +00:00
Compare commits
13 Commits
Xe/logrota
...
v1.24.0-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c54aa852f | ||
|
|
cb689ee55b | ||
|
|
071b836741 | ||
|
|
bbdeee00f7 | ||
|
|
21d7753b1c | ||
|
|
43b8658bfd | ||
|
|
00fa939acf | ||
|
|
4ead3ed16e | ||
|
|
1f9c2272e6 | ||
|
|
b11d8132dd | ||
|
|
f032d5d0ac | ||
|
|
a709a2b2da | ||
|
|
18d2b4ffff |
2
.github/actions/spelling/allow.txt
vendored
2
.github/actions/spelling/allow.txt
vendored
@@ -10,3 +10,5 @@ ABee
|
|||||||
tencent
|
tencent
|
||||||
maintnotifications
|
maintnotifications
|
||||||
azurediamond
|
azurediamond
|
||||||
|
cooldown
|
||||||
|
verifyfcrdns
|
||||||
|
|||||||
791
.github/actions/spelling/expect.txt
vendored
791
.github/actions/spelling/expect.txt
vendored
@@ -1,391 +1,400 @@
|
|||||||
acs
|
|
||||||
Actorified
|
acs
|
||||||
actorifiedstore
|
Actorified
|
||||||
actorify
|
actorifiedstore
|
||||||
Aibrew
|
actorify
|
||||||
alibaba
|
Aibrew
|
||||||
alrest
|
alibaba
|
||||||
amazonbot
|
alrest
|
||||||
anthro
|
amazonbot
|
||||||
anubis
|
anthro
|
||||||
anubistest
|
anubis
|
||||||
apnic
|
anubistest
|
||||||
APNICRANDNETAU
|
apnic
|
||||||
Applebot
|
APNICRANDNETAU
|
||||||
archlinux
|
Applebot
|
||||||
asnc
|
archlinux
|
||||||
asnchecker
|
arpa
|
||||||
asns
|
asnc
|
||||||
aspirational
|
asnchecker
|
||||||
atuin
|
asns
|
||||||
azuretools
|
aspirational
|
||||||
badregexes
|
atuin
|
||||||
bbolt
|
azuretools
|
||||||
bdba
|
badregexes
|
||||||
berr
|
bbolt
|
||||||
bezier
|
bdba
|
||||||
bingbot
|
berr
|
||||||
Bitcoin
|
bezier
|
||||||
bitrate
|
bingbot
|
||||||
Bluesky
|
Bitcoin
|
||||||
blueskybot
|
bitrate
|
||||||
boi
|
Bluesky
|
||||||
Bokm
|
blueskybot
|
||||||
botnet
|
boi
|
||||||
botstopper
|
Bokm
|
||||||
BPort
|
botnet
|
||||||
Brightbot
|
botstopper
|
||||||
broked
|
BPort
|
||||||
buildah
|
Brightbot
|
||||||
byteslice
|
broked
|
||||||
Bytespider
|
buildah
|
||||||
cachebuster
|
byteslice
|
||||||
cachediptoasn
|
Bytespider
|
||||||
Caddyfile
|
cachebuster
|
||||||
caninetools
|
cachediptoasn
|
||||||
Cardyb
|
Caddyfile
|
||||||
celchecker
|
caninetools
|
||||||
celphase
|
Cardyb
|
||||||
cerr
|
celchecker
|
||||||
certresolver
|
celphase
|
||||||
cespare
|
cerr
|
||||||
CGNAT
|
certresolver
|
||||||
cgr
|
cespare
|
||||||
chainguard
|
CGNAT
|
||||||
chall
|
cgr
|
||||||
challengemozilla
|
chainguard
|
||||||
challengetest
|
chall
|
||||||
checkpath
|
challengemozilla
|
||||||
checkresult
|
challengetest
|
||||||
chibi
|
checkpath
|
||||||
cidranger
|
checkresult
|
||||||
ckie
|
chibi
|
||||||
cloudflare
|
cidranger
|
||||||
Codespaces
|
ckie
|
||||||
confd
|
cloudflare
|
||||||
connnection
|
Codespaces
|
||||||
containerbuild
|
confd
|
||||||
containerregistry
|
connnection
|
||||||
coreutils
|
containerbuild
|
||||||
Cotoyogi
|
containerregistry
|
||||||
Cromite
|
coreutils
|
||||||
crt
|
Cotoyogi
|
||||||
Cscript
|
Cromite
|
||||||
daemonizing
|
crt
|
||||||
dayjob
|
Cscript
|
||||||
DDOS
|
daemonizing
|
||||||
Debian
|
dayjob
|
||||||
debrpm
|
DDOS
|
||||||
decaymap
|
Debian
|
||||||
devcontainers
|
debrpm
|
||||||
Diffbot
|
decaymap
|
||||||
discordapp
|
devcontainers
|
||||||
discordbot
|
Diffbot
|
||||||
distros
|
discordapp
|
||||||
dnf
|
discordbot
|
||||||
dnsbl
|
distros
|
||||||
dnserr
|
dnf
|
||||||
domainhere
|
dnsbl
|
||||||
dracula
|
dnserr
|
||||||
dronebl
|
DNSTTL
|
||||||
droneblresponse
|
domainhere
|
||||||
dropin
|
dracula
|
||||||
dsilence
|
dronebl
|
||||||
duckduckbot
|
droneblresponse
|
||||||
eerror
|
dropin
|
||||||
ellenjoe
|
dsilence
|
||||||
emacs
|
duckduckbot
|
||||||
enbyware
|
eerror
|
||||||
etld
|
ellenjoe
|
||||||
everyones
|
emacs
|
||||||
evilbot
|
enbyware
|
||||||
evilsite
|
etld
|
||||||
expressionorlist
|
everyones
|
||||||
externalagent
|
evilbot
|
||||||
externalfetcher
|
evilsite
|
||||||
extldflags
|
expressionorlist
|
||||||
facebookgo
|
externalagent
|
||||||
Factset
|
externalfetcher
|
||||||
fahedouch
|
extldflags
|
||||||
fastcgi
|
facebookgo
|
||||||
fediverse
|
Factset
|
||||||
ffprobe
|
fahedouch
|
||||||
financials
|
fastcgi
|
||||||
finfos
|
FCr
|
||||||
Firecrawl
|
fcrdns
|
||||||
flagenv
|
fediverse
|
||||||
Fordola
|
ffprobe
|
||||||
forgejo
|
financials
|
||||||
forwardauth
|
finfos
|
||||||
fsys
|
Firecrawl
|
||||||
fullchain
|
flagenv
|
||||||
gaissmai
|
Fordola
|
||||||
Galvus
|
forgejo
|
||||||
geoip
|
forwardauth
|
||||||
geoipchecker
|
fsys
|
||||||
gha
|
fullchain
|
||||||
GHSA
|
gaissmai
|
||||||
Ghz
|
Galvus
|
||||||
gipc
|
geoip
|
||||||
gitea
|
geoipchecker
|
||||||
godotenv
|
gha
|
||||||
goland
|
GHSA
|
||||||
gomod
|
Ghz
|
||||||
goodbot
|
gipc
|
||||||
googlebot
|
gitea
|
||||||
gopsutil
|
godotenv
|
||||||
govulncheck
|
goland
|
||||||
goyaml
|
gomod
|
||||||
GPG
|
goodbot
|
||||||
GPT
|
googlebot
|
||||||
gptbot
|
gopsutil
|
||||||
Graphene
|
govulncheck
|
||||||
grpcprom
|
goyaml
|
||||||
grw
|
GPG
|
||||||
gzw
|
GPT
|
||||||
Hashcash
|
gptbot
|
||||||
hashrate
|
Graphene
|
||||||
headermap
|
grpcprom
|
||||||
healthcheck
|
grw
|
||||||
healthz
|
gzw
|
||||||
hec
|
Hashcash
|
||||||
helpdesk
|
hashrate
|
||||||
Hetzner
|
headermap
|
||||||
hmc
|
healthcheck
|
||||||
homelab
|
healthz
|
||||||
hostable
|
hec
|
||||||
htmlc
|
helpdesk
|
||||||
htmx
|
Hetzner
|
||||||
httpdebug
|
hmc
|
||||||
Huawei
|
homelab
|
||||||
huawei
|
hostable
|
||||||
hypertext
|
htmlc
|
||||||
iaskspider
|
htmx
|
||||||
iaso
|
httpdebug
|
||||||
iat
|
huawei
|
||||||
ifm
|
hypertext
|
||||||
Imagesift
|
iaskspider
|
||||||
imgproxy
|
iaso
|
||||||
impressum
|
iat
|
||||||
inbox
|
ifm
|
||||||
ingressed
|
Imagesift
|
||||||
inp
|
imgproxy
|
||||||
internets
|
impressum
|
||||||
IPTo
|
inbox
|
||||||
iptoasn
|
ingressed
|
||||||
isp
|
inp
|
||||||
iss
|
internets
|
||||||
isset
|
IPTo
|
||||||
ivh
|
iptoasn
|
||||||
Jenomis
|
isp
|
||||||
JGit
|
iss
|
||||||
jhjj
|
isset
|
||||||
joho
|
ivh
|
||||||
journalctl
|
Jenomis
|
||||||
jshelter
|
JGit
|
||||||
JWTs
|
jhjj
|
||||||
kagi
|
joho
|
||||||
kagibot
|
journalctl
|
||||||
Keyfunc
|
jshelter
|
||||||
keypair
|
JWTs
|
||||||
KHTML
|
kagi
|
||||||
kinda
|
kagibot
|
||||||
KUBECONFIG
|
Keyfunc
|
||||||
lcj
|
keypair
|
||||||
ldflags
|
KHTML
|
||||||
letsencrypt
|
kinda
|
||||||
Lexentale
|
KUBECONFIG
|
||||||
lfc
|
lcj
|
||||||
lgbt
|
ldflags
|
||||||
licend
|
letsencrypt
|
||||||
licstart
|
Lexentale
|
||||||
lightpanda
|
lfc
|
||||||
limsa
|
lgbt
|
||||||
Linting
|
licend
|
||||||
listor
|
licstart
|
||||||
LLU
|
lightpanda
|
||||||
loadbalancer
|
limsa
|
||||||
lol
|
Linting
|
||||||
lominsa
|
listor
|
||||||
maintainership
|
LLU
|
||||||
malware
|
loadbalancer
|
||||||
mcr
|
lol
|
||||||
memes
|
lominsa
|
||||||
metarefresh
|
maintainership
|
||||||
metrix
|
malware
|
||||||
mimi
|
mcr
|
||||||
Minfilia
|
memes
|
||||||
mistralai
|
metarefresh
|
||||||
mnt
|
metrix
|
||||||
Mojeek
|
mimi
|
||||||
mojeekbot
|
Minfilia
|
||||||
mozilla
|
mistralai
|
||||||
myclient
|
mnt
|
||||||
mymaster
|
Mojeek
|
||||||
mypass
|
mojeekbot
|
||||||
myuser
|
mozilla
|
||||||
nbf
|
myclient
|
||||||
nepeat
|
mymaster
|
||||||
netsurf
|
mypass
|
||||||
nginx
|
myuser
|
||||||
nicksnyder
|
nbf
|
||||||
nobots
|
nepeat
|
||||||
NONINFRINGEMENT
|
netsurf
|
||||||
nosleep
|
nginx
|
||||||
nullglob
|
nicksnyder
|
||||||
oci
|
nobots
|
||||||
OCOB
|
NONINFRINGEMENT
|
||||||
ogtag
|
nosleep
|
||||||
oklch
|
nullglob
|
||||||
omgili
|
oci
|
||||||
omgilibot
|
OCOB
|
||||||
openai
|
ogtag
|
||||||
opengraph
|
oklch
|
||||||
openrc
|
omgili
|
||||||
oswald
|
omgilibot
|
||||||
pag
|
openai
|
||||||
palemoon
|
opendns
|
||||||
Pangu
|
opengraph
|
||||||
parseable
|
openrc
|
||||||
passthrough
|
oswald
|
||||||
Patreon
|
pag
|
||||||
pgrep
|
palemoon
|
||||||
phrik
|
Pangu
|
||||||
pidfile
|
parseable
|
||||||
pids
|
passthrough
|
||||||
pipefail
|
Patreon
|
||||||
pki
|
pgrep
|
||||||
podkova
|
phrik
|
||||||
podman
|
pidfile
|
||||||
Postgre
|
pids
|
||||||
poststart
|
pipefail
|
||||||
prebaked
|
pki
|
||||||
privkey
|
podkova
|
||||||
promauto
|
podman
|
||||||
promhttp
|
Postgre
|
||||||
proofofwork
|
poststart
|
||||||
publicsuffix
|
prebaked
|
||||||
purejs
|
privkey
|
||||||
pwcmd
|
promauto
|
||||||
pwuser
|
promhttp
|
||||||
qualys
|
proofofwork
|
||||||
qwant
|
publicsuffix
|
||||||
qwantbot
|
purejs
|
||||||
rac
|
pwcmd
|
||||||
rawler
|
pwuser
|
||||||
rcvar
|
qualys
|
||||||
redhat
|
qwant
|
||||||
redir
|
qwantbot
|
||||||
redirectscheme
|
rac
|
||||||
refactors
|
rawler
|
||||||
reputational
|
rcvar
|
||||||
risc
|
redhat
|
||||||
ruleset
|
redir
|
||||||
runlevels
|
redirectscheme
|
||||||
RUnlock
|
refactors
|
||||||
runtimedir
|
remoteip
|
||||||
runtimedirectory
|
reputational
|
||||||
Ryzen
|
risc
|
||||||
sas
|
ruleset
|
||||||
sasl
|
runlevels
|
||||||
screenshots
|
RUnlock
|
||||||
searchbot
|
runtimedir
|
||||||
searx
|
runtimedirectory
|
||||||
sebest
|
Ryzen
|
||||||
secretplans
|
sas
|
||||||
Semrush
|
sasl
|
||||||
Seo
|
screenshots
|
||||||
setsebool
|
searchbot
|
||||||
shellcheck
|
searx
|
||||||
shirou
|
sebest
|
||||||
shopt
|
secretplans
|
||||||
Sidetrade
|
Semrush
|
||||||
simprint
|
Seo
|
||||||
sitemap
|
setsebool
|
||||||
sls
|
shellcheck
|
||||||
sni
|
shirou
|
||||||
Spambot
|
shopt
|
||||||
sparkline
|
Sidetrade
|
||||||
spyderbot
|
simprint
|
||||||
srv
|
sitemap
|
||||||
stackoverflow
|
sls
|
||||||
startprecmd
|
sni
|
||||||
stoppostcmd
|
snipster
|
||||||
storetest
|
Spambot
|
||||||
subgrid
|
sparkline
|
||||||
subr
|
spyderbot
|
||||||
subrequest
|
srv
|
||||||
SVCNAME
|
stackoverflow
|
||||||
tagline
|
startprecmd
|
||||||
tarballs
|
stoppostcmd
|
||||||
tarrif
|
storetest
|
||||||
taviso
|
subgrid
|
||||||
tbn
|
subr
|
||||||
tbr
|
subrequest
|
||||||
techaro
|
SVCNAME
|
||||||
techarohq
|
tagline
|
||||||
templ
|
tarballs
|
||||||
templruntime
|
tarrif
|
||||||
testarea
|
taviso
|
||||||
Thancred
|
tbn
|
||||||
thoth
|
tbr
|
||||||
thothmock
|
techaro
|
||||||
Tik
|
techarohq
|
||||||
Timpibot
|
telegrambot
|
||||||
TLog
|
templ
|
||||||
traefik
|
templruntime
|
||||||
trunc
|
testarea
|
||||||
uberspace
|
Thancred
|
||||||
Unbreak
|
thoth
|
||||||
unbreakdocker
|
thothmock
|
||||||
unifiedjs
|
Tik
|
||||||
unmarshal
|
Timpibot
|
||||||
unparseable
|
TLog
|
||||||
uvx
|
traefik
|
||||||
UXP
|
trunc
|
||||||
valkey
|
uberspace
|
||||||
Varis
|
Unbreak
|
||||||
Velen
|
unbreakdocker
|
||||||
vendored
|
unifiedjs
|
||||||
vhosts
|
unmarshal
|
||||||
VKE
|
unparseable
|
||||||
vnd
|
uvx
|
||||||
VPS
|
UXP
|
||||||
Vultr
|
valkey
|
||||||
weblate
|
Varis
|
||||||
webmaster
|
Velen
|
||||||
webpage
|
vendored
|
||||||
websecure
|
verify
|
||||||
websites
|
vhosts
|
||||||
Webzio
|
vkbot
|
||||||
whois
|
VKE
|
||||||
wildbase
|
vnd
|
||||||
withthothmock
|
VPS
|
||||||
wolfbeast
|
Vultr
|
||||||
wordpress
|
weblate
|
||||||
Workaround
|
webmaster
|
||||||
workaround
|
webpage
|
||||||
workdir
|
websecure
|
||||||
wpbot
|
websites
|
||||||
XCircle
|
Webzio
|
||||||
xeiaso
|
whois
|
||||||
xeserv
|
wildbase
|
||||||
xesite
|
withthothmock
|
||||||
xess
|
wolfbeast
|
||||||
xff
|
wordpress
|
||||||
XForwarded
|
workaround
|
||||||
XNG
|
workdir
|
||||||
XOB
|
wpbot
|
||||||
XOriginal
|
XCircle
|
||||||
XReal
|
xeiaso
|
||||||
yae
|
xeserv
|
||||||
YAMLTo
|
xesite
|
||||||
Yda
|
xess
|
||||||
yeet
|
xff
|
||||||
yeetfile
|
XForwarded
|
||||||
yourdomain
|
XNG
|
||||||
yyz
|
XOB
|
||||||
Zenos
|
XOriginal
|
||||||
zizmor
|
XReal
|
||||||
zombocom
|
yae
|
||||||
zos
|
YAMLTo
|
||||||
|
Yda
|
||||||
|
yeet
|
||||||
|
yeetfile
|
||||||
|
yourdomain
|
||||||
|
yyz
|
||||||
|
Zenos
|
||||||
|
zizmor
|
||||||
|
zombocom
|
||||||
|
zos
|
||||||
|
|||||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -8,6 +8,8 @@ updates:
|
|||||||
github-actions:
|
github-actions:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
|
||||||
- package-ecosystem: gomod
|
- package-ecosystem: gomod
|
||||||
directory: /
|
directory: /
|
||||||
@@ -17,6 +19,8 @@ updates:
|
|||||||
gomod:
|
gomod:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: /
|
directory: /
|
||||||
@@ -26,3 +30,5 @@ updates:
|
|||||||
npm:
|
npm:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
|||||||
9
.github/workflows/asset-verification.yml
vendored
9
.github/workflows/asset-verification.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
asset_verification:
|
asset_verification:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -24,11 +24,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- name: install node deps
|
- name: install node deps
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
9
.github/workflows/docker-pr.yml
vendored
9
.github/workflows/docker-pr.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -28,11 +28,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
||||||
|
|
||||||
|
|||||||
9
.github/workflows/docker.yml
vendored
9
.github/workflows/docker.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -38,11 +38,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/docs-deploy.yml
vendored
6
.github/workflows/docs-deploy.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -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@f14933a23bc8c582b5aa7d108defd8e2cb9fa86d # v1.34.1
|
uses: actions-hub/kubectl@1d2c1e96fe0ae23b0c95ee8240ae151b1e638c23 # v1.34.2
|
||||||
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@f14933a23bc8c582b5aa7d108defd8e2cb9fa86d # v1.34.1
|
uses: actions-hub/kubectl@1d2c1e96fe0ae23b0c95ee8240ae151b1e638c23 # v1.34.2
|
||||||
env:
|
env:
|
||||||
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
|
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/docs-test.yml
vendored
2
.github/workflows/docs-test.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
76
.github/workflows/go-mod-tidy-check.yml
vendored
Normal file
76
.github/workflows/go-mod-tidy-check.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
name: Go Mod Tidy Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
go_mod_tidy_check:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
|
with:
|
||||||
|
go-version: '1.25.4'
|
||||||
|
|
||||||
|
- name: Check go.mod and go.sum in main directory
|
||||||
|
run: |
|
||||||
|
# Store original file state
|
||||||
|
cp go.mod go.mod.orig
|
||||||
|
cp go.sum go.sum.orig
|
||||||
|
|
||||||
|
# Run go mod tidy
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
# Check if files changed
|
||||||
|
if ! diff -q go.mod.orig go.mod > /dev/null 2>&1; then
|
||||||
|
echo "ERROR: go.mod in main directory has changed after running 'go mod tidy'"
|
||||||
|
echo "Please run 'go mod tidy' locally and commit the changes"
|
||||||
|
diff go.mod.orig go.mod
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! diff -q go.sum.orig go.sum > /dev/null 2>&1; then
|
||||||
|
echo "ERROR: go.sum in main directory has changed after running 'go mod tidy'"
|
||||||
|
echo "Please run 'go mod tidy' locally and commit the changes"
|
||||||
|
diff go.sum.orig go.sum
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "SUCCESS: go.mod and go.sum in main directory are tidy"
|
||||||
|
|
||||||
|
- name: Check go.mod and go.sum in test directory
|
||||||
|
run: |
|
||||||
|
cd test
|
||||||
|
|
||||||
|
# Store original file state
|
||||||
|
cp go.mod go.mod.orig
|
||||||
|
cp go.sum go.sum.orig
|
||||||
|
|
||||||
|
# Run go mod tidy
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
# Check if files changed
|
||||||
|
if ! diff -q go.mod.orig go.mod > /dev/null 2>&1; then
|
||||||
|
echo "ERROR: go.mod in test directory has changed after running 'go mod tidy'"
|
||||||
|
echo "Please run 'go mod tidy' locally and commit the changes"
|
||||||
|
diff go.mod.orig go.mod
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! diff -q go.sum.orig go.sum > /dev/null 2>&1; then
|
||||||
|
echo "ERROR: go.sum in test directory has changed after running 'go mod tidy'"
|
||||||
|
echo "Please run 'go mod tidy' locally and commit the changes"
|
||||||
|
diff go.sum.orig go.sum
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "SUCCESS: go.mod and go.sum in test directory are tidy"
|
||||||
9
.github/workflows/go.yml
vendored
9
.github/workflows/go.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
#runs-on: alrest-techarohq
|
#runs-on: alrest-techarohq
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -26,11 +26,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- name: Cache playwright binaries
|
- name: Cache playwright binaries
|
||||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||||
|
|||||||
9
.github/workflows/package-builds-stable.yml
vendored
9
.github/workflows/package-builds-stable.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
#runs-on: alrest-techarohq
|
#runs-on: alrest-techarohq
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
@@ -27,11 +27,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- name: install node deps
|
- name: install node deps
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
#runs-on: alrest-techarohq
|
#runs-on: alrest-techarohq
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
@@ -28,11 +28,10 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- name: install node deps
|
- name: install node deps
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
9
.github/workflows/smoke-tests.yml
vendored
9
.github/workflows/smoke-tests.yml
vendored
@@ -29,17 +29,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
node-version: latest
|
node-version: '24.11.0'
|
||||||
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/ssh-ci-runner-cron.yml
vendored
2
.github/workflows/ssh-ci-runner-cron.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|||||||
6
.github/workflows/ssh-ci.yml
vendored
6
.github/workflows/ssh-ci.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- aarch64-16k
|
- aarch64-16k
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -35,9 +35,9 @@ jobs:
|
|||||||
name: id_rsa
|
name: id_rsa
|
||||||
known_hosts: ${{ secrets.CI_SSH_KNOWN_HOSTS }}
|
known_hosts: ${{ secrets.CI_SSH_KNOWN_HOSTS }}
|
||||||
|
|
||||||
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||||
with:
|
with:
|
||||||
go-version: stable
|
go-version: '1.25.4'
|
||||||
|
|
||||||
- name: Run CI
|
- name: Run CI
|
||||||
run: go run ./utils/cmd/backoff-retry bash test/ssh-ci/rigging.sh ${{ matrix.host }}
|
run: go run ./utils/cmd/backoff-retry bash test/ssh-ci/rigging.sh ${{ matrix.host }}
|
||||||
|
|||||||
4
.github/workflows/zizmor.yml
vendored
4
.github/workflows/zizmor.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
|||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
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@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
|
uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
|
||||||
|
|
||||||
- name: Run zizmor 🌈
|
- name: Run zizmor 🌈
|
||||||
run: uvx zizmor --format sarif . > results.sarif
|
run: uvx zizmor --format sarif . > results.sarif
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ bots:
|
|||||||
# user_agent_regex: (?i:bot|crawler)
|
# user_agent_regex: (?i:bot|crawler)
|
||||||
# action: CHALLENGE
|
# action: CHALLENGE
|
||||||
# challenge:
|
# challenge:
|
||||||
# difficulty: 16 # impossible
|
# difficulty: 16 # impossible
|
||||||
# report_as: 4 # lie to the operator
|
|
||||||
# algorithm: slow # intentionally waste CPU cycles and time
|
# algorithm: slow # intentionally waste CPU cycles and time
|
||||||
|
|
||||||
# Requires a subscription to Thoth to use, see
|
# Requires a subscription to Thoth to use, see
|
||||||
@@ -249,7 +248,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/metarefresh
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/metarefresh
|
||||||
algorithm: metarefresh
|
algorithm: metarefresh
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
# For clients that are browser-like but have either gained points from custom rules or
|
# For clients that are browser-like but have either gained points from custom rules or
|
||||||
# report as a standard browser.
|
# report as a standard browser.
|
||||||
- name: moderate-suspicion
|
- name: moderate-suspicion
|
||||||
@@ -262,7 +260,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 2 # two leading zeros, very fast for most clients
|
difficulty: 2 # two leading zeros, very fast for most clients
|
||||||
report_as: 2
|
|
||||||
- name: mild-proof-of-work
|
- name: mild-proof-of-work
|
||||||
expression:
|
expression:
|
||||||
all:
|
all:
|
||||||
@@ -273,7 +270,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
report_as: 4
|
|
||||||
# For clients that are browser like and have gained many points from custom rules
|
# For clients that are browser like and have gained many points from custom rules
|
||||||
- name: extreme-suspicion
|
- name: extreme-suspicion
|
||||||
expression: weight >= 30
|
expression: weight >= 30
|
||||||
@@ -282,4 +278,3 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 6
|
difficulty: 6
|
||||||
report_as: 6
|
|
||||||
|
|||||||
6
data/clients/telegram-preview.yaml
Normal file
6
data/clients/telegram-preview.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: telegrambot
|
||||||
|
action: ALLOW
|
||||||
|
expression:
|
||||||
|
all:
|
||||||
|
- userAgent.matches("TelegramBot")
|
||||||
|
- verifyFCrDNS(remoteAddress, "ptr\\.telegram\\.org$")
|
||||||
6
data/clients/vk-preview.yaml
Normal file
6
data/clients/vk-preview.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: vkbot
|
||||||
|
action: ALLOW
|
||||||
|
expression:
|
||||||
|
all:
|
||||||
|
- userAgent.matches("vkShare[^+]+\\+http\\://vk\\.com/dev/Share")
|
||||||
|
- verifyFCrDNS(remoteAddress, "^snipster\\d+\\.go\\.mail\\.ru$")
|
||||||
@@ -8,3 +8,4 @@
|
|||||||
- import: (data)/crawlers/marginalia.yaml
|
- import: (data)/crawlers/marginalia.yaml
|
||||||
- import: (data)/crawlers/mojeekbot.yaml
|
- import: (data)/crawlers/mojeekbot.yaml
|
||||||
- import: (data)/crawlers/commoncrawl.yaml
|
- import: (data)/crawlers/commoncrawl.yaml
|
||||||
|
- import: (data)/crawlers/yandexbot.yaml
|
||||||
|
|||||||
6
data/crawlers/yandexbot.yaml
Normal file
6
data/crawlers/yandexbot.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: yandexbot
|
||||||
|
action: ALLOW
|
||||||
|
expression:
|
||||||
|
all:
|
||||||
|
- userAgent.matches("\\+http\\://yandex\\.com/bots")
|
||||||
|
- verifyFCrDNS(remoteAddress, "^.*\\.yandex\\.(ru|com|net)$")
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
# action: CHALLENGE
|
# action: CHALLENGE
|
||||||
# challenge:
|
# challenge:
|
||||||
# difficulty: 16 # impossible
|
# difficulty: 16 # impossible
|
||||||
# report_as: 4 # lie to the operator
|
|
||||||
# algorithm: slow # intentionally waste CPU cycles and time
|
# algorithm: slow # intentionally waste CPU cycles and time
|
||||||
|
|
||||||
# Requires a subscription to Thoth to use, see
|
# Requires a subscription to Thoth to use, see
|
||||||
|
|||||||
2
data/meta/messengers-preview.yaml
Normal file
2
data/meta/messengers-preview.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- import: (data)/clients/telegram-preview.yaml
|
||||||
|
- import: (data)/clients/vk-preview.yaml
|
||||||
@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
<!-- This changes the project to: -->
|
<!-- This changes the project to: -->
|
||||||
|
|
||||||
|
## v1.24.0 [pre1]: Y'shtola Rhul
|
||||||
|
|
||||||
|
Anubis is back and better than ever! Lots of minor fixes with some big ones interspersed.
|
||||||
|
|
||||||
- Fix panic when validating challenges after privacy-mode browsers strip headers and the follow-up request matches an `ALLOW` threshold.
|
- Fix panic when validating challenges after privacy-mode browsers strip headers and the follow-up request matches an `ALLOW` threshold.
|
||||||
- Expose WEIGHT rule matches as Prometheus metrics.
|
- Expose WEIGHT rule matches as Prometheus metrics.
|
||||||
- Allow more OCI registry clients [based on feedback](https://github.com/TecharoHQ/anubis/pull/1253#issuecomment-3506744184).
|
- Allow more OCI registry clients [based on feedback](https://github.com/TecharoHQ/anubis/pull/1253#issuecomment-3506744184).
|
||||||
@@ -24,6 +28,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- 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.
|
||||||
|
|
||||||
|
### Deprecate `report_as` in challenge configuration
|
||||||
|
|
||||||
|
Previously Anubis let you lie to users about the difficulty of a challenge to interfere with operators of malicious scrapers as a psychological attack:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bots:
|
||||||
|
# Punish any bot with "bot" in the user-agent string
|
||||||
|
# This is known to have a high false-positive rate, use at your own risk
|
||||||
|
- name: generic-bot-catchall
|
||||||
|
user_agent_regex: (?i:bot|crawler)
|
||||||
|
action: CHALLENGE
|
||||||
|
challenge:
|
||||||
|
difficulty: 16 # impossible
|
||||||
|
report_as: 4 # lie to the operator
|
||||||
|
algorithm: slow # intentionally waste CPU cycles and time
|
||||||
|
```
|
||||||
|
|
||||||
|
This has turned out to be a bad idea because it has caused massive user experience problems and has been removed. If you are using this setting, you will get a warning in your logs like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"time": "2025-11-25T23:10:31.092201549-05:00",
|
||||||
|
"level": "WARN",
|
||||||
|
"source": {
|
||||||
|
"function": "github.com/TecharoHQ/anubis/lib/policy.ParseConfig",
|
||||||
|
"file": "/home/xe/code/TecharoHQ/anubis/lib/policy/policy.go",
|
||||||
|
"line": 201
|
||||||
|
},
|
||||||
|
"msg": "use of deprecated report_as setting detected, please remove this from your policy file when possible",
|
||||||
|
"at": "config-validate",
|
||||||
|
"name": "mild-suspicion"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To remove this warning, remove this setting from your policy file.
|
||||||
|
|
||||||
### Logging customization
|
### Logging customization
|
||||||
|
|
||||||
Anubis now supports the ability to log to multiple backends ("sinks"). This allows you to have Anubis [log to a file](./admin/policies.mdx#file-sink) instead of just logging to standard out. You can also customize the [logging level](./admin/policies.mdx#log-levels) in the policy file:
|
Anubis now supports the ability to log to multiple backends ("sinks"). This allows you to have Anubis [log to a file](./admin/policies.mdx#file-sink) instead of just logging to standard out. You can also customize the [logging level](./admin/policies.mdx#log-levels) in the policy file:
|
||||||
@@ -44,6 +84,33 @@ logging:
|
|||||||
|
|
||||||
Additionally, information about [how Anubis uses each logging level](./admin/policies.mdx#log-levels) has been added to the documentation.
|
Additionally, information about [how Anubis uses each logging level](./admin/policies.mdx#log-levels) has been added to the documentation.
|
||||||
|
|
||||||
|
### DNS Features
|
||||||
|
|
||||||
|
- CEL expressions for:
|
||||||
|
- FCrDNS checks
|
||||||
|
- Forward DNS queries
|
||||||
|
- Reverse DNS queries
|
||||||
|
- `arpaReverseIP` to transform IPv4/6 addresses into ARPA reverse IP notation.
|
||||||
|
- `regexSafe` to escape regex special characters (useful for including `remoteAddress` or headers in regular expressions).
|
||||||
|
- DNS cache and other optimizations to minimize unnecessary DNS queries.
|
||||||
|
|
||||||
|
The DNS cache TTL can be changed in the bots config like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dns_ttl:
|
||||||
|
forward: 600
|
||||||
|
reverse: 600
|
||||||
|
```
|
||||||
|
|
||||||
|
The default value for both forward and reverse queries is 300 seconds.
|
||||||
|
|
||||||
|
The `verifyFCrDNS` CEL function has two overloads:
|
||||||
|
|
||||||
|
- `(addr)`
|
||||||
|
Simply verifies that the remote side has PTR records pointing to the target address.
|
||||||
|
- `(addr, ptrPattern)`
|
||||||
|
Verifies that the remote side refers to a specific domain and that this domain points to the target IP.
|
||||||
|
|
||||||
## v1.23.1: Lyse Hext - Echo 1
|
## v1.23.1: Lyse Hext - Echo 1
|
||||||
|
|
||||||
- Fix `SERVE_ROBOTS_TXT` setting after the double slash fix broke it.
|
- Fix `SERVE_ROBOTS_TXT` setting after the double slash fix broke it.
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ To use it in your Anubis configuration:
|
|||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
difficulty: 1 # Number of seconds to wait before refreshing the page
|
difficulty: 1 # Number of seconds to wait before refreshing the page
|
||||||
report_as: 4 # Unused by this challenge method
|
|
||||||
algorithm: metarefresh # Specify a non-JS challenge method
|
algorithm: metarefresh # Specify a non-JS challenge method
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ To use it in your Anubis configuration:
|
|||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
difficulty: 1 # Number of seconds to wait before refreshing the page
|
difficulty: 1 # Number of seconds to wait before refreshing the page
|
||||||
report_as: 4 # Unused by this challenge method
|
|
||||||
algorithm: preact
|
algorithm: preact
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -233,6 +233,27 @@ This is best applied when doing explicit block rules, eg:
|
|||||||
|
|
||||||
It seems counter-intuitive to allow known bad clients through sometimes, but this allows you to confuse attackers by making Anubis' behavior random. Adjust the thresholds and numbers as facts and circumstances demand.
|
It seems counter-intuitive to allow known bad clients through sometimes, but this allows you to confuse attackers by making Anubis' behavior random. Adjust the thresholds and numbers as facts and circumstances demand.
|
||||||
|
|
||||||
|
### `regexSafe`
|
||||||
|
|
||||||
|
Available in `bot` expressions.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function regexSafe(input: string): string;
|
||||||
|
```
|
||||||
|
|
||||||
|
`regexSafe` takes a string and escapes it for safe use inside of a regular expression. This is useful when you are creating regular expressions from headers or variables such as `remoteAddress`.
|
||||||
|
|
||||||
|
| Input | Output |
|
||||||
|
| :------------------------ | :------------------------------ |
|
||||||
|
| `regexSafe("1.2.3.4")` | `1\\.2\\.3\\.4` |
|
||||||
|
| `regexSafe("techaro.lol")` | `techaro\\.lol` |
|
||||||
|
| `regexSafe("star*")` | `star\\*` |
|
||||||
|
| `regexSafe("plus+")` | `plus\\+` |
|
||||||
|
| `regexSafe("{braces}")` | `\\{braces\\}` |
|
||||||
|
| `regexSafe("start^")` | `start\\^` |
|
||||||
|
| `regexSafe("back\\slash")` | `back\\\\slash` |
|
||||||
|
| `regexSafe("dash-dash")` | `dash\\-dash` |
|
||||||
|
|
||||||
### `segments`
|
### `segments`
|
||||||
|
|
||||||
Available in `bot` expressions.
|
Available in `bot` expressions.
|
||||||
@@ -266,6 +287,99 @@ This is useful if you want to write rules that allow requests that have no query
|
|||||||
- size(segments(path)) < 2
|
- size(segments(path)) < 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### DNS Functions
|
||||||
|
|
||||||
|
Anubis can also perform DNS lookups as a part of its expression evaluation. This can be useful for doing things like checking for a valid [Forward-confirmed reverse DNS (FCrDNS)](https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS) record.
|
||||||
|
|
||||||
|
#### `arpaReverseIP`
|
||||||
|
|
||||||
|
Available in `bot` expressions.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function arpaReverseIP(ip: string): string;
|
||||||
|
```
|
||||||
|
|
||||||
|
`arpaReverseIP` takes an IP address and returns its value in [ARPA notation](https://www.ietf.org/rfc/rfc2317.html). This can be useful when matching PTR record patterns.
|
||||||
|
|
||||||
|
| Input | Output |
|
||||||
|
| :----------------------------- | :------------------------------------------------------------------- |
|
||||||
|
| `arpaReverseIP("1.2.3.4")` | `4.3.2.1` |
|
||||||
|
| `arpaReverseIP("2001:db8::1")` | `1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2` |
|
||||||
|
|
||||||
|
#### `lookupHost`
|
||||||
|
|
||||||
|
Available in `bot` expressions.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function lookupHost(host: string): string[];
|
||||||
|
```
|
||||||
|
|
||||||
|
`lookupHost` performs a DNS lookup for the given hostname and returns a list of IP addresses.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: cloudflare-ip-in-host-header
|
||||||
|
action: DENY
|
||||||
|
expression: '"104.16.0.0" in lookupHost(headers["Host"])'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `reverseDNS`
|
||||||
|
|
||||||
|
Available in `bot` expressions.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function reverseDNS(ip: string): string[];
|
||||||
|
```
|
||||||
|
|
||||||
|
`reverseDNS` takes an IP address and returns the DNS names associated with it. This is useful when you want to check PTR records of an IP address.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: allow-googlebot
|
||||||
|
action: ALLOW
|
||||||
|
expression: 'reverseDNS(remoteAddress).endsWith(".googlebot.com")'
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
|
||||||
|
Do not use this for validating the legitimacy of an IP address. It is possible for DNS records to be out of date or otherwise manipulated. Use [`verifyFCrDNS`](#verifyfcrdns) instead for a more reliable result.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
#### `verifyFCrDNS`
|
||||||
|
|
||||||
|
Available in `bot` expressions.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function verifyFCrDNS(ip: string): bool;
|
||||||
|
function verifyFCrDNS(ip: string, pattern: string): bool;
|
||||||
|
```
|
||||||
|
|
||||||
|
`verifyFCrDNS` checks if the reverse DNS of an IP address matches its forward DNS. This is a common technique to filter out spam and bot traffic. `verifyFCrDNS` comes in two forms:
|
||||||
|
|
||||||
|
- `verifyFCrDNS(remoteAddress)` will check that the reverse DNS of the remote address resolves back to the remote address. If no PTR records, returns true.
|
||||||
|
- `verifyFCrDNS(remoteAddress, pattern)` will check that the reverse DNS of the remote address is matching with pattern and that name resolves back to the remote address.
|
||||||
|
|
||||||
|
This is best used in rules like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: require-fcrdns-for-post
|
||||||
|
action: DENY
|
||||||
|
expression:
|
||||||
|
all:
|
||||||
|
- method == "POST"
|
||||||
|
- "!verifyFCrDNS(remoteAddress)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an another example that allows requests from telegram:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: telegrambot
|
||||||
|
action: ALLOW
|
||||||
|
expression:
|
||||||
|
all:
|
||||||
|
- userAgent.matches("TelegramBot")
|
||||||
|
- verifyFCrDNS(remoteAddress, "ptr\\.telegram\\.org$")
|
||||||
|
```
|
||||||
|
|
||||||
## Life advice
|
## Life advice
|
||||||
|
|
||||||
Expressions are very powerful. This is a benefit and a burden. If you are not careful with your expression targeting, you will be liable to get yourself into trouble. If you are at all in doubt, throw a `CHALLENGE` over a `DENY`. Legitimate users can easily work around a `CHALLENGE` result with a [proof of work challenge](../../design/why-proof-of-work.mdx). Bots are less likely to be able to do this.
|
Expressions are very powerful. This is a benefit and a burden. If you are not careful with your expression targeting, you will be liable to get yourself into trouble. If you are at all in doubt, throw a `CHALLENGE` over a `DENY`. Legitimate users can easily work around a `CHALLENGE` result with a [proof of work challenge](../../design/why-proof-of-work.mdx). Bots are less likely to be able to do this.
|
||||||
|
|||||||
@@ -156,3 +156,68 @@ server {
|
|||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## Caddy
|
||||||
|
|
||||||
|
Anubis can be used with the [`forward_auth`](https://caddyserver.com/docs/caddyfile/directives/forward_auth) directive in Caddy.
|
||||||
|
|
||||||
|
First, the `TARGET` environment variable in Anubis must be set to a space, eg:
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem value="env-file" label="Environment file" default>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# anubis.env
|
||||||
|
|
||||||
|
TARGET=" "
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="docker-compose" label="Docker Compose">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
anubis-caddy:
|
||||||
|
image: ghcr.io/techarohq/anubis:latest
|
||||||
|
environment:
|
||||||
|
TARGET: " "
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="k8s" label="Kubernetes">
|
||||||
|
|
||||||
|
Inside your Deployment, StatefulSet, or Pod:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: anubis
|
||||||
|
image: ghcr.io/techarohq/anubis:latest
|
||||||
|
env:
|
||||||
|
- name: TARGET
|
||||||
|
value: " "
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
Then configure the necessary directives in your site block:
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
route {
|
||||||
|
# Assumption: Anubis is running in the same network namespace as
|
||||||
|
# caddy on localhost TCP port 8923
|
||||||
|
reverse_proxy /.within.website/* 127.0.0.1:8923
|
||||||
|
forward_auth 127.0.0.1:8923 {
|
||||||
|
uri /.within.website/x/cmd/anubis/api/check
|
||||||
|
trusted_proxies private_ranges
|
||||||
|
@unauthorized status 401
|
||||||
|
handle_response @unauthorized {
|
||||||
|
redir * /.within.website/?redir={uri} 307
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to use this for multiple sites, you can create a [snippet](https://caddyserver.com/docs/caddyfile/concepts#snippets) and import it in multiple site blocks.
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: metarefresh
|
algorithm: metarefresh
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
|
|
||||||
- name: moderate-suspicion
|
- name: moderate-suspicion
|
||||||
expression:
|
expression:
|
||||||
@@ -52,7 +51,6 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 2
|
difficulty: 2
|
||||||
report_as: 2
|
|
||||||
|
|
||||||
- name: extreme-suspicion
|
- name: extreme-suspicion
|
||||||
expression: weight >= 20
|
expression: weight >= 20
|
||||||
@@ -60,7 +58,6 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
report_as: 4
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This defines a suite of 4 thresholds:
|
This defines a suite of 4 thresholds:
|
||||||
@@ -130,7 +127,6 @@ action: CHALLENGE
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: metarefresh
|
algorithm: metarefresh
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ Assuming you are protecting `anubistest.techaro.lol`, you need the following ser
|
|||||||
DocumentRoot /var/www/anubistest.techaro.lol
|
DocumentRoot /var/www/anubistest.techaro.lol
|
||||||
ErrorLog /var/log/httpd/anubistest.techaro.lol_error.log
|
ErrorLog /var/log/httpd/anubistest.techaro.lol_error.log
|
||||||
CustomLog /var/log/httpd/anubistest.techaro.lol_access.log combined
|
CustomLog /var/log/httpd/anubistest.techaro.lol_access.log combined
|
||||||
|
|
||||||
|
# Pass the remote IP to the proxied application instead of 127.0.0.1
|
||||||
|
# This requires mod_remoteip
|
||||||
|
RemoteIPHeader X-Real-IP
|
||||||
|
RemoteIPTrustedProxy 127.0.0.1/32
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ This rule has been known to have a high false positive rate in testing. Please u
|
|||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
difficulty: 16 # impossible
|
difficulty: 16 # impossible
|
||||||
report_as: 4 # lie to the operator
|
|
||||||
algorithm: slow # intentionally waste CPU cycles and time
|
algorithm: slow # intentionally waste CPU cycles and time
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -93,7 +92,6 @@ Challenges can be configured with these settings:
|
|||||||
| Key | Example | Description |
|
| Key | Example | Description |
|
||||||
| :----------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :----------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `difficulty` | `4` | The challenge difficulty (number of leading zeros) for proof-of-work. See [Why does Anubis use Proof-of-Work?](/docs/design/why-proof-of-work) for more details. |
|
| `difficulty` | `4` | The challenge difficulty (number of leading zeros) for proof-of-work. See [Why does Anubis use Proof-of-Work?](/docs/design/why-proof-of-work) for more details. |
|
||||||
| `report_as` | `4` | What difficulty the UI should report to the user. Useful for messing with industrial-scale scraping efforts. |
|
|
||||||
| `algorithm` | `"fast"` | The challenge method to use. See [the list of challenge methods](./configuration/challenges/) for more information. |
|
| `algorithm` | `"fast"` | The challenge method to use. See [the list of challenge methods](./configuration/challenges/) for more information. |
|
||||||
|
|
||||||
### Remote IP based filtering
|
### Remote IP based filtering
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ bots:
|
|||||||
# action: CHALLENGE
|
# action: CHALLENGE
|
||||||
# challenge:
|
# challenge:
|
||||||
# difficulty: 16 # impossible
|
# difficulty: 16 # impossible
|
||||||
# report_as: 4 # lie to the operator
|
|
||||||
# algorithm: slow # intentionally waste CPU cycles and time
|
# algorithm: slow # intentionally waste CPU cycles and time
|
||||||
|
|
||||||
- name: rss-feed-blog
|
- name: rss-feed-blog
|
||||||
@@ -105,7 +104,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/metarefresh
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/metarefresh
|
||||||
algorithm: metarefresh
|
algorithm: metarefresh
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
# For clients that are browser-like but have either gained points from custom rules or
|
# For clients that are browser-like but have either gained points from custom rules or
|
||||||
# report as a standard browser.
|
# report as a standard browser.
|
||||||
- name: moderate-suspicion
|
- name: moderate-suspicion
|
||||||
@@ -122,7 +120,6 @@ thresholds:
|
|||||||
# challenge data, and forwards that to the client.
|
# challenge data, and forwards that to the client.
|
||||||
algorithm: preact
|
algorithm: preact
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
- name: mild-proof-of-work
|
- name: mild-proof-of-work
|
||||||
expression:
|
expression:
|
||||||
all:
|
all:
|
||||||
@@ -133,7 +130,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 2 # two leading zeros, very fast for most clients
|
difficulty: 2 # two leading zeros, very fast for most clients
|
||||||
report_as: 2
|
|
||||||
# For clients that are browser like and have gained many points from custom rules
|
# For clients that are browser like and have gained many points from custom rules
|
||||||
- name: extreme-suspicion
|
- name: extreme-suspicion
|
||||||
expression: weight >= 30
|
expression: weight >= 30
|
||||||
@@ -142,7 +138,6 @@ thresholds:
|
|||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
report_as: 4
|
|
||||||
|
|
||||||
dnsbl: false
|
dnsbl: false
|
||||||
|
|
||||||
|
|||||||
41
go.mod
41
go.mod
@@ -5,9 +5,9 @@ go 1.24.2
|
|||||||
require (
|
require (
|
||||||
github.com/TecharoHQ/thoth-proto v0.5.0
|
github.com/TecharoHQ/thoth-proto v0.5.0
|
||||||
github.com/a-h/templ v0.3.960
|
github.com/a-h/templ v0.3.960
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6
|
github.com/aws/aws-sdk-go-v2 v1.40.0
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20
|
github.com/aws/aws-sdk-go-v2/config v1.32.1
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0
|
||||||
github.com/cespare/xxhash/v2 v2.3.0
|
github.com/cespare/xxhash/v2 v2.3.0
|
||||||
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
|
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
|
||||||
github.com/fahedouch/go-logrotate v0.3.0
|
github.com/fahedouch/go-logrotate v0.3.0
|
||||||
@@ -22,14 +22,14 @@ require (
|
|||||||
github.com/nicksnyder/go-i18n/v2 v2.6.0
|
github.com/nicksnyder/go-i18n/v2 v2.6.0
|
||||||
github.com/playwright-community/playwright-go v0.5200.1
|
github.com/playwright-community/playwright-go v0.5200.1
|
||||||
github.com/prometheus/client_golang v1.23.2
|
github.com/prometheus/client_golang v1.23.2
|
||||||
github.com/redis/go-redis/v9 v9.16.0
|
github.com/redis/go-redis/v9 v9.17.0
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
|
||||||
github.com/shirou/gopsutil/v4 v4.25.10
|
github.com/shirou/gopsutil/v4 v4.25.10
|
||||||
github.com/testcontainers/testcontainers-go v0.40.0
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
go.etcd.io/bbolt v1.4.3
|
go.etcd.io/bbolt v1.4.3
|
||||||
golang.org/x/net v0.47.0
|
golang.org/x/net v0.47.0
|
||||||
golang.org/x/text v0.31.0
|
golang.org/x/text v0.31.0
|
||||||
google.golang.org/grpc v1.76.0
|
google.golang.org/grpc v1.77.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/apimachinery v0.34.2
|
k8s.io/apimachinery v0.34.2
|
||||||
sigs.k8s.io/yaml v1.6.0
|
sigs.k8s.io/yaml v1.6.0
|
||||||
@@ -54,19 +54,20 @@ require (
|
|||||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 // indirect
|
||||||
github.com/aws/smithy-go v1.23.2 // indirect
|
github.com/aws/smithy-go v1.23.2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
||||||
@@ -171,12 +172,12 @@ require (
|
|||||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
|||||||
90
go.sum
90
go.sum
@@ -51,40 +51,42 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW
|
|||||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
|
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20 h1:/jWF4Wu90EhKCgjTdy1DGxcbcbNrjfBHvksEL79tfQc=
|
github.com/aws/aws-sdk-go-v2/config v1.32.1 h1:iODUDLgk3q8/flEC7ymhmxjfoAnBDwEEYEVyKZ9mzjU=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20/go.mod h1:95Hh1Tc5VYKL9NJ7tAkDcqeKt+MCXQB1hQZaRdJIZE0=
|
github.com/aws/aws-sdk-go-v2/config v1.32.1/go.mod h1:xoAgo17AGrPpJBSLg81W+ikM0cpOZG8ad04T2r+d5P0=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24 h1:iJ2FmPT35EaIB0+kMa6TnQ+PwG5A1prEdAw+PsMzfHg=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1 h1:JeW+EwmtTE0yXFK8SmklrFh/cGTTXsQJumgMZNlbxfM=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24/go.mod h1:U91+DrfjAiXPDEGYhh/x29o4p0qHX5HDqG7y5VViv64=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1/go.mod h1:BOoXiStwTF+fT2XufhO0Efssbi1CNIO/ZXpZu87N0pw=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 h1:ITi7qiDSv/mSGDSWNpZ4k4Ve0DQR6Ug2SJQ8zEHoDXg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14/go.mod h1:k1xtME53H1b6YpZt74YmwlONMWf4ecM+lut1WQLAF/U=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 h1:Hjkh7kE6D81PgrHlE/m9gx+4TyyeLHuY8xJs7yXN5C4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4/go.mod h1:455WPHSwaGj2waRSpQp7TsnpOnBfw8iDfPfbwl7KPJE=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5/go.mod h1:nPRXgyCfAurhyaTMoBMwRBYBhaHI4lNPAnJmjM0Tslc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 h1:FzQE21lNtUor0Fb7QNgnEyiRCBlolLTX/Z1j65S7teM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14/go.mod h1:s1ydyWG9pm3ZwmmYN21HKyG9WzAZhYVW85wMHs5FV6w=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2 h1:DhdbtDl4FdNlj31+xiRXANxEE+eC7n8JQz+/ilwQ8Uc=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0 h1:8FshVvnV2sr9kOSAbOnc/vwVmmAwMjOedKH6JW2ddPM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0/go.mod h1:wYNqY3L02Z3IgRYxOBPH9I1zD9Cjh9hI5QOy/eOjQvw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 h1:BDgIUYGEo5TkayOWv/oBLPphWwNm/A91AebUjAu5L5g=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 h1:U//SlnkE1wOQiIImxzdY5PXat4Wq+8rlfVEw4Y7J8as=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 h1:HK5ON3KmQV2HcAunnx4sKLB9aPf3gKGwVAf7xnx0QT0=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 h1:LU8S9W/mPDAU9q0FjCLi0TrCheLMGwzbRpvUMwYspcA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 h1:GdGmKtG+/Krag7VfyOXV17xjTCz0i9NT+JnqLTOI5nA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso=
|
||||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@@ -343,8 +345,8 @@ github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyA
|
|||||||
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
||||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
|
github.com/redis/go-redis/v9 v9.17.0 h1:K6E+ZlYN95KSMmZeEQPbU/c++wfmEvfFB17yEAq/VhM=
|
||||||
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
github.com/redis/go-redis/v9 v9.17.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
@@ -418,24 +420,24 @@ gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/Yjui
|
|||||||
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
|
||||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
|
||||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -533,8 +535,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:
|
|||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
70
internal/dns/cache.go
Normal file
70
internal/dns/cache.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/lib/store"
|
||||||
|
|
||||||
|
_ "github.com/TecharoHQ/anubis/lib/store/all"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DnsCache struct {
|
||||||
|
forward store.JSON[[]string]
|
||||||
|
reverse store.JSON[[]string]
|
||||||
|
forwardTTL time.Duration
|
||||||
|
reverseTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDNSCache(forwardTTL int, reverseTTL int, backend store.Interface) *DnsCache {
|
||||||
|
return &DnsCache{
|
||||||
|
forward: store.JSON[[]string]{
|
||||||
|
Underlying: backend,
|
||||||
|
Prefix: "forwardDNS",
|
||||||
|
},
|
||||||
|
reverse: store.JSON[[]string]{
|
||||||
|
Underlying: backend,
|
||||||
|
Prefix: "reverseDNS",
|
||||||
|
},
|
||||||
|
forwardTTL: time.Duration(forwardTTL) * time.Second,
|
||||||
|
reverseTTL: time.Duration(reverseTTL) * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dns) getCachedForward(host string) ([]string, bool) {
|
||||||
|
if d.cache == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
if cached, err := d.cache.forward.Get(d.ctx, host); err == nil {
|
||||||
|
slog.Debug("DNS: forward cache hit", "name", host, "ips", cached)
|
||||||
|
return cached, true
|
||||||
|
}
|
||||||
|
slog.Debug("DNS: forward cache miss", "name", host)
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dns) getCachedReverse(addr string) ([]string, bool) {
|
||||||
|
if d.cache == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
if cached, err := d.cache.reverse.Get(d.ctx, addr); err == nil {
|
||||||
|
slog.Debug("DNS: reverse cache hit", "addr", addr, "names", cached)
|
||||||
|
return cached, true
|
||||||
|
}
|
||||||
|
slog.Debug("DNS: reverse cache miss", "addr", addr)
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dns) forwardCachePut(host string, entries []string) {
|
||||||
|
if d.cache == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.cache.forward.Set(d.ctx, host, entries, d.cache.forwardTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dns) reverseCachePut(addr string, entries []string) {
|
||||||
|
if d.cache == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.cache.reverse.Set(d.ctx, addr, entries, d.cache.reverseTTL)
|
||||||
|
}
|
||||||
174
internal/dns/dns.go
Normal file
174
internal/dns/dns.go
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DNSLookupAddr = net.LookupAddr
|
||||||
|
DNSLookupHost = net.LookupHost
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dns struct {
|
||||||
|
cache *DnsCache
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, cache *DnsCache) *Dns {
|
||||||
|
return &Dns{
|
||||||
|
cache: cache,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseDNS performs a reverse DNS lookup for the given IP address and trims the trailing dot from the results.
|
||||||
|
func (d *Dns) ReverseDNS(addr string) ([]string, error) {
|
||||||
|
slog.Debug("DNS: performing reverse lookup", "addr", addr)
|
||||||
|
|
||||||
|
if cached, ok := d.getCachedReverse(addr); ok {
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
names, err := DNSLookupAddr(addr)
|
||||||
|
if err != nil {
|
||||||
|
if dnsErr, ok := err.(*net.DNSError); ok && dnsErr.IsNotFound {
|
||||||
|
slog.Debug("DNS: no PTR record found", "addr", addr)
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
slog.Error("DNS: reverse lookup failed", "addr", addr, "err", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Debug("DNS: reverse lookup successful", "addr", addr, "names", names)
|
||||||
|
|
||||||
|
trimmedNames := make([]string, len(names))
|
||||||
|
for i, name := range names {
|
||||||
|
trimmedNames[i] = strings.TrimSuffix(name, ".")
|
||||||
|
}
|
||||||
|
d.reverseCachePut(addr, trimmedNames)
|
||||||
|
|
||||||
|
return trimmedNames, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupHost performs a forward DNS lookup for the given hostname.
|
||||||
|
func (d *Dns) LookupHost(host string) ([]string, error) {
|
||||||
|
slog.Debug("DNS: performing forward lookup", "host", host)
|
||||||
|
|
||||||
|
if cached, ok := d.getCachedForward(host); ok {
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := DNSLookupHost(host)
|
||||||
|
if err != nil {
|
||||||
|
if dnsErr, ok := err.(*net.DNSError); ok && dnsErr.IsNotFound {
|
||||||
|
slog.Debug("DNS: no A/AAAA record found", "host", host)
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
slog.Error("DNS: forward lookup failed", "host", host, "err", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Debug("DNS: forward lookup successful", "host", host, "addrs", addrs)
|
||||||
|
d.forwardCachePut(host, addrs)
|
||||||
|
return addrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyFCrDNSInternal performs the second half of the FCrDNS check, using a
|
||||||
|
// pre-fetched list of names to perform the forward lookups.
|
||||||
|
func (d *Dns) verifyFCrDNSInternal(addr string, names []string) bool {
|
||||||
|
for _, name := range names {
|
||||||
|
if cached, err := d.LookupHost(name); err == nil {
|
||||||
|
if slices.Contains(cached, addr) {
|
||||||
|
slog.Info("DNS: forward lookup confirmed original IP", "name", name, "addr", addr)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("DNS: could not confirm original IP in forward lookups", "addr", addr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyFCrDNS performs a forward-confirmed reverse DNS (FCrDNS) lookup for the given IP address,
|
||||||
|
// optionally matching against a provided pattern.
|
||||||
|
func (d *Dns) VerifyFCrDNS(addr string, pattern *string) bool {
|
||||||
|
var patternVal string
|
||||||
|
if pattern != nil {
|
||||||
|
patternVal = *pattern
|
||||||
|
}
|
||||||
|
slog.Debug("DNS: performing FCrDNS lookup", "addr", addr, "pattern", patternVal)
|
||||||
|
|
||||||
|
names, err := d.ReverseDNS(addr)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(names) == 0 {
|
||||||
|
return pattern == nil // If no pattern specified, check is passed
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a pattern is provided, check for a match.
|
||||||
|
if pattern != nil {
|
||||||
|
anyNameMatched := false
|
||||||
|
for _, name := range names {
|
||||||
|
matched, err := regexp.MatchString(*pattern, name)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("DNS: verifyFCrDNS invalid regex pattern", "err", err)
|
||||||
|
return false // Invalid pattern is a failure.
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
|
anyNameMatched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !anyNameMatched {
|
||||||
|
slog.Debug("DNS: FCrDNS no PTR matches the pattern", "addr", addr, "pattern", *pattern)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
slog.Debug("DNS: FCrDNS PTR matched pattern, proceeding with forward check", "addr", addr, "pattern", *pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're here, either there was no pattern, or the pattern matched.
|
||||||
|
// Proceed with the forward lookup confirmation.
|
||||||
|
return d.verifyFCrDNSInternal(addr, names)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArpaReverseIP performs translation from ip v4/v6 to arpa reverse notation
|
||||||
|
func (d *Dns) ArpaReverseIP(addr string) (string, error) {
|
||||||
|
ip := net.ParseIP(addr)
|
||||||
|
if ip == nil {
|
||||||
|
return addr, errors.New("invalid IP address")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d", ipv4[3], ipv4[2], ipv4[1], ipv4[0]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6 := ip.To16()
|
||||||
|
if ipv6 == nil {
|
||||||
|
return addr, errors.New("invalid IPv6 address")
|
||||||
|
}
|
||||||
|
|
||||||
|
hexBytes := make([]byte, hex.EncodedLen(len(ipv6)))
|
||||||
|
hex.Encode(hexBytes, ipv6)
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.Grow(len(hexBytes)*2 - 1)
|
||||||
|
|
||||||
|
for i := len(hexBytes) - 1; i >= 0; i-- {
|
||||||
|
sb.WriteByte(hexBytes[i])
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteByte('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.String(), nil
|
||||||
|
}
|
||||||
308
internal/dns/dns_test.go
Normal file
308
internal/dns/dns_test.go
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/lib/store/memory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newTestDNS is a helper function to create a new Dns object with an in-memory cache for testing.
|
||||||
|
func newTestDNS(forwardTTL int, reverseTTL int) *Dns {
|
||||||
|
ctx := context.Background()
|
||||||
|
memStore := memory.New(ctx)
|
||||||
|
cache := NewDNSCache(forwardTTL, reverseTTL, memStore)
|
||||||
|
return New(ctx, cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mockLookupAddr is a mock implementation of the net.LookupAddr function.
|
||||||
|
func mockLookupAddr(addr string) ([]string, error) {
|
||||||
|
switch addr {
|
||||||
|
case "8.8.8.8":
|
||||||
|
return []string{"dns.google."}, nil
|
||||||
|
case "1.1.1.1":
|
||||||
|
return []string{"one.one.one.one."}, nil
|
||||||
|
case "208.67.222.222":
|
||||||
|
return []string{"resolver1.opendns.com."}, nil
|
||||||
|
case "9.9.9.9":
|
||||||
|
return nil, &net.DNSError{Err: "no such host", Name: "9.9.9.9", IsNotFound: true}
|
||||||
|
case "1.2.3.4":
|
||||||
|
return nil, errors.New("unknown error")
|
||||||
|
default:
|
||||||
|
return nil, &net.DNSError{Err: "no such host", Name: addr, IsNotFound: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mockLookupHost is a mock implementation of the net.LookupHost function.
|
||||||
|
func mockLookupHost(host string) ([]string, error) {
|
||||||
|
switch host {
|
||||||
|
case "dns.google":
|
||||||
|
return []string{"8.8.8.8", "8.8.4.4"}, nil
|
||||||
|
case "one.one.one.one":
|
||||||
|
return []string{"1.1.1.1", "1.0.0.1"}, nil
|
||||||
|
case "resolver1.opendns.com":
|
||||||
|
return []string{"208.67.222.222"}, nil
|
||||||
|
case "example.com":
|
||||||
|
return nil, &net.DNSError{Err: "no such host", Name: "example.com", IsNotFound: true}
|
||||||
|
default:
|
||||||
|
return nil, &net.DNSError{Err: "no such host", Name: host, IsNotFound: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// Before all tests
|
||||||
|
originalLookupAddr := DNSLookupAddr
|
||||||
|
originalLookupHost := DNSLookupHost
|
||||||
|
|
||||||
|
DNSLookupAddr = mockLookupAddr
|
||||||
|
DNSLookupHost = mockLookupHost
|
||||||
|
|
||||||
|
// Run tests
|
||||||
|
exitCode := m.Run()
|
||||||
|
|
||||||
|
// After all tests
|
||||||
|
DNSLookupAddr = originalLookupAddr
|
||||||
|
DNSLookupHost = originalLookupHost
|
||||||
|
|
||||||
|
// Exit
|
||||||
|
if exitCode != 0 {
|
||||||
|
panic(exitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDns_ArpaReverseIP(t *testing.T) {
|
||||||
|
d := newTestDNS(0, 0)
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ip string
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ipv4", "192.0.2.1", "1.2.0.192", false},
|
||||||
|
{"ipv6", "2001:db8::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2", false},
|
||||||
|
{"invalid ip", "invalid", "invalid", true},
|
||||||
|
{"ipv4-mapped ipv6", "::ffff:192.0.2.1", "1.2.0.192", false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := d.ArpaReverseIP(tt.ip)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("ArpaReverseIP() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("ArpaReverseIP() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDns_ReverseDNS(t *testing.T) {
|
||||||
|
d := newTestDNS(1, 1) // short TTL for testing cache
|
||||||
|
|
||||||
|
// First call - cache miss
|
||||||
|
t.Run("cache miss", func(t *testing.T) {
|
||||||
|
got, err := d.ReverseDNS("8.8.8.8")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReverseDNS() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"dns.google"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("ReverseDNS() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Second call - cache hit
|
||||||
|
t.Run("cache hit", func(t *testing.T) {
|
||||||
|
// Temporarily replace lookup function to ensure cache is used
|
||||||
|
originalLookupAddr := DNSLookupAddr
|
||||||
|
DNSLookupAddr = func(addr string) ([]string, error) {
|
||||||
|
return nil, errors.New("should not be called")
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupAddr = originalLookupAddr }()
|
||||||
|
|
||||||
|
got, err := d.ReverseDNS("8.8.8.8")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReverseDNS() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"dns.google"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("ReverseDNS() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test cache expiration
|
||||||
|
t.Run("cache expiration", func(t *testing.T) {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
// Now the cache should be expired
|
||||||
|
// We expect the mock to be called again
|
||||||
|
// To test this we will change the mock to return something different
|
||||||
|
originalLookupAddr := DNSLookupAddr
|
||||||
|
DNSLookupAddr = func(addr string) ([]string, error) {
|
||||||
|
if addr == "8.8.8.8" {
|
||||||
|
return []string{"expired.google."}, nil
|
||||||
|
}
|
||||||
|
return mockLookupAddr(addr)
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupAddr = originalLookupAddr }()
|
||||||
|
|
||||||
|
got, err := d.ReverseDNS("8.8.8.8")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReverseDNS() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"expired.google"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("ReverseDNS() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test not found
|
||||||
|
t.Run("not found", func(t *testing.T) {
|
||||||
|
got, err := d.ReverseDNS("9.9.9.9")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReverseDNS() error = %v", err)
|
||||||
|
}
|
||||||
|
if len(got) != 0 {
|
||||||
|
t.Errorf("ReverseDNS() = %v, want empty slice", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDns_LookupHost(t *testing.T) {
|
||||||
|
d := newTestDNS(1, 1)
|
||||||
|
|
||||||
|
t.Run("cache miss", func(t *testing.T) {
|
||||||
|
got, err := d.LookupHost("dns.google")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("LookupHost() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"8.8.8.8", "8.8.4.4"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("LookupHost() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("cache hit", func(t *testing.T) {
|
||||||
|
originalLookupHost := DNSLookupHost
|
||||||
|
DNSLookupHost = func(host string) ([]string, error) {
|
||||||
|
return nil, errors.New("should not be called")
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupHost = originalLookupHost }()
|
||||||
|
|
||||||
|
got, err := d.LookupHost("dns.google")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("LookupHost() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"8.8.8.8", "8.8.4.4"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("LookupHost() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("cache expiration", func(t *testing.T) {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
originalLookupHost := DNSLookupHost
|
||||||
|
DNSLookupHost = func(host string) ([]string, error) {
|
||||||
|
if host == "dns.google" {
|
||||||
|
return []string{"9.9.9.9"}, nil
|
||||||
|
}
|
||||||
|
return mockLookupHost(host)
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupHost = originalLookupHost }()
|
||||||
|
|
||||||
|
got, err := d.LookupHost("dns.google")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("LookupHost() error = %v", err)
|
||||||
|
}
|
||||||
|
want := []string{"9.9.9.9"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("LookupHost() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not found", func(t *testing.T) {
|
||||||
|
got, err := d.LookupHost("example.com")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("LookupHost() error = %v", err)
|
||||||
|
}
|
||||||
|
if len(got) != 0 {
|
||||||
|
t.Errorf("LookupHost() = %v, want empty slice", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDns_VerifyFCrDNS(t *testing.T) {
|
||||||
|
d := newTestDNS(1, 1)
|
||||||
|
|
||||||
|
// Helper to convert string to *string
|
||||||
|
p := func(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ip string
|
||||||
|
pattern *string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// Cases without pattern
|
||||||
|
{"valid no pattern", "8.8.8.8", nil, true},
|
||||||
|
{"valid partial no pattern", "1.1.1.1", nil, true},
|
||||||
|
{"not found no pattern", "9.9.9.9", nil, true},
|
||||||
|
{"unknown error no pattern", "1.2.3.4", nil, false},
|
||||||
|
|
||||||
|
// Cases with pattern
|
||||||
|
{"valid match", "8.8.8.8", p(`.*\.google$`), true},
|
||||||
|
{"valid no match", "8.8.8.8", p(`\.com$`), false},
|
||||||
|
{"not found with pattern", "9.9.9.9", p(".*"), false},
|
||||||
|
{"unknown error with pattern", "1.2.3.4", p(".*"), false},
|
||||||
|
{"invalid pattern", "8.8.8.8", p(`[`), false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := d.VerifyFCrDNS(tt.ip, tt.pattern); got != tt.want {
|
||||||
|
t.Errorf("VerifyFCrDNS() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("reverse cache hit", func(t *testing.T) {
|
||||||
|
// Prime the cache
|
||||||
|
if got := d.VerifyFCrDNS("8.8.8.8", nil); got != true {
|
||||||
|
t.Fatalf("VerifyFCrDNS() priming failed, got %v, want true", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now test with a failing lookup to ensure cache is used
|
||||||
|
originalLookupAddr := DNSLookupAddr
|
||||||
|
DNSLookupAddr = func(addr string) ([]string, error) {
|
||||||
|
return nil, errors.New("should not be called")
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupAddr = originalLookupAddr }()
|
||||||
|
|
||||||
|
if got := d.VerifyFCrDNS("8.8.8.8", nil); got != true {
|
||||||
|
t.Errorf("VerifyFCrDNS() = %v, want true", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("forward cache hit", func(t *testing.T) {
|
||||||
|
// Prime the cache
|
||||||
|
if got := d.VerifyFCrDNS("8.8.8.8", nil); got != true {
|
||||||
|
t.Fatalf("VerifyFCrDNS() priming failed, got %v, want true", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now test with a failing lookup to ensure cache is used
|
||||||
|
originalLookupHost := DNSLookupHost
|
||||||
|
DNSLookupHost = func(host string) ([]string, error) {
|
||||||
|
return nil, errors.New("should not be called")
|
||||||
|
}
|
||||||
|
defer func() { DNSLookupHost = originalLookupHost }()
|
||||||
|
|
||||||
|
if got := d.VerifyFCrDNS("8.8.8.8", nil); got != true {
|
||||||
|
t.Errorf("VerifyFCrDNS() = %v, want true", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -167,8 +167,8 @@ func (s *Server) hydrateChallengeRule(rule *policy.Bot, chall *challenge.Challen
|
|||||||
if rule.Challenge.Difficulty == 0 {
|
if rule.Challenge.Difficulty == 0 {
|
||||||
rule.Challenge.Difficulty = chall.Difficulty
|
rule.Challenge.Difficulty = chall.Difficulty
|
||||||
}
|
}
|
||||||
if rule.Challenge.ReportAs == 0 {
|
if rule.Challenge.ReportAs != 0 {
|
||||||
rule.Challenge.ReportAs = chall.Difficulty
|
s.logger.Warn("[DEPRECATION] the report_as field in this bot rule is deprecated, see https://github.com/TecharoHQ/anubis/issues/1310 for more information", "bot_name", rule.Name, "difficulty", rule.Challenge.Difficulty, "report_as", rule.Challenge.ReportAs)
|
||||||
}
|
}
|
||||||
if rule.Challenge.Algorithm == "" {
|
if rule.Challenge.Algorithm == "" {
|
||||||
rule.Challenge.Algorithm = chall.Method
|
rule.Challenge.Algorithm = chall.Method
|
||||||
@@ -648,7 +648,6 @@ func (s *Server) check(r *http.Request, lg *slog.Logger) (policy.CheckResult, *p
|
|||||||
return cr("default/allow", config.RuleAllow, weight), &policy.Bot{
|
return cr("default/allow", config.RuleAllow, weight), &policy.Bot{
|
||||||
Challenge: &config.ChallengeRules{
|
Challenge: &config.ChallengeRules{
|
||||||
Difficulty: s.policy.DefaultDifficulty,
|
Difficulty: s.policy.DefaultDifficulty,
|
||||||
ReportAs: s.policy.DefaultDifficulty,
|
|
||||||
Algorithm: config.DefaultAlgorithm,
|
Algorithm: config.DefaultAlgorithm,
|
||||||
},
|
},
|
||||||
Rules: &checker.List{},
|
Rules: &checker.List{},
|
||||||
|
|||||||
@@ -464,10 +464,6 @@ func TestCheckDefaultDifficultyMatchesPolicy(t *testing.T) {
|
|||||||
if bot.Challenge.Difficulty != i {
|
if bot.Challenge.Difficulty != i {
|
||||||
t.Errorf("Challenge.Difficulty is wrong, wanted %d, got: %d", i, bot.Challenge.Difficulty)
|
t.Errorf("Challenge.Difficulty is wrong, wanted %d, got: %d", i, bot.Challenge.Difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.Challenge.ReportAs != i {
|
|
||||||
t.Errorf("Challenge.ReportAs is wrong, wanted %d, got: %d", i, bot.Challenge.ReportAs)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ func TestBasic(t *testing.T) {
|
|||||||
Challenge: &config.ChallengeRules{
|
Challenge: &config.ChallengeRules{
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
Difficulty: 0,
|
Difficulty: 0,
|
||||||
ReportAs: 0,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const challengeStr = "hunter"
|
const challengeStr = "hunter"
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ type fileConfig struct {
|
|||||||
Thresholds []Threshold `json:"thresholds"`
|
Thresholds []Threshold `json:"thresholds"`
|
||||||
StatusCodes StatusCodes `json:"status_codes"`
|
StatusCodes StatusCodes `json:"status_codes"`
|
||||||
DNSBL bool `json:"dnsbl"`
|
DNSBL bool `json:"dnsbl"`
|
||||||
|
DNSTTL DnsTTL `json:"dns_ttl"`
|
||||||
Logging *Logging `json:"logging"`
|
Logging *Logging `json:"logging"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,6 +388,10 @@ func Load(fin io.Reader, fname string) (*Config, error) {
|
|||||||
Challenge: http.StatusOK,
|
Challenge: http.StatusOK,
|
||||||
Deny: http.StatusOK,
|
Deny: http.StatusOK,
|
||||||
},
|
},
|
||||||
|
DNSTTL: DnsTTL{
|
||||||
|
Forward: 300,
|
||||||
|
Reverse: 300,
|
||||||
|
},
|
||||||
Store: &Store{
|
Store: &Store{
|
||||||
Backend: "memory",
|
Backend: "memory",
|
||||||
},
|
},
|
||||||
@@ -402,7 +407,8 @@ func Load(fin io.Reader, fname string) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Config{
|
result := &Config{
|
||||||
DNSBL: c.DNSBL,
|
DNSBL: c.DNSBL,
|
||||||
|
DNSTTL: c.DNSTTL,
|
||||||
OpenGraph: OpenGraph{
|
OpenGraph: OpenGraph{
|
||||||
Enabled: c.OpenGraph.Enabled,
|
Enabled: c.OpenGraph.Enabled,
|
||||||
ConsiderHost: c.OpenGraph.ConsiderHost,
|
ConsiderHost: c.OpenGraph.ConsiderHost,
|
||||||
@@ -469,6 +475,29 @@ func Load(fin io.Reader, fname string) (*Config, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DnsTTL struct {
|
||||||
|
Forward int `json:"forward"`
|
||||||
|
Reverse int `json:"reverse"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc DnsTTL) Valid() error {
|
||||||
|
var errs []error
|
||||||
|
|
||||||
|
if sc.Forward < 0 {
|
||||||
|
errs = append(errs, fmt.Errorf("%w: forward TTL is %d", ErrStatusCodeNotValid, sc.Forward))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc.Reverse < 0 {
|
||||||
|
errs = append(errs, fmt.Errorf("%w: reverse TTL is %d", ErrStatusCodeNotValid, sc.Reverse))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) != 0 {
|
||||||
|
return fmt.Errorf("dns TTL values not valid:\n%w", errors.Join(errs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Impressum *Impressum
|
Impressum *Impressum
|
||||||
Store *Store
|
Store *Store
|
||||||
@@ -478,6 +507,7 @@ type Config struct {
|
|||||||
StatusCodes StatusCodes
|
StatusCodes StatusCodes
|
||||||
Logging *Logging
|
Logging *Logging
|
||||||
DNSBL bool
|
DNSBL bool
|
||||||
|
DNSTTL DnsTTL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) Valid() error {
|
func (c Config) Valid() error {
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ func TestBotValid(t *testing.T) {
|
|||||||
PathRegex: p("Mozilla"),
|
PathRegex: p("Mozilla"),
|
||||||
Challenge: &ChallengeRules{
|
Challenge: &ChallengeRules{
|
||||||
Difficulty: -1,
|
Difficulty: -1,
|
||||||
ReportAs: 4,
|
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -124,7 +123,6 @@ func TestBotValid(t *testing.T) {
|
|||||||
PathRegex: p("Mozilla"),
|
PathRegex: p("Mozilla"),
|
||||||
Challenge: &ChallengeRules{
|
Challenge: &ChallengeRules{
|
||||||
Difficulty: 420,
|
Difficulty: 420,
|
||||||
ReportAs: 4,
|
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -361,7 +359,6 @@ func TestBotConfigZero(t *testing.T) {
|
|||||||
|
|
||||||
b.Challenge = &ChallengeRules{
|
b.Challenge = &ChallengeRules{
|
||||||
Difficulty: 4,
|
Difficulty: 4,
|
||||||
ReportAs: 4,
|
|
||||||
Algorithm: DefaultAlgorithm,
|
Algorithm: DefaultAlgorithm,
|
||||||
}
|
}
|
||||||
if b.Zero() {
|
if b.Zero() {
|
||||||
|
|||||||
8
lib/config/testdata/bad/dns-ttl-custom.yaml
vendored
Normal file
8
lib/config/testdata/bad/dns-ttl-custom.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
dns_ttl:
|
||||||
|
forward: 60.0
|
||||||
|
reverse: "600"
|
||||||
|
|
||||||
|
bots:
|
||||||
|
- name: "test"
|
||||||
|
user_agent_regex: ".*"
|
||||||
|
action: "DENY"
|
||||||
8
lib/config/testdata/good/dns-ttl-custom.yaml
vendored
Normal file
8
lib/config/testdata/good/dns-ttl-custom.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
dns_ttl:
|
||||||
|
forward: 600
|
||||||
|
reverse: 600
|
||||||
|
|
||||||
|
bots:
|
||||||
|
- name: "test"
|
||||||
|
user_agent_regex: ".*"
|
||||||
|
action: "DENY"
|
||||||
3
lib/config/testdata/good/thresholds.yaml
vendored
3
lib/config/testdata/good/thresholds.yaml
vendored
@@ -18,7 +18,6 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: metarefresh
|
algorithm: metarefresh
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
- name: moderate-suspicion
|
- name: moderate-suspicion
|
||||||
expression:
|
expression:
|
||||||
all:
|
all:
|
||||||
@@ -28,11 +27,9 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 2
|
difficulty: 2
|
||||||
report_as: 2
|
|
||||||
- name: extreme-suspicion
|
- name: extreme-suspicion
|
||||||
expression: weight >= 20
|
expression: weight >= 20
|
||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
report_as: 4
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ var (
|
|||||||
Challenge: &ChallengeRules{
|
Challenge: &ChallengeRules{
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
Difficulty: anubis.DefaultDifficulty,
|
Difficulty: anubis.DefaultDifficulty,
|
||||||
ReportAs: anubis.DefaultDifficulty,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ func TestThresholdValid(t *testing.T) {
|
|||||||
Challenge: &ChallengeRules{
|
Challenge: &ChallengeRules{
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
Difficulty: 1,
|
Difficulty: 1,
|
||||||
ReportAs: 1,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
err: nil,
|
err: nil,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
|
"github.com/TecharoHQ/anubis/internal/dns"
|
||||||
"github.com/TecharoHQ/anubis/lib/config"
|
"github.com/TecharoHQ/anubis/lib/config"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/expressions"
|
"github.com/TecharoHQ/anubis/lib/policy/expressions"
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
@@ -16,8 +17,8 @@ type CELChecker struct {
|
|||||||
src string
|
src string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCELChecker(cfg *config.ExpressionOrList) (*CELChecker, error) {
|
func NewCELChecker(cfg *config.ExpressionOrList, dnsObj *dns.Dns) (*CELChecker, error) {
|
||||||
env, err := expressions.BotEnvironment()
|
env, err := expressions.BotEnvironment(dnsObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/internal/dns"
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
"github.com/google/cel-go/common/types/ref"
|
"github.com/google/cel-go/common/types/ref"
|
||||||
@@ -15,7 +16,7 @@ import (
|
|||||||
// variables and functions that are passed into the CEL scope so that
|
// variables and functions that are passed into the CEL scope so that
|
||||||
// Anubis can fail loudly and early when something is invalid instead
|
// Anubis can fail loudly and early when something is invalid instead
|
||||||
// of blowing up at runtime.
|
// of blowing up at runtime.
|
||||||
func BotEnvironment() (*cel.Env, error) {
|
func BotEnvironment(dnsObj *dns.Dns) (*cel.Env, error) {
|
||||||
return New(
|
return New(
|
||||||
// Variables exposed to CEL programs:
|
// Variables exposed to CEL programs:
|
||||||
cel.Variable("remoteAddress", cel.StringType),
|
cel.Variable("remoteAddress", cel.StringType),
|
||||||
@@ -57,6 +58,118 @@ func BotEnvironment() (*cel.Env, error) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
cel.Function("reverseDNS",
|
||||||
|
cel.Overload("reverseDNS_string_list_string",
|
||||||
|
[]*cel.Type{cel.StringType},
|
||||||
|
cel.ListType(cel.StringType),
|
||||||
|
cel.UnaryBinding(func(addr ref.Val) ref.Val {
|
||||||
|
addrStr, ok := addr.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(addr, "addr is not a string, but is %T", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
names, err := dnsObj.ReverseDNS(string(addrStr))
|
||||||
|
if err != nil {
|
||||||
|
return types.NewStringList(types.DefaultTypeAdapter, []string{})
|
||||||
|
}
|
||||||
|
return types.NewStringList(types.DefaultTypeAdapter, names)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
cel.Function("lookupHost",
|
||||||
|
cel.Overload("lookupHost_string_list_string",
|
||||||
|
[]*cel.Type{cel.StringType},
|
||||||
|
cel.ListType(cel.StringType),
|
||||||
|
cel.UnaryBinding(func(host ref.Val) ref.Val {
|
||||||
|
hostStr, ok := host.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(host, "host is not a string, but is %T", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := dnsObj.LookupHost(string(hostStr))
|
||||||
|
if err != nil {
|
||||||
|
return types.NewStringList(types.DefaultTypeAdapter, []string{})
|
||||||
|
}
|
||||||
|
return types.NewStringList(types.DefaultTypeAdapter, addrs)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
cel.Function("verifyFCrDNS",
|
||||||
|
cel.Overload("verifyFCrDNS_string_bool",
|
||||||
|
[]*cel.Type{cel.StringType},
|
||||||
|
cel.BoolType,
|
||||||
|
cel.UnaryBinding(func(addr ref.Val) ref.Val {
|
||||||
|
addrStr, ok := addr.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(addr, "addr is not a string")
|
||||||
|
}
|
||||||
|
return types.Bool(dnsObj.VerifyFCrDNS(string(addrStr), nil))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
cel.Overload("verifyFCrDNS_string_string_bool",
|
||||||
|
[]*cel.Type{cel.StringType, cel.StringType},
|
||||||
|
cel.BoolType,
|
||||||
|
cel.BinaryBinding(func(addr, pattern ref.Val) ref.Val {
|
||||||
|
addrStr, ok := addr.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(addr, "addr is not a string")
|
||||||
|
}
|
||||||
|
patternStr, ok := pattern.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(pattern, "pattern is not a string")
|
||||||
|
}
|
||||||
|
p := string(patternStr)
|
||||||
|
return types.Bool(dnsObj.VerifyFCrDNS(string(addrStr), &p))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// arpaReverseIP transforms ip into arpa reverse notation like this
|
||||||
|
// 1.2.3.4 -> 4.3.2.1
|
||||||
|
// 2001:db8::1 -> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2
|
||||||
|
cel.Function("arpaReverseIP",
|
||||||
|
cel.Overload("arpaReverseIP_string_string",
|
||||||
|
[]*cel.Type{cel.StringType},
|
||||||
|
cel.StringType,
|
||||||
|
cel.UnaryBinding(func(addr ref.Val) ref.Val {
|
||||||
|
s, ok := addr.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(addr, "addr is not a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
reversedIp, err := dnsObj.ArpaReverseIP(string(s))
|
||||||
|
if err != nil {
|
||||||
|
return types.ValOrErr(addr, "%s", err.Error())
|
||||||
|
}
|
||||||
|
return types.String(reversedIp)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// regexSafe escapes a string for insertion into a regular expression
|
||||||
|
cel.Function("regexSafe",
|
||||||
|
cel.Overload("regexSafe_string_string",
|
||||||
|
[]*cel.Type{cel.StringType},
|
||||||
|
cel.StringType,
|
||||||
|
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||||
|
s, ok := str.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return types.ValOrErr(str, "addr is not a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
escapes := []string{"\\", ".", ":", "*", "?", "-", "[", "]", "(", ")", "+", "{", "}", "|", "^", "$"}
|
||||||
|
r := string(s)
|
||||||
|
|
||||||
|
for _, escape := range escapes {
|
||||||
|
r = strings.ReplaceAll(r, escape, "\\"+escape)
|
||||||
|
}
|
||||||
|
return types.String(r)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
cel.Function("segments",
|
cel.Function("segments",
|
||||||
cel.Overload("segments_string_list_string",
|
cel.Overload("segments_string_list_string",
|
||||||
[]*cel.Type{cel.StringType},
|
[]*cel.Type{cel.StringType},
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
package expressions
|
package expressions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/internal/dns"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/store/memory"
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
|
"github.com/google/cel-go/common/types/ref"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// newTestDNS is a helper function to create a new Dns object with an in-memory cache for testing.
|
||||||
|
func newTestDNS(forwardTTL int, reverseTTL int) *dns.Dns {
|
||||||
|
ctx := context.Background()
|
||||||
|
memStore := memory.New(ctx)
|
||||||
|
cache := dns.NewDNSCache(forwardTTL, reverseTTL, memStore)
|
||||||
|
return dns.New(ctx, cache)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBotEnvironment(t *testing.T) {
|
func TestBotEnvironment(t *testing.T) {
|
||||||
env, err := BotEnvironment()
|
dnsObj := newTestDNS(300, 300)
|
||||||
|
env, err := BotEnvironment(dnsObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create bot environment: %v", err)
|
t.Fatalf("failed to create bot environment: %v", err)
|
||||||
}
|
}
|
||||||
@@ -235,6 +251,344 @@ func TestBotEnvironment(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("regexSafe", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expression string
|
||||||
|
expected types.String
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "complex-test",
|
||||||
|
expression: `regexSafe("^(test1|test2|)[a-z]+$")`,
|
||||||
|
expected: types.String("\\^\\(test1\\|test2\\|\\)\\[a\\-z\\]\\+\\$"),
|
||||||
|
description: "should escape all reserved regex characters",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "backslash-test",
|
||||||
|
expression: `regexSafe("use \\\\ for special characters escaping\t, one/\"\\\"/for/cel and one/for/regex")`,
|
||||||
|
expected: types.String("use \\\\\\\\ for special characters escaping\t, one/\"\\\\\"/for/cel and one/for/regex"),
|
||||||
|
description: "should escape double-backslashes as double-double-backslashes and ignore cel escaping and forward slashes",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
prog, err := Compile(env, tt.expression)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _, err := prog.Eval(map[string]interface{}{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to evaluate expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("%s: expected %v, got %v", tt.description, tt.expected, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("function-compilation", func(t *testing.T) {
|
||||||
|
src := `regexSafe(".*")`
|
||||||
|
_, err := Compile(env, src)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile regexSafe expression: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("dnsFunctions", func(t *testing.T) {
|
||||||
|
originalDNSLookupAddr := dns.DNSLookupAddr
|
||||||
|
originalDNSLookupHost := dns.DNSLookupHost
|
||||||
|
defer func() {
|
||||||
|
dns.DNSLookupAddr = originalDNSLookupAddr
|
||||||
|
dns.DNSLookupHost = originalDNSLookupHost
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Run("reverseDNS", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
addr string
|
||||||
|
mockReturn []string
|
||||||
|
mockError error
|
||||||
|
expression string
|
||||||
|
expected ref.Val
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
addr: "8.8.8.8",
|
||||||
|
mockReturn: []string{"dns.google."},
|
||||||
|
expression: `reverseDNS("8.8.8.8")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{"dns.google"}),
|
||||||
|
description: "should return domain names for an IP",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not-found",
|
||||||
|
addr: "127.0.0.1",
|
||||||
|
mockReturn: []string{},
|
||||||
|
mockError: &net.DNSError{IsNotFound: true},
|
||||||
|
expression: `reverseDNS("127.0.0.1")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{}),
|
||||||
|
description: "should return an empty list when not found",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error",
|
||||||
|
addr: "error-addr",
|
||||||
|
mockError: errors.New("some dns error"),
|
||||||
|
expression: `reverseDNS("error-addr")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{}),
|
||||||
|
description: "should return empty list on error",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
dns.DNSLookupAddr = func(addr string) ([]string, error) {
|
||||||
|
if addr == tt.addr {
|
||||||
|
return tt.mockReturn, tt.mockError
|
||||||
|
}
|
||||||
|
return nil, errors.New("unexpected address for reverse lookup")
|
||||||
|
}
|
||||||
|
|
||||||
|
prog, err := Compile(env, tt.expression)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _, err := prog.Eval(map[string]interface{}{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to evaluate expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
if result.Equal(tt.expected) != types.True {
|
||||||
|
t.Errorf("%s: expected %v, got %v", tt.description, tt.expected, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("lookupHost", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
host string
|
||||||
|
mockReturn []string
|
||||||
|
mockError error
|
||||||
|
expression string
|
||||||
|
expected ref.Val
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
host: "dns.google",
|
||||||
|
mockReturn: []string{"8.8.8.8", "8.8.4.4"},
|
||||||
|
expression: `lookupHost("dns.google")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{"8.8.8.8", "8.8.4.4"}),
|
||||||
|
description: "should return IPs for a domain name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not-found",
|
||||||
|
host: "nonexistent.domain.example.com",
|
||||||
|
mockReturn: []string{},
|
||||||
|
mockError: &net.DNSError{IsNotFound: true},
|
||||||
|
expression: `lookupHost("nonexistent.domain.example.com")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{}),
|
||||||
|
description: "should return an empty list when not found",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error",
|
||||||
|
host: "error-host",
|
||||||
|
mockError: errors.New("some dns error"),
|
||||||
|
expression: `lookupHost("error-host")`,
|
||||||
|
expected: types.NewStringList(types.DefaultTypeAdapter, []string{}),
|
||||||
|
description: "should return empty list on error",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
dns.DNSLookupHost = func(host string) ([]string, error) {
|
||||||
|
if host == tt.host {
|
||||||
|
return tt.mockReturn, tt.mockError
|
||||||
|
}
|
||||||
|
return nil, errors.New("unexpected host for forward lookup")
|
||||||
|
}
|
||||||
|
|
||||||
|
prog, err := Compile(env, tt.expression)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _, err := prog.Eval(map[string]interface{}{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to evaluate expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
if result.Equal(tt.expected) != types.True {
|
||||||
|
t.Errorf("%s: expected %v, got %v", tt.description, tt.expected, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("verifyFCrDNS", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
addr string
|
||||||
|
reverseMockReturn []string
|
||||||
|
reverseMockError error
|
||||||
|
forwardMockReturn map[string][]string // name -> ips
|
||||||
|
forwardMockError map[string]error
|
||||||
|
expression string
|
||||||
|
expected types.Bool
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
addr: "8.8.8.8",
|
||||||
|
reverseMockReturn: []string{"dns.google."},
|
||||||
|
forwardMockReturn: map[string][]string{"dns.google": {"8.8.8.8", "8.8.4.4"}},
|
||||||
|
expression: `verifyFCrDNS("8.8.8.8")`,
|
||||||
|
expected: types.Bool(true),
|
||||||
|
description: "should return true for valid FCrDNS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failure",
|
||||||
|
addr: "1.2.3.4",
|
||||||
|
reverseMockReturn: []string{"spoofed.example.com."},
|
||||||
|
forwardMockReturn: map[string][]string{"spoofed.example.com": {"5.6.7.8"}},
|
||||||
|
expression: `verifyFCrDNS("1.2.3.4")`,
|
||||||
|
expected: types.Bool(false),
|
||||||
|
description: "should return false for invalid FCrDNS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reverse-lookup-fails",
|
||||||
|
addr: "1.1.1.1",
|
||||||
|
reverseMockError: errors.New("reverse lookup failed"),
|
||||||
|
expression: `verifyFCrDNS("1.1.1.1")`,
|
||||||
|
expected: types.Bool(false),
|
||||||
|
description: "should return false if reverse lookup fails",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success-with-pattern",
|
||||||
|
addr: "8.8.8.8",
|
||||||
|
reverseMockReturn: []string{"dns.google."},
|
||||||
|
forwardMockReturn: map[string][]string{"dns.google": {"8.8.8.8"}},
|
||||||
|
expression: `verifyFCrDNS("8.8.8.8", "dns.google")`,
|
||||||
|
expected: types.Bool(true),
|
||||||
|
description: "should return true for valid FCrDNS with matching pattern",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failure-with-pattern",
|
||||||
|
addr: "8.8.8.8",
|
||||||
|
reverseMockReturn: []string{"dns.google."},
|
||||||
|
forwardMockReturn: map[string][]string{"dns.google": {"8.8.8.8"}},
|
||||||
|
expression: `verifyFCrDNS("8.8.8.8", "wrong.pattern")`,
|
||||||
|
expected: types.Bool(false),
|
||||||
|
description: "should return false for FCrDNS with non-matching pattern",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
dns.DNSLookupAddr = func(addr string) ([]string, error) {
|
||||||
|
if addr == tt.addr {
|
||||||
|
return tt.reverseMockReturn, tt.reverseMockError
|
||||||
|
}
|
||||||
|
return nil, errors.New("unexpected address for reverse lookup")
|
||||||
|
}
|
||||||
|
dns.DNSLookupHost = func(host string) ([]string, error) {
|
||||||
|
host = strings.TrimSuffix(host, ".")
|
||||||
|
if ips, ok := tt.forwardMockReturn[host]; ok {
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
if err, ok := tt.forwardMockError[host]; ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, &net.DNSError{IsNotFound: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
prog, err := Compile(env, tt.expression)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _, err := prog.Eval(map[string]interface{}{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to evaluate expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
if result.Equal(tt.expected) != types.True {
|
||||||
|
t.Errorf("%s: expected %v, got %v", tt.description, tt.expected, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("arpaReverseIP", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expression string
|
||||||
|
expected types.String
|
||||||
|
description string
|
||||||
|
evalError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ipv4",
|
||||||
|
expression: `arpaReverseIP("1.2.3.4")`,
|
||||||
|
expected: types.String("4.3.2.1"),
|
||||||
|
description: "should correctly reverse an IPv4 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ipv6",
|
||||||
|
expression: `arpaReverseIP("2001:db8::1")`,
|
||||||
|
expected: types.String("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2"),
|
||||||
|
description: "should correctly reverse an IPv6 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ipv6-full",
|
||||||
|
expression: `arpaReverseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")`,
|
||||||
|
expected: types.String("4.3.3.7.0.7.3.0.e.2.a.8.0.0.0.0.0.0.0.0.3.a.5.8.8.b.d.0.1.0.0.2"),
|
||||||
|
description: "should correctly reverse a fully expanded IPv6 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ipv6-loopback",
|
||||||
|
expression: `arpaReverseIP("::1")`,
|
||||||
|
expected: types.String("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"),
|
||||||
|
description: "should correctly reverse the IPv6 loopback address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid-ip",
|
||||||
|
expression: `arpaReverseIP("not-an-ip")`,
|
||||||
|
evalError: true,
|
||||||
|
description: "should error on an invalid IP",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
prog, err := Compile(env, tt.expression)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, _, err := prog.Eval(map[string]interface{}{})
|
||||||
|
if tt.evalError {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("%s: expected an evaluation error, but got none", tt.description)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to evaluate expression %q: %v", tt.expression, err)
|
||||||
|
}
|
||||||
|
if result.Equal(tt.expected) != types.True {
|
||||||
|
t.Errorf("%s: expected %v, got %v", tt.description, tt.expected, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestThresholdEnvironment(t *testing.T) {
|
func TestThresholdEnvironment(t *testing.T) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
|
"github.com/TecharoHQ/anubis/internal/dns"
|
||||||
"github.com/TecharoHQ/anubis/lib/config"
|
"github.com/TecharoHQ/anubis/lib/config"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/checker"
|
"github.com/TecharoHQ/anubis/lib/policy/checker"
|
||||||
"github.com/TecharoHQ/anubis/lib/store"
|
"github.com/TecharoHQ/anubis/lib/store"
|
||||||
@@ -42,6 +43,8 @@ type ParsedConfig struct {
|
|||||||
StatusCodes config.StatusCodes
|
StatusCodes config.StatusCodes
|
||||||
DefaultDifficulty int
|
DefaultDifficulty int
|
||||||
DNSBL bool
|
DNSBL bool
|
||||||
|
DnsCache *dns.DnsCache
|
||||||
|
Dns *dns.Dns
|
||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +69,45 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
result := newParsedConfig(c)
|
result := newParsedConfig(c)
|
||||||
result.DefaultDifficulty = defaultDifficulty
|
result.DefaultDifficulty = defaultDifficulty
|
||||||
|
|
||||||
|
if c.Logging.Level != nil {
|
||||||
|
logLevel = c.Logging.Level.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.Logging.Sink {
|
||||||
|
case config.LogSinkStdio:
|
||||||
|
result.Logger = internal.InitSlog(logLevel, os.Stderr)
|
||||||
|
case config.LogSinkFile:
|
||||||
|
out := &logrotate.Logger{
|
||||||
|
Filename: c.Logging.Parameters.Filename,
|
||||||
|
FilenameTimeFormat: time.RFC3339,
|
||||||
|
MaxBytes: c.Logging.Parameters.MaxBytes,
|
||||||
|
MaxAge: c.Logging.Parameters.MaxAge,
|
||||||
|
MaxBackups: c.Logging.Parameters.MaxBackups,
|
||||||
|
LocalTime: c.Logging.Parameters.UseLocalTime,
|
||||||
|
Compress: c.Logging.Parameters.Compress,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Logger = internal.InitSlog(logLevel, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
lg := result.Logger.With("at", "config-validate")
|
||||||
|
|
||||||
|
stFac, ok := store.Get(c.Store.Backend)
|
||||||
|
switch ok {
|
||||||
|
case true:
|
||||||
|
store, err := stFac.Build(ctx, c.Store.Parameters)
|
||||||
|
if err != nil {
|
||||||
|
validationErrs = append(validationErrs, err)
|
||||||
|
} else {
|
||||||
|
result.Store = store
|
||||||
|
}
|
||||||
|
case false:
|
||||||
|
validationErrs = append(validationErrs, config.ErrUnknownStoreBackend)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.DnsCache = dns.NewDNSCache(result.orig.DNSTTL.Forward, result.orig.DNSTTL.Reverse, result.Store)
|
||||||
|
result.Dns = dns.New(ctx, result.DnsCache)
|
||||||
|
|
||||||
for _, b := range c.Bots {
|
for _, b := range c.Bots {
|
||||||
if berr := b.Valid(); berr != nil {
|
if berr := b.Valid(); berr != nil {
|
||||||
validationErrs = append(validationErrs, berr)
|
validationErrs = append(validationErrs, berr)
|
||||||
@@ -116,7 +158,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b.Expression != nil {
|
if b.Expression != nil {
|
||||||
c, err := NewCELChecker(b.Expression)
|
c, err := NewCELChecker(b.Expression, result.Dns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s expressions: %w", b.Name, err))
|
validationErrs = append(validationErrs, fmt.Errorf("while processing rule %s expressions: %w", b.Name, err))
|
||||||
} else {
|
} else {
|
||||||
@@ -126,7 +168,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
|
|
||||||
if b.ASNs != nil {
|
if b.ASNs != nil {
|
||||||
if !hasThothClient {
|
if !hasThothClient {
|
||||||
slog.Warn("You have specified a Thoth specific check but you have no Thoth client configured. Please read https://anubis.techaro.lol/docs/admin/thoth for more information", "check", "asn", "settings", b.ASNs)
|
lg.Warn("You have specified a Thoth specific check but you have no Thoth client configured. Please read https://anubis.techaro.lol/docs/admin/thoth for more information", "check", "asn", "settings", b.ASNs)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +177,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
|
|
||||||
if b.GeoIP != nil {
|
if b.GeoIP != nil {
|
||||||
if !hasThothClient {
|
if !hasThothClient {
|
||||||
slog.Warn("You have specified a Thoth specific check but you have no Thoth client configured. Please read https://anubis.techaro.lol/docs/admin/thoth for more information", "check", "geoip", "settings", b.GeoIP)
|
lg.Warn("You have specified a Thoth specific check but you have no Thoth client configured. Please read https://anubis.techaro.lol/docs/admin/thoth for more information", "check", "geoip", "settings", b.GeoIP)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +187,6 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
if b.Challenge == nil {
|
if b.Challenge == nil {
|
||||||
parsedBot.Challenge = &config.ChallengeRules{
|
parsedBot.Challenge = &config.ChallengeRules{
|
||||||
Difficulty: defaultDifficulty,
|
Difficulty: defaultDifficulty,
|
||||||
ReportAs: defaultDifficulty,
|
|
||||||
Algorithm: "fast",
|
Algorithm: "fast",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -155,7 +196,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
}
|
}
|
||||||
|
|
||||||
if parsedBot.Challenge.Algorithm == "slow" {
|
if parsedBot.Challenge.Algorithm == "slow" {
|
||||||
slog.Warn("use of deprecated algorithm \"slow\" detected, please update this to \"fast\" when possible", "name", parsedBot.Name)
|
lg.Warn("use of deprecated algorithm \"slow\" detected, please update this to \"fast\" when possible", "name", parsedBot.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,17 +213,20 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
|
|
||||||
for _, t := range c.Thresholds {
|
for _, t := range c.Thresholds {
|
||||||
if t.Challenge != nil && t.Challenge.Algorithm == "slow" {
|
if t.Challenge != nil && t.Challenge.Algorithm == "slow" {
|
||||||
slog.Warn("use of deprecated algorithm \"slow\" detected, please update this to \"fast\" when possible", "name", t.Name)
|
lg.Warn("use of deprecated algorithm \"slow\" detected, please update this to \"fast\" when possible", "name", t.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Challenge != nil && t.Challenge.ReportAs != 0 {
|
||||||
|
lg.Warn("use of deprecated report_as setting detected, please remove this from your policy file when possible", "name", t.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Name == "legacy-anubis-behaviour" && t.Expression.String() == "true" {
|
if t.Name == "legacy-anubis-behaviour" && t.Expression.String() == "true" {
|
||||||
if !warnedAboutThresholds.Load() {
|
if !warnedAboutThresholds.Load() {
|
||||||
slog.Warn("configuration file does not contain thresholds, see docs for details on how to upgrade", "fname", fname, "docs_url", "https://anubis.techaro.lol/docs/admin/configuration/thresholds/")
|
lg.Warn("configuration file does not contain thresholds, see docs for details on how to upgrade", "fname", fname, "docs_url", "https://anubis.techaro.lol/docs/admin/configuration/thresholds/")
|
||||||
warnedAboutThresholds.Store(true)
|
warnedAboutThresholds.Store(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Challenge.Difficulty = defaultDifficulty
|
t.Challenge.Difficulty = defaultDifficulty
|
||||||
t.Challenge.ReportAs = defaultDifficulty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
threshold, err := ParsedThresholdFromConfig(t)
|
threshold, err := ParsedThresholdFromConfig(t)
|
||||||
@@ -194,40 +238,6 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
|
|||||||
result.Thresholds = append(result.Thresholds, threshold)
|
result.Thresholds = append(result.Thresholds, threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
stFac, ok := store.Get(c.Store.Backend)
|
|
||||||
switch ok {
|
|
||||||
case true:
|
|
||||||
store, err := stFac.Build(ctx, c.Store.Parameters)
|
|
||||||
if err != nil {
|
|
||||||
validationErrs = append(validationErrs, err)
|
|
||||||
} else {
|
|
||||||
result.Store = store
|
|
||||||
}
|
|
||||||
case false:
|
|
||||||
validationErrs = append(validationErrs, config.ErrUnknownStoreBackend)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Logging.Level != nil {
|
|
||||||
logLevel = c.Logging.Level.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c.Logging.Sink {
|
|
||||||
case config.LogSinkStdio:
|
|
||||||
result.Logger = internal.InitSlog(logLevel, os.Stderr)
|
|
||||||
case config.LogSinkFile:
|
|
||||||
out := &logrotate.Logger{
|
|
||||||
Filename: c.Logging.Parameters.Filename,
|
|
||||||
FilenameTimeFormat: time.RFC3339,
|
|
||||||
MaxBytes: c.Logging.Parameters.MaxBytes,
|
|
||||||
MaxAge: c.Logging.Parameters.MaxAge,
|
|
||||||
MaxBackups: c.Logging.Parameters.MaxBackups,
|
|
||||||
LocalTime: c.Logging.Parameters.UseLocalTime,
|
|
||||||
Compress: c.Logging.Parameters.Compress,
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Logger = internal.InitSlog(logLevel, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(validationErrs) > 0 {
|
if len(validationErrs) > 0 {
|
||||||
return nil, fmt.Errorf("errors validating policy config JSON %s: %w", fname, errors.Join(validationErrs...))
|
return nil, fmt.Errorf("errors validating policy config JSON %s: %w", fname, errors.Join(validationErrs...))
|
||||||
}
|
}
|
||||||
|
|||||||
1
lib/testdata/invalid-challenge-method.yaml
vendored
1
lib/testdata/invalid-challenge-method.yaml
vendored
@@ -4,5 +4,4 @@ bots:
|
|||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
difficulty: 16
|
difficulty: 16
|
||||||
report_as: 4
|
|
||||||
algorithm: hunter2 # invalid algorithm
|
algorithm: hunter2 # invalid algorithm
|
||||||
|
|||||||
1
lib/testdata/test_config.yaml
vendored
1
lib/testdata/test_config.yaml
vendored
@@ -42,4 +42,3 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 1
|
difficulty: 1
|
||||||
report_as: 1
|
|
||||||
|
|||||||
1
lib/testdata/zero_difficulty.yaml
vendored
1
lib/testdata/zero_difficulty.yaml
vendored
@@ -42,4 +42,3 @@ thresholds:
|
|||||||
challenge:
|
challenge:
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
difficulty: 0
|
difficulty: 0
|
||||||
report_as: 0
|
|
||||||
|
|||||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@techaro/anubis",
|
"name": "@techaro/anubis",
|
||||||
"version": "1.23.1",
|
"version": "1.24.0-pre1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@techaro/anubis",
|
"name": "@techaro/anubis",
|
||||||
"version": "1.23.1",
|
"version": "1.24.0-pre1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
"@aws-crypto/sha256-js": "^5.2.0",
|
||||||
@@ -712,6 +712,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.19",
|
"baseline-browser-mapping": "^2.8.19",
|
||||||
"caniuse-lite": "^1.0.30001751",
|
"caniuse-lite": "^1.0.30001751",
|
||||||
@@ -1517,7 +1518,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
@@ -2611,6 +2611,7 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@techaro/anubis",
|
"name": "@techaro/anubis",
|
||||||
"version": "1.23.1",
|
"version": "1.24.0-pre1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
41
test/go.mod
41
test/go.mod
@@ -18,23 +18,24 @@ require (
|
|||||||
github.com/TecharoHQ/thoth-proto v0.5.0 // indirect
|
github.com/TecharoHQ/thoth-proto v0.5.0 // indirect
|
||||||
github.com/a-h/templ v0.3.960 // indirect
|
github.com/a-h/templ v0.3.960 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.40.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.32.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 // indirect
|
||||||
github.com/aws/smithy-go v1.23.2 // indirect
|
github.com/aws/smithy-go v1.23.2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
@@ -73,18 +74,18 @@ require (
|
|||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.67.2 // indirect
|
github.com/prometheus/common v0.67.2 // indirect
|
||||||
github.com/prometheus/procfs v0.19.2 // indirect
|
github.com/prometheus/procfs v0.19.2 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.16.0 // indirect
|
github.com/redis/go-redis/v9 v9.17.0 // indirect
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a // indirect
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a // indirect
|
||||||
github.com/shirou/gopsutil/v4 v4.25.10 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.10 // indirect
|
||||||
github.com/stoewer/go-strcase v1.3.1 // indirect
|
github.com/stoewer/go-strcase v1.3.1 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.etcd.io/bbolt v1.4.3 // indirect
|
go.etcd.io/bbolt v1.4.3 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/net v0.47.0 // indirect
|
||||||
@@ -92,7 +93,7 @@ require (
|
|||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.31.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect
|
||||||
google.golang.org/grpc v1.76.0 // indirect
|
google.golang.org/grpc v1.77.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gotest.tools/v3 v3.5.2 // indirect
|
gotest.tools/v3 v3.5.2 // indirect
|
||||||
k8s.io/apimachinery v0.34.2 // indirect
|
k8s.io/apimachinery v0.34.2 // indirect
|
||||||
|
|||||||
94
test/go.sum
94
test/go.sum
@@ -16,40 +16,42 @@ github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM=
|
|||||||
github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
|
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20 h1:/jWF4Wu90EhKCgjTdy1DGxcbcbNrjfBHvksEL79tfQc=
|
github.com/aws/aws-sdk-go-v2/config v1.32.1 h1:iODUDLgk3q8/flEC7ymhmxjfoAnBDwEEYEVyKZ9mzjU=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.31.20/go.mod h1:95Hh1Tc5VYKL9NJ7tAkDcqeKt+MCXQB1hQZaRdJIZE0=
|
github.com/aws/aws-sdk-go-v2/config v1.32.1/go.mod h1:xoAgo17AGrPpJBSLg81W+ikM0cpOZG8ad04T2r+d5P0=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24 h1:iJ2FmPT35EaIB0+kMa6TnQ+PwG5A1prEdAw+PsMzfHg=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1 h1:JeW+EwmtTE0yXFK8SmklrFh/cGTTXsQJumgMZNlbxfM=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.24/go.mod h1:U91+DrfjAiXPDEGYhh/x29o4p0qHX5HDqG7y5VViv64=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.1/go.mod h1:BOoXiStwTF+fT2XufhO0Efssbi1CNIO/ZXpZu87N0pw=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 h1:ITi7qiDSv/mSGDSWNpZ4k4Ve0DQR6Ug2SJQ8zEHoDXg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14/go.mod h1:k1xtME53H1b6YpZt74YmwlONMWf4ecM+lut1WQLAF/U=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 h1:Hjkh7kE6D81PgrHlE/m9gx+4TyyeLHuY8xJs7yXN5C4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4/go.mod h1:455WPHSwaGj2waRSpQp7TsnpOnBfw8iDfPfbwl7KPJE=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5/go.mod h1:nPRXgyCfAurhyaTMoBMwRBYBhaHI4lNPAnJmjM0Tslc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 h1:FzQE21lNtUor0Fb7QNgnEyiRCBlolLTX/Z1j65S7teM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14/go.mod h1:s1ydyWG9pm3ZwmmYN21HKyG9WzAZhYVW85wMHs5FV6w=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2 h1:DhdbtDl4FdNlj31+xiRXANxEE+eC7n8JQz+/ilwQ8Uc=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0 h1:8FshVvnV2sr9kOSAbOnc/vwVmmAwMjOedKH6JW2ddPM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.2/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.0/go.mod h1:wYNqY3L02Z3IgRYxOBPH9I1zD9Cjh9hI5QOy/eOjQvw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1 h1:BDgIUYGEo5TkayOWv/oBLPphWwNm/A91AebUjAu5L5g=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.1/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4 h1:U//SlnkE1wOQiIImxzdY5PXat4Wq+8rlfVEw4Y7J8as=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.4/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 h1:HK5ON3KmQV2HcAunnx4sKLB9aPf3gKGwVAf7xnx0QT0=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9 h1:LU8S9W/mPDAU9q0FjCLi0TrCheLMGwzbRpvUMwYspcA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.40.2/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.9/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1 h1:GdGmKtG+/Krag7VfyOXV17xjTCz0i9NT+JnqLTOI5nA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.1/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso=
|
||||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@@ -189,10 +191,10 @@ github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyA
|
|||||||
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko=
|
||||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
|
github.com/redis/go-redis/v9 v9.17.0 h1:K6E+ZlYN95KSMmZeEQPbU/c++wfmEvfFB17yEAq/VhM=
|
||||||
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
github.com/redis/go-redis/v9 v9.17.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM=
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM=
|
||||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
|
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
|
||||||
github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA=
|
github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA=
|
||||||
@@ -219,24 +221,24 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
|
||||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -269,8 +271,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:
|
|||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ bots:
|
|||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
difficulty: 2
|
difficulty: 2
|
||||||
report_as: 2
|
|
||||||
algorithm: fast
|
algorithm: fast
|
||||||
|
|
||||||
status_codes:
|
status_codes:
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ const t = (key) => translations[`js_${key}`] || translations[key] || key;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.innerHTML = `${t('calculating_difficulty')} ${rules.report_as}, `;
|
status.innerHTML = `${t('calculating_difficulty')} ${rules.difficulty}, `;
|
||||||
progress.style.display = "inline-block";
|
progress.style.display = "inline-block";
|
||||||
|
|
||||||
// the whole text, including "Speed:", as a single node, because some browsers
|
// the whole text, including "Speed:", as a single node, because some browsers
|
||||||
@@ -166,7 +166,7 @@ const t = (key) => translations[`js_${key}`] || translations[key] || key;
|
|||||||
|
|
||||||
let lastSpeedUpdate = 0;
|
let lastSpeedUpdate = 0;
|
||||||
let showingApology = false;
|
let showingApology = false;
|
||||||
const likelihood = Math.pow(16, -rules.report_as);
|
const likelihood = Math.pow(16, -rules.difficulty);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const t0 = Date.now();
|
const t0 = Date.now();
|
||||||
|
|||||||
Reference in New Issue
Block a user