mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-08 17:48:44 +00:00
Compare commits
1 Commits
Xe/contrib
...
Xe/remove-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1313a24d0b |
@@ -2,7 +2,9 @@
|
|||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
|
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
|
||||||
{
|
{
|
||||||
"name": "Dev",
|
"name": "Dev",
|
||||||
"dockerComposeFile": ["./docker-compose.yaml"],
|
"dockerComposeFile": [
|
||||||
|
"./docker-compose.yaml"
|
||||||
|
],
|
||||||
"service": "workspace",
|
"service": "workspace",
|
||||||
"workspaceFolder": "/workspace/anubis",
|
"workspaceFolder": "/workspace/anubis",
|
||||||
"postStartCommand": "bash ./.devcontainer/poststart.sh",
|
"postStartCommand": "bash ./.devcontainer/poststart.sh",
|
||||||
@@ -21,12 +23,7 @@
|
|||||||
"a-h.templ",
|
"a-h.templ",
|
||||||
"redhat.vscode-yaml",
|
"redhat.vscode-yaml",
|
||||||
"streetsidesoftware.code-spell-checker"
|
"streetsidesoftware.code-spell-checker"
|
||||||
],
|
]
|
||||||
"settings": {
|
|
||||||
"chat.instructionsFilesLocations": {
|
|
||||||
".github/copilot-instructions.md": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,3 +1,2 @@
|
|||||||
patreon: cadey
|
patreon: cadey
|
||||||
github: xe
|
github: xe
|
||||||
liberapay: Xe
|
|
||||||
|
|||||||
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,60 +0,0 @@
|
|||||||
name: Bug report
|
|
||||||
description: Create a report to help us improve
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
id: description-of-bug
|
|
||||||
attributes:
|
|
||||||
label: Describe the bug
|
|
||||||
description: A clear and concise description of what the bug is.
|
|
||||||
placeholder: I can reliably get an error when...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: steps-to-reproduce
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce
|
|
||||||
description: |
|
|
||||||
Steps to reproduce the behavior.
|
|
||||||
placeholder: |
|
|
||||||
1. Go to the following url...
|
|
||||||
2. Click on...
|
|
||||||
3. You get the following error: ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: expected-behavior
|
|
||||||
attributes:
|
|
||||||
label: Expected behavior
|
|
||||||
description: |
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
Ideally also describe *why* you expect it to happen.
|
|
||||||
placeholder: Instead of displaying an error, it would...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: version-os
|
|
||||||
attributes:
|
|
||||||
label: Your operating system and its version.
|
|
||||||
description: Unsure? Visit https://whatsmyos.com/
|
|
||||||
placeholder: Android 13
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: version-browser
|
|
||||||
attributes:
|
|
||||||
label: Your browser and its version.
|
|
||||||
description: Unsure? Visit https://www.whatsmybrowser.org/
|
|
||||||
placeholder: Firefox 142
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: additional-context
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add any other context about the problem here.
|
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Security
|
|
||||||
url: https://techaro.lol/contact
|
|
||||||
about: Do not file security reports here. Email security@techaro.lol.
|
|
||||||
39
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
39
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -1,39 +0,0 @@
|
|||||||
name: Feature request
|
|
||||||
description: Suggest an idea for this project
|
|
||||||
title: "[Feature request] "
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
id: description-of-bug
|
|
||||||
attributes:
|
|
||||||
label: Is your feature request related to a problem? Please describe.
|
|
||||||
description: A clear and concise description of what the problem is that made you submit this report.
|
|
||||||
placeholder: I am always frustrated, when...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: description-of-solution
|
|
||||||
attributes:
|
|
||||||
label: Solution you would like.
|
|
||||||
description: A clear and concise description of what you want to happen.
|
|
||||||
placeholder: Instead of behaving like this, there should be...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: alternatives
|
|
||||||
attributes:
|
|
||||||
label: Describe alternatives you have considered.
|
|
||||||
description: A clear and concise description of any alternative solutions or features you have considered.
|
|
||||||
placeholder: Another workaround that would work, is...
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: additional-context
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add any other context (such as mock-ups, proof of concepts or screenshots) about the feature request here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -9,4 +9,3 @@ Checklist:
|
|||||||
- [ ] Added a description of the changes to the `[Unreleased]` section of docs/docs/CHANGELOG.md
|
- [ ] Added a description of the changes to the `[Unreleased]` section of docs/docs/CHANGELOG.md
|
||||||
- [ ] Added test cases to [the relevant parts of the codebase](https://anubis.techaro.lol/docs/developer/code-quality)
|
- [ ] Added test cases to [the relevant parts of the codebase](https://anubis.techaro.lol/docs/developer/code-quality)
|
||||||
- [ ] Ran integration tests `npm run test:integration` (unsupported on Windows, please use WSL)
|
- [ ] Ran integration tests `npm run test:integration` (unsupported on Windows, please use WSL)
|
||||||
- [ ] All of my commits have [verified signatures](https://anubis.techaro.lol/docs/developer/signed-commits)
|
|
||||||
|
|||||||
24
.github/actions/spelling/README.md
vendored
24
.github/actions/spelling/README.md
vendored
@@ -1,17 +1,17 @@
|
|||||||
# check-spelling/check-spelling configuration
|
# check-spelling/check-spelling configuration
|
||||||
|
|
||||||
| File | Purpose | Format | Info |
|
File | Purpose | Format | Info
|
||||||
| -------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
-|-|-|-
|
||||||
| [dictionary.txt](dictionary.txt) | Replacement dictionary (creating this file will override the default dictionary) | one word per line | [dictionary](https://github.com/check-spelling/check-spelling/wiki/Configuration#dictionary) |
|
[dictionary.txt](dictionary.txt) | Replacement dictionary (creating this file will override the default dictionary) | one word per line | [dictionary](https://github.com/check-spelling/check-spelling/wiki/Configuration#dictionary)
|
||||||
| [allow.txt](allow.txt) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow) |
|
[allow.txt](allow.txt) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
|
||||||
| [reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject) |
|
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
|
||||||
| [excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes) |
|
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
|
||||||
| [only.txt](only.txt) | Only check matching files (applied after excludes) | perl regular expression | [only](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-only) |
|
[only.txt](only.txt) | Only check matching files (applied after excludes) | perl regular expression | [only](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-only)
|
||||||
| [patterns.txt](patterns.txt) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) |
|
[patterns.txt](patterns.txt) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||||
| [candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns) |
|
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
|
||||||
| [line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) |
|
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||||
| [expect.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect) |
|
[expect.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
|
||||||
| [advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice) |
|
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
|
||||||
|
|
||||||
Note: you can replace any of these files with a directory by the same name (minus the suffix)
|
Note: you can replace any of these files with a directory by the same name (minus the suffix)
|
||||||
and then include multiple files inside that directory (with that suffix) to merge multiple files together.
|
and then include multiple files inside that directory (with that suffix) to merge multiple files together.
|
||||||
|
|||||||
19
.github/actions/spelling/advice.md
vendored
19
.github/actions/spelling/advice.md
vendored
@@ -2,27 +2,30 @@
|
|||||||
<details><summary>If the flagged items are :exploding_head: false positives</summary>
|
<details><summary>If the flagged items are :exploding_head: false positives</summary>
|
||||||
|
|
||||||
If items relate to a ...
|
If items relate to a ...
|
||||||
|
* binary file (or some other file you wouldn't want to check at all).
|
||||||
- binary file (or some other file you wouldn't want to check at all).
|
|
||||||
|
|
||||||
Please add a file path to the `excludes.txt` file matching the containing file.
|
Please add a file path to the `excludes.txt` file matching the containing file.
|
||||||
|
|
||||||
File paths are Perl 5 Regular Expressions - you can [test](https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
|
File paths are Perl 5 Regular Expressions - you can [test](
|
||||||
|
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
|
||||||
|
|
||||||
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](../tree/HEAD/README.md) (on whichever branch you're using).
|
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
|
||||||
|
../tree/HEAD/README.md) (on whichever branch you're using).
|
||||||
|
|
||||||
- well-formed pattern.
|
* well-formed pattern.
|
||||||
|
|
||||||
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
|
If you can write a [pattern](
|
||||||
|
https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
|
||||||
|
) that would match it,
|
||||||
try adding it to the `patterns.txt` file.
|
try adding it to the `patterns.txt` file.
|
||||||
|
|
||||||
Patterns are Perl 5 Regular Expressions - you can [test](https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
|
Patterns are Perl 5 Regular Expressions - you can [test](
|
||||||
|
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
|
||||||
|
|
||||||
Note that patterns can't match multiline strings.
|
Note that patterns can't match multiline strings.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<!-- adoption information-->
|
<!-- adoption information-->
|
||||||
|
|
||||||
:steam_locomotive: If you're seeing this message and your PR is from a branch that doesn't have check-spelling,
|
:steam_locomotive: If you're seeing this message and your PR is from a branch that doesn't have check-spelling,
|
||||||
please merge to your PR's base branch to get the version configured for your repository.
|
please merge to your PR's base branch to get the version configured for your repository.
|
||||||
|
|||||||
19
.github/actions/spelling/allow.txt
vendored
19
.github/actions/spelling/allow.txt
vendored
@@ -5,22 +5,3 @@ ubuntu
|
|||||||
workarounds
|
workarounds
|
||||||
rjack
|
rjack
|
||||||
msgbox
|
msgbox
|
||||||
xeact
|
|
||||||
ABee
|
|
||||||
tencent
|
|
||||||
maintnotifications
|
|
||||||
azurediamond
|
|
||||||
cooldown
|
|
||||||
verifyfcrdns
|
|
||||||
Spintax
|
|
||||||
spintax
|
|
||||||
clampip
|
|
||||||
pseudoprofound
|
|
||||||
reimagining
|
|
||||||
iocaine
|
|
||||||
admins
|
|
||||||
fout
|
|
||||||
iplist
|
|
||||||
NArg
|
|
||||||
blocklists
|
|
||||||
rififi
|
|
||||||
|
|||||||
11
.github/actions/spelling/excludes.txt
vendored
11
.github/actions/spelling/excludes.txt
vendored
@@ -87,14 +87,9 @@
|
|||||||
^docs/docs/user/known-instances.md$
|
^docs/docs/user/known-instances.md$
|
||||||
^docs/manifest/.*$
|
^docs/manifest/.*$
|
||||||
^docs/static/\.nojekyll$
|
^docs/static/\.nojekyll$
|
||||||
^internal/glob/glob_test.go$
|
|
||||||
^internal/honeypot/naive/affirmations\.txt$
|
|
||||||
^internal/honeypot/naive/spintext\.txt$
|
|
||||||
^internal/honeypot/naive/titles\.txt$
|
|
||||||
^lib/config/testdata/bad/unparseable\.json$
|
|
||||||
^lib/localization/.*_test.go$
|
|
||||||
^lib/localization/locales/.*\.json$
|
|
||||||
^lib/policy/config/testdata/bad/unparseable\.json$
|
^lib/policy/config/testdata/bad/unparseable\.json$
|
||||||
^test/.*$
|
|
||||||
ignore$
|
ignore$
|
||||||
robots.txt
|
robots.txt
|
||||||
|
^lib/localization/locales/.*\.json$
|
||||||
|
^lib/localization/.*_test.go$
|
||||||
|
^test/.*$
|
||||||
|
|||||||
74
.github/actions/spelling/expect.txt
vendored
74
.github/actions/spelling/expect.txt
vendored
@@ -1,19 +1,12 @@
|
|||||||
acs
|
acs
|
||||||
Actorified
|
|
||||||
actorifiedstore
|
|
||||||
actorify
|
|
||||||
Aibrew
|
Aibrew
|
||||||
alibaba
|
|
||||||
alrest
|
alrest
|
||||||
amazonbot
|
amazonbot
|
||||||
anthro
|
anthro
|
||||||
anubis
|
anubis
|
||||||
anubistest
|
anubistest
|
||||||
apnic
|
|
||||||
APNICRANDNETAU
|
|
||||||
Applebot
|
Applebot
|
||||||
archlinux
|
archlinux
|
||||||
arpa
|
|
||||||
asnc
|
asnc
|
||||||
asnchecker
|
asnchecker
|
||||||
asns
|
asns
|
||||||
@@ -24,7 +17,6 @@ badregexes
|
|||||||
bbolt
|
bbolt
|
||||||
bdba
|
bdba
|
||||||
berr
|
berr
|
||||||
bezier
|
|
||||||
bingbot
|
bingbot
|
||||||
Bitcoin
|
Bitcoin
|
||||||
bitrate
|
bitrate
|
||||||
@@ -37,7 +29,6 @@ botstopper
|
|||||||
BPort
|
BPort
|
||||||
Brightbot
|
Brightbot
|
||||||
broked
|
broked
|
||||||
buildah
|
|
||||||
byteslice
|
byteslice
|
||||||
Bytespider
|
Bytespider
|
||||||
cachebuster
|
cachebuster
|
||||||
@@ -64,17 +55,14 @@ ckie
|
|||||||
cloudflare
|
cloudflare
|
||||||
Codespaces
|
Codespaces
|
||||||
confd
|
confd
|
||||||
|
connnection
|
||||||
containerbuild
|
containerbuild
|
||||||
containerregistry
|
|
||||||
coreutils
|
coreutils
|
||||||
Cotoyogi
|
Cotoyogi
|
||||||
Cromite
|
Cromite
|
||||||
crt
|
crt
|
||||||
Cscript
|
Cscript
|
||||||
daemonizing
|
daemonizing
|
||||||
databento
|
|
||||||
dayjob
|
|
||||||
dco
|
|
||||||
DDOS
|
DDOS
|
||||||
Debian
|
Debian
|
||||||
debrpm
|
debrpm
|
||||||
@@ -87,13 +75,11 @@ distros
|
|||||||
dnf
|
dnf
|
||||||
dnsbl
|
dnsbl
|
||||||
dnserr
|
dnserr
|
||||||
DNSTTL
|
|
||||||
domainhere
|
domainhere
|
||||||
dracula
|
dracula
|
||||||
dronebl
|
dronebl
|
||||||
droneblresponse
|
droneblresponse
|
||||||
dropin
|
dropin
|
||||||
dsilence
|
|
||||||
duckduckbot
|
duckduckbot
|
||||||
eerror
|
eerror
|
||||||
ellenjoe
|
ellenjoe
|
||||||
@@ -109,13 +95,9 @@ externalfetcher
|
|||||||
extldflags
|
extldflags
|
||||||
facebookgo
|
facebookgo
|
||||||
Factset
|
Factset
|
||||||
fahedouch
|
|
||||||
fastcgi
|
fastcgi
|
||||||
FCr
|
|
||||||
fcrdns
|
|
||||||
fediverse
|
fediverse
|
||||||
ffprobe
|
ffprobe
|
||||||
financials
|
|
||||||
finfos
|
finfos
|
||||||
Firecrawl
|
Firecrawl
|
||||||
flagenv
|
flagenv
|
||||||
@@ -130,12 +112,9 @@ geoip
|
|||||||
geoipchecker
|
geoipchecker
|
||||||
gha
|
gha
|
||||||
GHSA
|
GHSA
|
||||||
Ghz
|
|
||||||
gipc
|
gipc
|
||||||
gitea
|
gitea
|
||||||
GLM
|
|
||||||
godotenv
|
godotenv
|
||||||
goimports
|
|
||||||
goland
|
goland
|
||||||
gomod
|
gomod
|
||||||
goodbot
|
goodbot
|
||||||
@@ -146,25 +125,20 @@ goyaml
|
|||||||
GPG
|
GPG
|
||||||
GPT
|
GPT
|
||||||
gptbot
|
gptbot
|
||||||
Graphene
|
|
||||||
grpcprom
|
grpcprom
|
||||||
grw
|
grw
|
||||||
gzw
|
|
||||||
Hashcash
|
Hashcash
|
||||||
hashrate
|
hashrate
|
||||||
headermap
|
headermap
|
||||||
healthcheck
|
healthcheck
|
||||||
healthz
|
healthz
|
||||||
hec
|
hec
|
||||||
helpdesk
|
|
||||||
Hetzner
|
|
||||||
hmc
|
hmc
|
||||||
homelab
|
|
||||||
hostable
|
hostable
|
||||||
htmlc
|
htmlc
|
||||||
htmx
|
htmx
|
||||||
httpdebug
|
httpdebug
|
||||||
huawei
|
Huawei
|
||||||
hypertext
|
hypertext
|
||||||
iaskspider
|
iaskspider
|
||||||
iaso
|
iaso
|
||||||
@@ -173,8 +147,6 @@ ifm
|
|||||||
Imagesift
|
Imagesift
|
||||||
imgproxy
|
imgproxy
|
||||||
impressum
|
impressum
|
||||||
inbox
|
|
||||||
ingressed
|
|
||||||
inp
|
inp
|
||||||
internets
|
internets
|
||||||
IPTo
|
IPTo
|
||||||
@@ -201,14 +173,13 @@ lcj
|
|||||||
ldflags
|
ldflags
|
||||||
letsencrypt
|
letsencrypt
|
||||||
Lexentale
|
Lexentale
|
||||||
lfc
|
|
||||||
lgbt
|
lgbt
|
||||||
licend
|
licend
|
||||||
licstart
|
licstart
|
||||||
lightpanda
|
lightpanda
|
||||||
limsa
|
limsa
|
||||||
Linting
|
Linting
|
||||||
listor
|
linuxbrew
|
||||||
LLU
|
LLU
|
||||||
loadbalancer
|
loadbalancer
|
||||||
lol
|
lol
|
||||||
@@ -222,43 +193,31 @@ metrix
|
|||||||
mimi
|
mimi
|
||||||
Minfilia
|
Minfilia
|
||||||
mistralai
|
mistralai
|
||||||
mnt
|
|
||||||
Mojeek
|
Mojeek
|
||||||
mojeekbot
|
mojeekbot
|
||||||
mozilla
|
mozilla
|
||||||
myclient
|
|
||||||
mymaster
|
|
||||||
mypass
|
|
||||||
myuser
|
|
||||||
nbf
|
nbf
|
||||||
nepeat
|
nepeat
|
||||||
netsurf
|
netsurf
|
||||||
nginx
|
nginx
|
||||||
nicksnyder
|
nicksnyder
|
||||||
nikandfor
|
|
||||||
nobots
|
nobots
|
||||||
NONINFRINGEMENT
|
NONINFRINGEMENT
|
||||||
nosleep
|
nosleep
|
||||||
nullglob
|
|
||||||
oci
|
|
||||||
OCOB
|
OCOB
|
||||||
ogtag
|
ogtag
|
||||||
oklch
|
|
||||||
omgili
|
omgili
|
||||||
omgilibot
|
omgilibot
|
||||||
openai
|
openai
|
||||||
opendns
|
|
||||||
opengraph
|
opengraph
|
||||||
openrc
|
openrc
|
||||||
oswald
|
oswald
|
||||||
pag
|
pag
|
||||||
pagegen
|
|
||||||
palemoon
|
palemoon
|
||||||
Pangu
|
Pangu
|
||||||
parseable
|
parseable
|
||||||
passthrough
|
passthrough
|
||||||
Patreon
|
Patreon
|
||||||
perplexitybot
|
|
||||||
pgrep
|
pgrep
|
||||||
phrik
|
phrik
|
||||||
pidfile
|
pidfile
|
||||||
@@ -267,7 +226,6 @@ pipefail
|
|||||||
pki
|
pki
|
||||||
podkova
|
podkova
|
||||||
podman
|
podman
|
||||||
Postgre
|
|
||||||
poststart
|
poststart
|
||||||
prebaked
|
prebaked
|
||||||
privkey
|
privkey
|
||||||
@@ -284,23 +242,20 @@ qwantbot
|
|||||||
rac
|
rac
|
||||||
rawler
|
rawler
|
||||||
rcvar
|
rcvar
|
||||||
|
rdb
|
||||||
redhat
|
redhat
|
||||||
redir
|
redir
|
||||||
redirectscheme
|
redirectscheme
|
||||||
refactors
|
refactors
|
||||||
remoteip
|
|
||||||
reputational
|
reputational
|
||||||
Rhul
|
|
||||||
risc
|
risc
|
||||||
ruleset
|
ruleset
|
||||||
runlevels
|
runlevels
|
||||||
RUnlock
|
RUnlock
|
||||||
runtimedir
|
runtimedir
|
||||||
runtimedirectory
|
runtimedirectory
|
||||||
Ryzen
|
|
||||||
sas
|
sas
|
||||||
sasl
|
sasl
|
||||||
screenshots
|
|
||||||
searchbot
|
searchbot
|
||||||
searx
|
searx
|
||||||
sebest
|
sebest
|
||||||
@@ -310,16 +265,12 @@ Seo
|
|||||||
setsebool
|
setsebool
|
||||||
shellcheck
|
shellcheck
|
||||||
shirou
|
shirou
|
||||||
shoneypot
|
|
||||||
shopt
|
|
||||||
Sidetrade
|
Sidetrade
|
||||||
simprint
|
simprint
|
||||||
sitemap
|
sitemap
|
||||||
sls
|
sls
|
||||||
sni
|
sni
|
||||||
snipster
|
|
||||||
Spambot
|
Spambot
|
||||||
spammer
|
|
||||||
sparkline
|
sparkline
|
||||||
spyderbot
|
spyderbot
|
||||||
srv
|
srv
|
||||||
@@ -334,12 +285,10 @@ SVCNAME
|
|||||||
tagline
|
tagline
|
||||||
tarballs
|
tarballs
|
||||||
tarrif
|
tarrif
|
||||||
taviso
|
|
||||||
tbn
|
tbn
|
||||||
tbr
|
tbr
|
||||||
techaro
|
techaro
|
||||||
techarohq
|
techarohq
|
||||||
telegrambot
|
|
||||||
templ
|
templ
|
||||||
templruntime
|
templruntime
|
||||||
testarea
|
testarea
|
||||||
@@ -350,7 +299,6 @@ Tik
|
|||||||
Timpibot
|
Timpibot
|
||||||
TLog
|
TLog
|
||||||
traefik
|
traefik
|
||||||
trunc
|
|
||||||
uberspace
|
uberspace
|
||||||
Unbreak
|
Unbreak
|
||||||
unbreakdocker
|
unbreakdocker
|
||||||
@@ -364,27 +312,22 @@ Varis
|
|||||||
Velen
|
Velen
|
||||||
vendored
|
vendored
|
||||||
vhosts
|
vhosts
|
||||||
vkbot
|
|
||||||
VKE
|
VKE
|
||||||
vnd
|
|
||||||
VPS
|
|
||||||
Vultr
|
Vultr
|
||||||
WAIFU
|
|
||||||
weblate
|
weblate
|
||||||
webmaster
|
webmaster
|
||||||
webpage
|
webpage
|
||||||
websecure
|
websecure
|
||||||
websites
|
websites
|
||||||
Webzio
|
Webzio
|
||||||
whois
|
|
||||||
wildbase
|
wildbase
|
||||||
withthothmock
|
withthothmock
|
||||||
wolfbeast
|
wolfbeast
|
||||||
wordpress
|
wordpress
|
||||||
workaround
|
Workaround
|
||||||
workdir
|
workdir
|
||||||
wpbot
|
wpbot
|
||||||
XCircle
|
Xeact
|
||||||
xeiaso
|
xeiaso
|
||||||
xeserv
|
xeserv
|
||||||
xesite
|
xesite
|
||||||
@@ -393,18 +336,15 @@ xff
|
|||||||
XForwarded
|
XForwarded
|
||||||
XNG
|
XNG
|
||||||
XOB
|
XOB
|
||||||
XOriginal
|
|
||||||
XReal
|
XReal
|
||||||
Y'shtola
|
|
||||||
yae
|
yae
|
||||||
YAMLTo
|
YAMLTo
|
||||||
Yda
|
|
||||||
yeet
|
yeet
|
||||||
yeetfile
|
yeetfile
|
||||||
yourdomain
|
yourdomain
|
||||||
|
yoursite
|
||||||
yyz
|
yyz
|
||||||
Zenos
|
Zenos
|
||||||
zizmor
|
zizmor
|
||||||
zombocom
|
zombocom
|
||||||
zos
|
zos
|
||||||
zst
|
|
||||||
|
|||||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -8,8 +8,6 @@ updates:
|
|||||||
github-actions:
|
github-actions:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
cooldown:
|
|
||||||
default-days: 7
|
|
||||||
|
|
||||||
- package-ecosystem: gomod
|
- package-ecosystem: gomod
|
||||||
directory: /
|
directory: /
|
||||||
@@ -19,8 +17,6 @@ updates:
|
|||||||
gomod:
|
gomod:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
cooldown:
|
|
||||||
default-days: 7
|
|
||||||
|
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: /
|
directory: /
|
||||||
@@ -30,5 +26,3 @@ updates:
|
|||||||
npm:
|
npm:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
cooldown:
|
|
||||||
default-days: 7
|
|
||||||
|
|||||||
72
.github/workflows/asset-verification.yml
vendored
72
.github/workflows/asset-verification.yml
vendored
@@ -1,72 +0,0 @@
|
|||||||
name: Asset Build Verification
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
asset_verification:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: build essential
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
||||||
with:
|
|
||||||
node-version: "24.11.0"
|
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
|
||||||
with:
|
|
||||||
go-version: "1.25.4"
|
|
||||||
|
|
||||||
- name: install node deps
|
|
||||||
run: |
|
|
||||||
npm ci
|
|
||||||
|
|
||||||
- name: Check for uncommitted changes before asset build
|
|
||||||
id: check-changes-before
|
|
||||||
run: |
|
|
||||||
if [[ -n $(git status --porcelain) ]]; then
|
|
||||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Fail if there are uncommitted changes before build
|
|
||||||
if: steps.check-changes-before.outputs.has_changes == 'true'
|
|
||||||
run: |
|
|
||||||
echo "There are uncommitted changes before running npm run assets"
|
|
||||||
git status
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
- name: Run asset build
|
|
||||||
run: |
|
|
||||||
npm run assets
|
|
||||||
|
|
||||||
- name: Check for uncommitted changes after asset build
|
|
||||||
id: check-changes-after
|
|
||||||
run: |
|
|
||||||
if [[ -n $(git status --porcelain) ]]; then
|
|
||||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Fail if assets generated changes
|
|
||||||
if: steps.check-changes-after.outputs.has_changes == 'true'
|
|
||||||
run: |
|
|
||||||
echo "npm run assets generated uncommitted changes. This indicates the repository has outdated generated files."
|
|
||||||
echo "Please run 'npm run assets' locally and commit the changes."
|
|
||||||
git status
|
|
||||||
git diff
|
|
||||||
exit 1
|
|
||||||
9
.github/workflows/dco-check.yaml
vendored
9
.github/workflows/dco-check.yaml
vendored
@@ -1,9 +0,0 @@
|
|||||||
name: DCO Check
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
dco_check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: tisonkun/actions-dco@f1024cd563550b5632e754df11b7d30b73be54a5 # v1.1
|
|
||||||
40
.github/workflows/docker-pr.yml
vendored
40
.github/workflows/docker-pr.yml
vendored
@@ -2,7 +2,7 @@ name: Docker image builds (pull requests)
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: [ "main" ]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOCKER_METADATA_SET_OUTPUT_ENV: "true"
|
DOCKER_METADATA_SET_OUTPUT_ENV: "true"
|
||||||
@@ -15,29 +15,39 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: build essential
|
- name: Set up Homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@main
|
||||||
|
|
||||||
|
- name: Setup Homebrew cellar cache
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/linuxbrew/.linuxbrew/Cellar
|
||||||
|
/home/linuxbrew/.linuxbrew/bin
|
||||||
|
/home/linuxbrew/.linuxbrew/etc
|
||||||
|
/home/linuxbrew/.linuxbrew/include
|
||||||
|
/home/linuxbrew/.linuxbrew/lib
|
||||||
|
/home/linuxbrew/.linuxbrew/opt
|
||||||
|
/home/linuxbrew/.linuxbrew/sbin
|
||||||
|
/home/linuxbrew/.linuxbrew/share
|
||||||
|
/home/linuxbrew/.linuxbrew/var
|
||||||
|
key: ${{ runner.os }}-go-homebrew-cellar-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-homebrew-cellar-
|
||||||
|
|
||||||
|
- name: Install Brew dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
brew bundle
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
|
||||||
with:
|
|
||||||
node-version: "24.11.0"
|
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
|
||||||
with:
|
|
||||||
go-version: "1.25.4"
|
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository }}
|
images: ghcr.io/${{ github.repository }}
|
||||||
|
|
||||||
|
|||||||
42
.github/workflows/docker.yml
vendored
42
.github/workflows/docker.yml
vendored
@@ -21,32 +21,42 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: build essential
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
|
|
||||||
- name: Set lowercase image name
|
- name: Set lowercase image name
|
||||||
run: |
|
run: |
|
||||||
echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
|
echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- name: Set up Homebrew
|
||||||
with:
|
uses: Homebrew/actions/setup-homebrew@main
|
||||||
node-version: "24.11.0"
|
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
|
||||||
with:
|
|
||||||
go-version: "1.25.4"
|
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- name: Setup Homebrew cellar cache
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/home/linuxbrew/.linuxbrew/Cellar
|
||||||
|
/home/linuxbrew/.linuxbrew/bin
|
||||||
|
/home/linuxbrew/.linuxbrew/etc
|
||||||
|
/home/linuxbrew/.linuxbrew/include
|
||||||
|
/home/linuxbrew/.linuxbrew/lib
|
||||||
|
/home/linuxbrew/.linuxbrew/opt
|
||||||
|
/home/linuxbrew/.linuxbrew/sbin
|
||||||
|
/home/linuxbrew/.linuxbrew/share
|
||||||
|
/home/linuxbrew/.linuxbrew/var
|
||||||
|
key: ${{ runner.os }}-go-homebrew-cellar-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-homebrew-cellar-
|
||||||
|
|
||||||
|
- name: Install Brew dependencies
|
||||||
|
run: |
|
||||||
|
brew bundle
|
||||||
|
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
@@ -54,7 +64,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||||
with:
|
with:
|
||||||
images: ${{ env.IMAGE }}
|
images: ${{ env.IMAGE }}
|
||||||
|
|
||||||
@@ -68,7 +78,7 @@ jobs:
|
|||||||
SLOG_LEVEL: debug
|
SLOG_LEVEL: debug
|
||||||
|
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.IMAGE }}
|
subject-name: ${{ env.IMAGE }}
|
||||||
subject-digest: ${{ steps.build.outputs.digest }}
|
subject-digest: ${{ steps.build.outputs.digest }}
|
||||||
|
|||||||
12
.github/workflows/docs-deploy.yml
vendored
12
.github/workflows/docs-deploy.yml
vendored
@@ -17,15 +17,15 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||||
|
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: techarohq
|
username: techarohq
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/techarohq/anubis/docs
|
images: ghcr.io/techarohq/anubis/docs
|
||||||
tags: |
|
tags: |
|
||||||
@@ -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@f6d776bd78f4523e36d6c74d34f9941c242b2213 # v1.35.0
|
uses: actions-hub/kubectl@b5b19eeb6a0ffde16637e398f8b96ef01eb8fdb7 # v1.33.3
|
||||||
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@f6d776bd78f4523e36d6c74d34f9941c242b2213 # v1.35.0
|
uses: actions-hub/kubectl@b5b19eeb6a0ffde16637e398f8b96ef01eb8fdb7 # v1.33.3
|
||||||
env:
|
env:
|
||||||
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
|
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
.github/workflows/docs-test.yml
vendored
6
.github/workflows/docs-test.yml
vendored
@@ -13,16 +13,16 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/techarohq/anubis/docs
|
images: ghcr.io/techarohq/anubis/docs
|
||||||
tags: |
|
tags: |
|
||||||
|
|||||||
76
.github/workflows/go-mod-tidy-check.yml
vendored
76
.github/workflows/go-mod-tidy-check.yml
vendored
@@ -1,76 +0,0 @@
|
|||||||
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.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"
|
|
||||||
43
.github/workflows/go.yml
vendored
43
.github/workflows/go.yml
vendored
@@ -2,9 +2,9 @@ name: Go
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: [ "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: [ "main" ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -24,15 +24,42 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential
|
sudo apt-get install -y build-essential
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- name: Set up Homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@main
|
||||||
|
|
||||||
|
- name: Setup Homebrew cellar cache
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
path: |
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
/home/linuxbrew/.linuxbrew/Cellar
|
||||||
|
/home/linuxbrew/.linuxbrew/bin
|
||||||
|
/home/linuxbrew/.linuxbrew/etc
|
||||||
|
/home/linuxbrew/.linuxbrew/include
|
||||||
|
/home/linuxbrew/.linuxbrew/lib
|
||||||
|
/home/linuxbrew/.linuxbrew/opt
|
||||||
|
/home/linuxbrew/.linuxbrew/sbin
|
||||||
|
/home/linuxbrew/.linuxbrew/share
|
||||||
|
/home/linuxbrew/.linuxbrew/var
|
||||||
|
key: ${{ runner.os }}-go-homebrew-cellar-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-homebrew-cellar-
|
||||||
|
|
||||||
|
- name: Install Brew dependencies
|
||||||
|
run: |
|
||||||
|
brew bundle
|
||||||
|
|
||||||
|
- name: Setup Golang caches
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.4"
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-golang-
|
||||||
|
|
||||||
- name: Cache playwright binaries
|
- name: Cache playwright binaries
|
||||||
uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
id: playwright-cache
|
id: playwright-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
19
.github/workflows/lint-pr-title.yaml
vendored
19
.github/workflows/lint-pr-title.yaml
vendored
@@ -1,19 +0,0 @@
|
|||||||
name: "Lint PR"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint_pr_title:
|
|
||||||
name: Validate PR title
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
pull-requests: read
|
|
||||||
steps:
|
|
||||||
- uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
37
.github/workflows/package-builds-stable.yml
vendored
37
.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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
@@ -25,12 +25,39 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential
|
sudo apt-get install -y build-essential
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- name: Set up Homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@main
|
||||||
|
|
||||||
|
- name: Setup Homebrew cellar cache
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
path: |
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
/home/linuxbrew/.linuxbrew/Cellar
|
||||||
|
/home/linuxbrew/.linuxbrew/bin
|
||||||
|
/home/linuxbrew/.linuxbrew/etc
|
||||||
|
/home/linuxbrew/.linuxbrew/include
|
||||||
|
/home/linuxbrew/.linuxbrew/lib
|
||||||
|
/home/linuxbrew/.linuxbrew/opt
|
||||||
|
/home/linuxbrew/.linuxbrew/sbin
|
||||||
|
/home/linuxbrew/.linuxbrew/share
|
||||||
|
/home/linuxbrew/.linuxbrew/var
|
||||||
|
key: ${{ runner.os }}-go-homebrew-cellar-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-homebrew-cellar-
|
||||||
|
|
||||||
|
- name: Install Brew dependencies
|
||||||
|
run: |
|
||||||
|
brew bundle
|
||||||
|
|
||||||
|
- name: Setup Golang caches
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.4"
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-golang-
|
||||||
|
|
||||||
- name: install node deps
|
- name: install node deps
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
43
.github/workflows/package-builds-unstable.yml
vendored
43
.github/workflows/package-builds-unstable.yml
vendored
@@ -2,9 +2,9 @@ name: Package builds (unstable)
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: [ "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: [ "main" ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
@@ -26,12 +26,39 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential
|
sudo apt-get install -y build-essential
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- name: Set up Homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@main
|
||||||
|
|
||||||
|
- name: Setup Homebrew cellar cache
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
path: |
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
/home/linuxbrew/.linuxbrew/Cellar
|
||||||
|
/home/linuxbrew/.linuxbrew/bin
|
||||||
|
/home/linuxbrew/.linuxbrew/etc
|
||||||
|
/home/linuxbrew/.linuxbrew/include
|
||||||
|
/home/linuxbrew/.linuxbrew/lib
|
||||||
|
/home/linuxbrew/.linuxbrew/opt
|
||||||
|
/home/linuxbrew/.linuxbrew/sbin
|
||||||
|
/home/linuxbrew/.linuxbrew/share
|
||||||
|
/home/linuxbrew/.linuxbrew/var
|
||||||
|
key: ${{ runner.os }}-go-homebrew-cellar-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-homebrew-cellar-
|
||||||
|
|
||||||
|
- name: Install Brew dependencies
|
||||||
|
run: |
|
||||||
|
brew bundle
|
||||||
|
|
||||||
|
- name: Setup Golang caches
|
||||||
|
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.4"
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-golang-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-golang-
|
||||||
|
|
||||||
- name: install node deps
|
- name: install node deps
|
||||||
run: |
|
run: |
|
||||||
@@ -41,7 +68,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go tool yeet
|
go tool yeet
|
||||||
|
|
||||||
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: packages
|
name: packages
|
||||||
path: var/*
|
path: var/*
|
||||||
|
|||||||
20
.github/workflows/smoke-tests.yml
vendored
20
.github/workflows/smoke-tests.yml
vendored
@@ -14,32 +14,26 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
test:
|
test:
|
||||||
- default-config-macro
|
|
||||||
- docker-registry
|
|
||||||
- double_slash
|
|
||||||
- forced-language
|
|
||||||
- git-clone
|
- git-clone
|
||||||
- git-push
|
- git-push
|
||||||
- healthcheck
|
- healthcheck
|
||||||
- i18n
|
- i18n
|
||||||
- log-file
|
|
||||||
- nginx
|
|
||||||
- palemoon/amd64
|
- palemoon/amd64
|
||||||
#- palemoon/i386
|
#- palemoon/i386
|
||||||
- robots_txt
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.0"
|
node-version: latest
|
||||||
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
|
||||||
|
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.4"
|
go-version: stable
|
||||||
|
|
||||||
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
|
||||||
|
|
||||||
@@ -57,7 +51,7 @@ jobs:
|
|||||||
run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV
|
run: echo "ARTIFACT_NAME=${{ matrix.test }}" | sed 's|/|-|g' >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: ${{ env.ARTIFACT_NAME }}
|
name: ${{ env.ARTIFACT_NAME }}
|
||||||
|
|||||||
12
.github/workflows/spelling.yml
vendored
12
.github/workflows/spelling.yml
vendored
@@ -59,16 +59,16 @@ name: Check Spelling
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "**"
|
- '**'
|
||||||
tags-ignore:
|
tags-ignore:
|
||||||
- "**"
|
- '**'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "**"
|
- '**'
|
||||||
types:
|
types:
|
||||||
- "opened"
|
- 'opened'
|
||||||
- "reopened"
|
- 'reopened'
|
||||||
- "synchronize"
|
- 'synchronize'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
spelling:
|
spelling:
|
||||||
|
|||||||
6
.github/workflows/ssh-ci-runner-cron.yml
vendored
6
.github/workflows/ssh-ci-runner-cron.yml
vendored
@@ -18,19 +18,19 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Log into registry
|
- name: Log into registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
run: |
|
run: |
|
||||||
cd ./test/ssh-ci
|
cd ./test/ssh-ci
|
||||||
|
|||||||
14
.github/workflows/ssh-ci.yml
vendored
14
.github/workflows/ssh-ci.yml
vendored
@@ -12,17 +12,15 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
ssh:
|
ssh:
|
||||||
if: github.repository == 'TecharoHQ/anubis'
|
if: github.repository == 'TecharoHQ/anubis'
|
||||||
runs-on: alrest-techarohq
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
host:
|
host:
|
||||||
- riscv64
|
- ubuntu@riscv64.techaro.lol
|
||||||
- ppc64le
|
- ci@ppc64le.techaro.lol
|
||||||
- aarch64-4k
|
|
||||||
- aarch64-16k
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -35,9 +33,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@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.25.4"
|
go-version: stable
|
||||||
|
|
||||||
- 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 }}
|
||||||
|
|||||||
10
.github/workflows/zizmor.yml
vendored
10
.github/workflows/zizmor.yml
vendored
@@ -3,10 +3,10 @@ name: zizmor
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- ".github/workflows/*.ya?ml"
|
- '.github/workflows/*.ya?ml'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- ".github/workflows/*.ya?ml"
|
- '.github/workflows/*.ya?ml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
zizmor:
|
zizmor:
|
||||||
@@ -16,12 +16,12 @@ jobs:
|
|||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
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@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
|
||||||
|
|
||||||
- name: Run zizmor 🌈
|
- name: Run zizmor 🌈
|
||||||
run: uvx zizmor --format sarif . > results.sarif
|
run: uvx zizmor --format sarif . > results.sarif
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: zizmor
|
category: zizmor
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
npx --no-install commitlint --edit "$1"
|
|
||||||
|
|
||||||
# Check if commit message contains Signed-off-by line
|
|
||||||
if ! grep -q "^Signed-off-by:" "$1"; then
|
|
||||||
echo "Commit message must contain a 'Signed-off-by:' line."
|
|
||||||
echo "Please use 'git commit --signoff' or add a Signed-off-by line to your commit message."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
npm run lint
|
|
||||||
npm run test
|
|
||||||
8
.ko.yaml
8
.ko.yaml
@@ -1,11 +1,11 @@
|
|||||||
defaultBaseImage: cgr.dev/chainguard/static
|
defaultBaseImage: cgr.dev/chainguard/static
|
||||||
defaultPlatforms:
|
defaultPlatforms:
|
||||||
- linux/arm64
|
- linux/arm64
|
||||||
- linux/amd64
|
- linux/amd64
|
||||||
- linux/arm/v7
|
- linux/arm/v7
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
- id: anubis
|
- id: anubis
|
||||||
main: ./cmd/anubis
|
main: ./cmd/anubis
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w
|
- -s -w
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
lib/config/testdata/bad/*
|
|
||||||
*.inc
|
|
||||||
144
CONTRIBUTING.md
144
CONTRIBUTING.md
@@ -1,144 +0,0 @@
|
|||||||
# Contributing to Anubis
|
|
||||||
|
|
||||||
Anubis is a Web AI Firewall Utility (WAIFU) written in Go. It uses sha256 proof-of-work challenges to protect upstream HTTP resources from scraper bots. This is security software -- correctness matters.
|
|
||||||
|
|
||||||
## Build & Run
|
|
||||||
|
|
||||||
Prerequisites: Go 1.24+, Node.js (any supported version), esbuild, gzip, zstd, brotli. Install all with `brew bundle` if you are using Homebrew.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm ci # install node dependencies
|
|
||||||
npm run assets # build JS/CSS (required before any Go build/test)
|
|
||||||
npm run build # assets + go build -> ./var/anubis
|
|
||||||
npm run dev # assets + run locally with --use-remote-address
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Run all unit tests (assets must be built first)
|
|
||||||
npm run test # or: make test
|
|
||||||
|
|
||||||
# Run a single test by name
|
|
||||||
go test -run TestClampIP ./internal/
|
|
||||||
|
|
||||||
# Run a single test file's package
|
|
||||||
go test ./lib/config/
|
|
||||||
|
|
||||||
# Run tests with verbose output
|
|
||||||
go test -v -run TestBotValid ./lib/config/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Smoke tests
|
|
||||||
|
|
||||||
The `tests` folder contains "smoke tests" that are intended to set up Anubis in production-adjacent settings and testing it against real infrastructure tools. A smoke test is a folder with `test.sh` that sets up infrastructure, validates the behaviour, and then tears it down. Smoke tests are run in GitHub actions with `.github/workflows/smoke-tests.yaml`.
|
|
||||||
|
|
||||||
## Linting
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go vet ./...
|
|
||||||
go tool staticcheck ./...
|
|
||||||
go tool govulncheck ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Generation
|
|
||||||
|
|
||||||
The project uses `go generate` for templ templates and stringer. Always run `npm run generate` (or `make assets`) before building or testing. Generated files include:
|
|
||||||
|
|
||||||
- `web/*.templ` -> templ-generated Go code
|
|
||||||
- `web/static/` -> bundled/minified JS and CSS (with .gz, .zst, .br variants)
|
|
||||||
|
|
||||||
## Project Layout
|
|
||||||
|
|
||||||
Important folders:
|
|
||||||
|
|
||||||
- `cmd/anubis`: Main entrypoint for the project. This is the program that runs on servers.
|
|
||||||
- `lib/*`: The core library for Anubis and all of its features. This is internal code that is made public for ease of downstream consumption. No API stability is guaranteed. Use at your own risk.
|
|
||||||
- `internal/*`: Actual internal code that is private to the implementation of Anubis. If you need to use a package in this, please copy it out and manually vendor it in your own project.
|
|
||||||
- `test/*` Smoke tests (see dedicated section for details).
|
|
||||||
- `web`: Frontend HTML templates.
|
|
||||||
- `xess`: Frontend CSS framework and build logic.
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
### Go
|
|
||||||
|
|
||||||
This project follows the idioms of the Go standard library. Generally follow the patterns that upstream Go uses, including:
|
|
||||||
|
|
||||||
- Prefer packages from the standard library unless there is no other option.
|
|
||||||
- Use package import aliases only when package names collide.
|
|
||||||
- Use `goimports` to format code. Run with `npm run format`.
|
|
||||||
- Use sentinel errors as package-level variables prefixed with `Err` (such as `ErrBotMustHaveName`). Wrap with `fmt.Errorf("package: small message giving context: %w", err)`.
|
|
||||||
- Use `log/slog` for structured logging. Pass loggers as arguments to functions. Use `lg.With` to preload with context. Prefer using `slog.Debug` unless you absolutely need to report messages to users, some users have magical thinking about log verbosity.
|
|
||||||
- Name PublicFunctionsAndTypes in PascalCase. Name privateFunctionsAndTypes in camelCase.
|
|
||||||
- Acronyms stay uppercase (`URL`, `HTTP`, `IP`, `DNS`, etc.)
|
|
||||||
- Enumerations should use strong types with validation logic for parsing remote input.
|
|
||||||
- Be conservative in what you send but liberal in what you accept.
|
|
||||||
- Anything reading configuration values should use both `json` and `yaml` struct tags. Use pointer values for optional configuration values.
|
|
||||||
- Use [table-driven tests](https://go.dev/wiki/TableDrivenTests) when writing test code.
|
|
||||||
- Use [`t.Helper()`](https://pkg.go.dev/testing#T.Helper) in helper code (setup/teardown scaffolding).
|
|
||||||
- Use [`t.Cleanup()`](https://pkg.go.dev/testing#T.Cleanup) to tear down per-test or per-suite scaffolding.
|
|
||||||
- Use [`errors.Is`](https://pkg.go.dev/errors#Is) for validating function results against sentinel errors.
|
|
||||||
- Prefer same-package tests over black-box tests (`_test` packages).
|
|
||||||
|
|
||||||
### JavaScript / TypeScript
|
|
||||||
|
|
||||||
- Source lives in `web/js/`. Built with esbuild, bundled and minified.
|
|
||||||
- Uses Preact (not React).
|
|
||||||
- No linter config. Keep functions small. Use `const` by default.
|
|
||||||
|
|
||||||
### Templ Templates
|
|
||||||
|
|
||||||
Anubis uses [Templ](https://templ.guide) for generating HTML on the server.
|
|
||||||
|
|
||||||
- `.templ` files in `web/` generate Go code. Run `go generate ./...` (or `npm run assets`) after modifying them.
|
|
||||||
- Templates receive typed Go parameters. Keep logic in Go, not templates.
|
|
||||||
|
|
||||||
## Commit Messages
|
|
||||||
|
|
||||||
Commit messages follow the [**Conventional Commits**](https://www.conventionalcommits.org/en/v1.0.0/) format:
|
|
||||||
|
|
||||||
```text
|
|
||||||
<type>[optional scope]: <description>
|
|
||||||
|
|
||||||
[optional body]
|
|
||||||
|
|
||||||
[optional footer(s)]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Types**: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
|
|
||||||
|
|
||||||
- Add `!` after type/scope for breaking changes or include `BREAKING CHANGE:` in the footer.
|
|
||||||
- Keep descriptions concise, imperative, lowercase, and without a trailing period.
|
|
||||||
- Reference issues/PRs in the footer when applicable.
|
|
||||||
- **ALL git commits MUST be made with `--signoff`.** This is mandatory.
|
|
||||||
|
|
||||||
### Attribution Requirements
|
|
||||||
|
|
||||||
AI agents must disclose what tool and model they are using in the "Assisted-by" commit footer:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Assisted-by: [Model Name] via [Tool Name]
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Assisted-by: GLM 4.6 via Claude Code
|
|
||||||
```
|
|
||||||
|
|
||||||
## PR Checklist
|
|
||||||
|
|
||||||
- Add description of changes to `[Unreleased]` in `docs/docs/CHANGELOG.md`.
|
|
||||||
- Add test cases for bug fixes and behavior changes.
|
|
||||||
- Run integration tests: `npm run test:integration`.
|
|
||||||
- All commits must have verified (signed) signatures.
|
|
||||||
|
|
||||||
## Key Conventions
|
|
||||||
|
|
||||||
- **Security-first**: This is security software. Code reviews are strict. Always add tests for bug fixes. Consider adversarial inputs.
|
|
||||||
- **Configuration**: YAML-based policy files. Config structs validate via `Valid() error` methods returning sentinel errors.
|
|
||||||
- **Store interface**: `lib/store.Interface` abstracts key-value storage.
|
|
||||||
- **Environment variables**: Parsed from flags via `flagenv`. Use `.env` files locally (loaded by `godotenv/autoload`). Never commit `.env` files.
|
|
||||||
- **Assets must be built first**: JS/CSS assets are embedded into the Go binary. Always run `npm run assets` before `go test` or `go build`.
|
|
||||||
- **CEL expressions**: Policy rules support CEL (Common Expression Language) expressions for advanced matching. See `lib/policy/expressions/`.
|
|
||||||
@@ -20,9 +20,6 @@ Anubis is brought to you by sponsors and donors like:
|
|||||||
<a href="https://www.raptorcs.com/content/base/products.html">
|
<a href="https://www.raptorcs.com/content/base/products.html">
|
||||||
<img src="./docs/static/img/sponsors/raptor-computing-logo.webp" alt="Raptor Computing Systems" height=64 />
|
<img src="./docs/static/img/sponsors/raptor-computing-logo.webp" alt="Raptor Computing Systems" height=64 />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://databento.com/?utm_source=anubis&utm_medium=sponsor&utm_campaign=anubis">
|
|
||||||
<img src="./docs/static/img/sponsors/databento-logo.webp" alt="Databento" height="64" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
### Gold Tier
|
### Gold Tier
|
||||||
|
|
||||||
@@ -69,7 +66,7 @@ Anubis is a bit of a nuclear response. This will result in your website being bl
|
|||||||
|
|
||||||
In most cases, you should not need this and can probably get by using Cloudflare to protect a given origin. However, for circumstances where you can't or won't use Cloudflare, Anubis is there for you.
|
In most cases, you should not need this and can probably get by using Cloudflare to protect a given origin. However, for circumstances where you can't or won't use Cloudflare, Anubis is there for you.
|
||||||
|
|
||||||
If you want to try this out, visit the Anubis documentation site at [anubis.techaro.lol](https://anubis.techaro.lol).
|
If you want to try this out, connect to [anubis.techaro.lol](https://anubis.techaro.lol).
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
|||||||
13
SECURITY.md
13
SECURITY.md
@@ -1,13 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
Techaro follows the [Semver 2.0 scheme](https://semver.org/).
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
Techaro strives to support the two most recent minor versions of Anubis. Patches to those versions will be published as patch releases.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
Email security@techaro.lol with details on the vulnerability and reproduction steps. You will get a response as soon as possible.
|
|
||||||
|
|
||||||
Please take care to send your email as a mixed plaintext and HTML message. Messages with GPG signatures or that are plaintext only may be blocked by the spam filter.
|
|
||||||
@@ -11,7 +11,7 @@ var Version = "devel"
|
|||||||
|
|
||||||
// CookieName is the name of the cookie that Anubis uses in order to validate
|
// CookieName is the name of the cookie that Anubis uses in order to validate
|
||||||
// access.
|
// access.
|
||||||
var CookieName = "techaro.lol-anubis"
|
var CookieName = "techaro.lol-anubis-auth"
|
||||||
|
|
||||||
// TestCookieName is the name of the cookie that Anubis uses in order to check
|
// TestCookieName is the name of the cookie that Anubis uses in order to check
|
||||||
// if cookies are enabled on the client's browser.
|
// if cookies are enabled on the client's browser.
|
||||||
@@ -23,9 +23,6 @@ const CookieDefaultExpirationTime = 7 * 24 * time.Hour
|
|||||||
// BasePrefix is a global prefix for all Anubis endpoints. Can be emptied to remove the prefix entirely.
|
// BasePrefix is a global prefix for all Anubis endpoints. Can be emptied to remove the prefix entirely.
|
||||||
var BasePrefix = ""
|
var BasePrefix = ""
|
||||||
|
|
||||||
// PublicUrl is the externally accessible URL for this Anubis instance.
|
|
||||||
var PublicUrl = ""
|
|
||||||
|
|
||||||
// StaticPath is the location where all static Anubis assets are located.
|
// StaticPath is the location where all static Anubis assets are located.
|
||||||
const StaticPath = "/.within.website/x/cmd/anubis/"
|
const StaticPath = "/.within.website/x/cmd/anubis/"
|
||||||
|
|
||||||
@@ -39,6 +36,3 @@ const DefaultDifficulty = 4
|
|||||||
// ForcedLanguage is the language being used instead of the one of the request's Accept-Language header
|
// ForcedLanguage is the language being used instead of the one of the request's Accept-Language header
|
||||||
// if being set.
|
// if being set.
|
||||||
var ForcedLanguage = ""
|
var ForcedLanguage = ""
|
||||||
|
|
||||||
// UseSimplifiedExplanation can be set to true for using the simplified explanation
|
|
||||||
var UseSimplifiedExplanation = false
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ import (
|
|||||||
"github.com/TecharoHQ/anubis/data"
|
"github.com/TecharoHQ/anubis/data"
|
||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
libanubis "github.com/TecharoHQ/anubis/lib"
|
libanubis "github.com/TecharoHQ/anubis/lib"
|
||||||
"github.com/TecharoHQ/anubis/lib/config"
|
|
||||||
botPolicy "github.com/TecharoHQ/anubis/lib/policy"
|
botPolicy "github.com/TecharoHQ/anubis/lib/policy"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
"github.com/TecharoHQ/anubis/lib/thoth"
|
"github.com/TecharoHQ/anubis/lib/thoth"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
"github.com/facebookgo/flagenv"
|
"github.com/facebookgo/flagenv"
|
||||||
@@ -51,12 +51,9 @@ var (
|
|||||||
cookieExpiration = flag.Duration("cookie-expiration-time", anubis.CookieDefaultExpirationTime, "The amount of time the authorization cookie is valid for")
|
cookieExpiration = flag.Duration("cookie-expiration-time", anubis.CookieDefaultExpirationTime, "The amount of time the authorization cookie is valid for")
|
||||||
cookiePrefix = flag.String("cookie-prefix", anubis.CookieName, "prefix for browser cookies created by Anubis")
|
cookiePrefix = flag.String("cookie-prefix", anubis.CookieName, "prefix for browser cookies created by Anubis")
|
||||||
cookiePartitioned = flag.Bool("cookie-partitioned", false, "if true, sets the partitioned flag on Anubis cookies, enabling CHIPS support")
|
cookiePartitioned = flag.Bool("cookie-partitioned", false, "if true, sets the partitioned flag on Anubis cookies, enabling CHIPS support")
|
||||||
difficultyInJWT = flag.Bool("difficulty-in-jwt", false, "if true, adds a difficulty field in the JWT claims")
|
|
||||||
useSimplifiedExplanation = flag.Bool("use-simplified-explanation", false, "if true, replaces the text when clicking \"Why am I seeing this?\" with a more simplified text for a non-tech-savvy audience.")
|
|
||||||
forcedLanguage = flag.String("forced-language", "", "if set, this language is being used instead of the one from the request's Accept-Language header")
|
forcedLanguage = flag.String("forced-language", "", "if set, this language is being used instead of the one from the request's Accept-Language header")
|
||||||
hs512Secret = flag.String("hs512-secret", "", "secret used to sign JWTs, uses ed25519 if not set")
|
hs512Secret = flag.String("hs512-secret", "", "secret used to sign JWTs, uses ed25519 if not set")
|
||||||
cookieSecure = flag.Bool("cookie-secure", true, "if true, sets the secure flag on Anubis cookies")
|
cookieSecure = flag.Bool("cookie-secure", true, "if true, sets the secure flag on Anubis cookies")
|
||||||
cookieSameSite = flag.String("cookie-same-site", "None", "sets the same site option on Anubis cookies, will auto-downgrade None to Lax if cookie-secure is false. Valid values are None, Lax, Strict, and Default.")
|
|
||||||
ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned")
|
ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned")
|
||||||
ed25519PrivateKeyHexFile = flag.String("ed25519-private-key-hex-file", "", "file name containing value for ed25519-private-key-hex")
|
ed25519PrivateKeyHexFile = flag.String("ed25519-private-key-hex-file", "", "file name containing value for ed25519-private-key-hex")
|
||||||
metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to")
|
metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to")
|
||||||
@@ -68,10 +65,9 @@ var (
|
|||||||
slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)")
|
slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)")
|
||||||
stripBasePrefix = flag.Bool("strip-base-prefix", false, "if true, strips the base prefix from requests forwarded to the target server")
|
stripBasePrefix = flag.Bool("strip-base-prefix", false, "if true, strips the base prefix from requests forwarded to the target server")
|
||||||
target = flag.String("target", "http://localhost:3923", "target to reverse proxy to, set to an empty string to disable proxying when only using auth request")
|
target = flag.String("target", "http://localhost:3923", "target to reverse proxy to, set to an empty string to disable proxying when only using auth request")
|
||||||
targetSNI = flag.String("target-sni", "", "if set, TLS handshake hostname when forwarding requests to the target, if set to auto, use Host header")
|
targetSNI = flag.String("target-sni", "", "if set, the value of the TLS handshake hostname when forwarding requests to the target")
|
||||||
targetHost = flag.String("target-host", "", "if set, the value of the Host header when forwarding requests to the target")
|
targetHost = flag.String("target-host", "", "if set, the value of the Host header when forwarding requests to the target")
|
||||||
targetInsecureSkipVerify = flag.Bool("target-insecure-skip-verify", false, "if true, skips TLS validation for the backend")
|
targetInsecureSkipVerify = flag.Bool("target-insecure-skip-verify", false, "if true, skips TLS validation for the backend")
|
||||||
targetDisableKeepAlive = flag.Bool("target-disable-keepalive", false, "if true, disables HTTP keep-alive for the backend")
|
|
||||||
healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis")
|
healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis")
|
||||||
useRemoteAddress = flag.Bool("use-remote-address", false, "read the client's IP address from the network request, useful for debugging and running Anubis on bare metal")
|
useRemoteAddress = flag.Bool("use-remote-address", false, "read the client's IP address from the network request, useful for debugging and running Anubis on bare metal")
|
||||||
debugBenchmarkJS = flag.Bool("debug-benchmark-js", false, "respond to every request with a challenge for benchmarking hashrate")
|
debugBenchmarkJS = flag.Bool("debug-benchmark-js", false, "respond to every request with a challenge for benchmarking hashrate")
|
||||||
@@ -83,7 +79,6 @@ var (
|
|||||||
versionFlag = flag.Bool("version", false, "print Anubis version")
|
versionFlag = flag.Bool("version", false, "print Anubis version")
|
||||||
publicUrl = flag.String("public-url", "", "the externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for forwardAuth).")
|
publicUrl = flag.String("public-url", "", "the externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for forwardAuth).")
|
||||||
xffStripPrivate = flag.Bool("xff-strip-private", true, "if set, strip private addresses from X-Forwarded-For")
|
xffStripPrivate = flag.Bool("xff-strip-private", true, "if set, strip private addresses from X-Forwarded-For")
|
||||||
customRealIPHeader = flag.String("custom-real-ip-header", "", "if set, read remote IP from header of this name (in case your environment doesn't set X-Real-IP header)")
|
|
||||||
|
|
||||||
thothInsecure = flag.Bool("thoth-insecure", false, "if set, connect to Thoth over plain HTTP/2, don't enable this unless support told you to")
|
thothInsecure = flag.Bool("thoth-insecure", false, "if set, connect to Thoth over plain HTTP/2, don't enable this unless support told you to")
|
||||||
thothURL = flag.String("thoth-url", "", "if set, URL for Thoth, the IP reputation database for Anubis")
|
thothURL = flag.String("thoth-url", "", "if set, URL for Thoth, the IP reputation database for Anubis")
|
||||||
@@ -145,22 +140,6 @@ func parseBindNetFromAddr(address string) (string, string) {
|
|||||||
return "", address
|
return "", address
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSameSite(s string) http.SameSite {
|
|
||||||
switch strings.ToLower(s) {
|
|
||||||
case "none":
|
|
||||||
return http.SameSiteNoneMode
|
|
||||||
case "lax":
|
|
||||||
return http.SameSiteLaxMode
|
|
||||||
case "strict":
|
|
||||||
return http.SameSiteStrictMode
|
|
||||||
case "default":
|
|
||||||
return http.SameSiteDefaultMode
|
|
||||||
default:
|
|
||||||
log.Fatalf("invalid cookie same-site mode: %s, valid values are None, Lax, Strict, and Default", s)
|
|
||||||
}
|
|
||||||
return http.SameSiteDefaultMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupListener(network string, address string) (net.Listener, string) {
|
func setupListener(network string, address string) (net.Listener, string) {
|
||||||
formattedAddress := ""
|
formattedAddress := ""
|
||||||
|
|
||||||
@@ -208,7 +187,7 @@ func setupListener(network string, address string) (net.Listener, string) {
|
|||||||
return listener, formattedAddress
|
return listener, formattedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeReverseProxy(target string, targetSNI string, targetHost string, insecureSkipVerify bool, targetDisableKeepAlive bool) (http.Handler, error) {
|
func makeReverseProxy(target string, targetSNI string, targetHost string, insecureSkipVerify bool) (http.Handler, error) {
|
||||||
targetUri, err := url.Parse(target)
|
targetUri, err := url.Parse(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse target URL: %w", err)
|
return nil, fmt.Errorf("failed to parse target URL: %w", err)
|
||||||
@@ -216,10 +195,6 @@ func makeReverseProxy(target string, targetSNI string, targetHost string, insecu
|
|||||||
|
|
||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
|
||||||
if targetDisableKeepAlive {
|
|
||||||
transport.DisableKeepAlives = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/oauth2-proxy/oauth2-proxy/blob/4e2100a2879ef06aea1411790327019c1a09217c/pkg/upstream/http.go#L124
|
// https://github.com/oauth2-proxy/oauth2-proxy/blob/4e2100a2879ef06aea1411790327019c1a09217c/pkg/upstream/http.go#L124
|
||||||
if targetUri.Scheme == "unix" {
|
if targetUri.Scheme == "unix" {
|
||||||
// clean path up so we don't use the socket path in proxied requests
|
// clean path up so we don't use the socket path in proxied requests
|
||||||
@@ -236,29 +211,24 @@ func makeReverseProxy(target string, targetSNI string, targetHost string, insecu
|
|||||||
|
|
||||||
if insecureSkipVerify || targetSNI != "" {
|
if insecureSkipVerify || targetSNI != "" {
|
||||||
transport.TLSClientConfig = &tls.Config{}
|
transport.TLSClientConfig = &tls.Config{}
|
||||||
}
|
|
||||||
if insecureSkipVerify {
|
if insecureSkipVerify {
|
||||||
slog.Warn("TARGET_INSECURE_SKIP_VERIFY is set to true, TLS certificate validation will not be performed", "target", target)
|
slog.Warn("TARGET_INSECURE_SKIP_VERIFY is set to true, TLS certificate validation will not be performed", "target", target)
|
||||||
transport.TLSClientConfig.InsecureSkipVerify = true
|
transport.TLSClientConfig.InsecureSkipVerify = true
|
||||||
}
|
}
|
||||||
if targetSNI != "" && targetSNI != "auto" {
|
if targetSNI != "" {
|
||||||
transport.TLSClientConfig.ServerName = targetSNI
|
transport.TLSClientConfig.ServerName = targetSNI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rp := httputil.NewSingleHostReverseProxy(targetUri)
|
rp := httputil.NewSingleHostReverseProxy(targetUri)
|
||||||
rp.Transport = transport
|
rp.Transport = transport
|
||||||
|
|
||||||
if targetHost != "" || targetSNI == "auto" {
|
if targetHost != "" {
|
||||||
originalDirector := rp.Director
|
originalDirector := rp.Director
|
||||||
rp.Director = func(req *http.Request) {
|
rp.Director = func(req *http.Request) {
|
||||||
originalDirector(req)
|
originalDirector(req)
|
||||||
if targetHost != "" {
|
|
||||||
req.Host = targetHost
|
req.Host = targetHost
|
||||||
}
|
}
|
||||||
if targetSNI == "auto" {
|
|
||||||
transport.TLSClientConfig.ServerName = req.Host
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rp, nil
|
return rp, nil
|
||||||
@@ -273,11 +243,9 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal.InitSlog(*slogLevel)
|
||||||
internal.SetHealth("anubis", healthv1.HealthCheckResponse_NOT_SERVING)
|
internal.SetHealth("anubis", healthv1.HealthCheckResponse_NOT_SERVING)
|
||||||
|
|
||||||
lg := internal.InitSlog(*slogLevel, os.Stderr)
|
|
||||||
lg.Info("starting up Anubis")
|
|
||||||
|
|
||||||
if *healthcheck {
|
if *healthcheck {
|
||||||
log.Println("running healthcheck")
|
log.Println("running healthcheck")
|
||||||
if err := doHealthCheck(); err != nil {
|
if err := doHealthCheck(); err != nil {
|
||||||
@@ -305,14 +273,14 @@ func main() {
|
|||||||
|
|
||||||
if *metricsBind != "" {
|
if *metricsBind != "" {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go metricsServer(ctx, *lg.With("subsystem", "metrics"), wg.Done)
|
go metricsServer(ctx, wg.Done)
|
||||||
}
|
}
|
||||||
|
|
||||||
var rp http.Handler
|
var rp http.Handler
|
||||||
// when using anubis via Systemd and environment variables, then it is not possible to set targe to an empty string but only to space
|
// when using anubis via Systemd and environment variables, then it is not possible to set targe to an empty string but only to space
|
||||||
if strings.TrimSpace(*target) != "" {
|
if strings.TrimSpace(*target) != "" {
|
||||||
var err error
|
var err error
|
||||||
rp, err = makeReverseProxy(*target, *targetSNI, *targetHost, *targetInsecureSkipVerify, *targetDisableKeepAlive)
|
rp, err = makeReverseProxy(*target, *targetSNI, *targetHost, *targetInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't make reverse proxy: %v", err)
|
log.Fatalf("can't make reverse proxy: %v", err)
|
||||||
}
|
}
|
||||||
@@ -325,11 +293,11 @@ func main() {
|
|||||||
// Thoth configuration
|
// Thoth configuration
|
||||||
switch {
|
switch {
|
||||||
case *thothURL != "" && *thothToken == "":
|
case *thothURL != "" && *thothToken == "":
|
||||||
lg.Warn("THOTH_URL is set but no THOTH_TOKEN is set")
|
slog.Warn("THOTH_URL is set but no THOTH_TOKEN is set")
|
||||||
case *thothURL == "" && *thothToken != "":
|
case *thothURL == "" && *thothToken != "":
|
||||||
lg.Warn("THOTH_TOKEN is set but no THOTH_URL is set")
|
slog.Warn("THOTH_TOKEN is set but no THOTH_URL is set")
|
||||||
case *thothURL != "" && *thothToken != "":
|
case *thothURL != "" && *thothToken != "":
|
||||||
lg.Debug("connecting to Thoth")
|
slog.Debug("connecting to Thoth")
|
||||||
thothClient, err := thoth.New(ctx, *thothURL, *thothToken, *thothInsecure)
|
thothClient, err := thoth.New(ctx, *thothURL, *thothToken, *thothInsecure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't dial thoth at %s: %v", *thothURL, err)
|
log.Fatalf("can't dial thoth at %s: %v", *thothURL, err)
|
||||||
@@ -338,24 +306,10 @@ func main() {
|
|||||||
ctx = thoth.With(ctx, thothClient)
|
ctx = thoth.With(ctx, thothClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
lg.Info("loading policy file", "fname", *policyFname)
|
policy, err := libanubis.LoadPoliciesOrDefault(ctx, *policyFname, *challengeDifficulty)
|
||||||
policy, err := libanubis.LoadPoliciesOrDefault(ctx, *policyFname, *challengeDifficulty, *slogLevel)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't parse policy file: %v", err)
|
log.Fatalf("can't parse policy file: %v", err)
|
||||||
}
|
}
|
||||||
lg = policy.Logger
|
|
||||||
lg.Debug("swapped to new logger")
|
|
||||||
slog.SetDefault(lg)
|
|
||||||
|
|
||||||
// Warn if persistent storage is used without a configured signing key
|
|
||||||
if policy.Store.IsPersistent() {
|
|
||||||
if *hs512Secret == "" && *ed25519PrivateKeyHex == "" && *ed25519PrivateKeyHexFile == "" {
|
|
||||||
lg.Warn("[misconfiguration] persistent storage backend is configured, but no private key is set. " +
|
|
||||||
"Challenges will be invalidated when Anubis restarts. " +
|
|
||||||
"Set HS512_SECRET, ED25519_PRIVATE_KEY_HEX, or ED25519_PRIVATE_KEY_HEX_FILE to ensure challenges survive service restarts. " +
|
|
||||||
"See: https://anubis.techaro.lol/docs/admin/installation#key-generation")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ruleErrorIDs := make(map[string]string)
|
ruleErrorIDs := make(map[string]string)
|
||||||
for _, rule := range policy.Bots {
|
for _, rule := range policy.Bots {
|
||||||
@@ -413,7 +367,7 @@ func main() {
|
|||||||
log.Fatalf("failed to generate ed25519 key: %v", err)
|
log.Fatalf("failed to generate ed25519 key: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lg.Warn("generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation")
|
slog.Warn("generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation")
|
||||||
}
|
}
|
||||||
|
|
||||||
var redirectDomainsList []string
|
var redirectDomainsList []string
|
||||||
@@ -427,13 +381,12 @@ func main() {
|
|||||||
redirectDomainsList = append(redirectDomainsList, strings.TrimSpace(domain))
|
redirectDomainsList = append(redirectDomainsList, strings.TrimSpace(domain))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lg.Warn("REDIRECT_DOMAINS is not set, Anubis will only redirect to the same domain a request is coming from, see https://anubis.techaro.lol/docs/admin/configuration/redirect-domains")
|
slog.Warn("REDIRECT_DOMAINS is not set, Anubis will only redirect to the same domain a request is coming from, see https://anubis.techaro.lol/docs/admin/configuration/redirect-domains")
|
||||||
}
|
}
|
||||||
|
|
||||||
anubis.CookieName = *cookiePrefix + "-auth"
|
anubis.CookieName = *cookiePrefix + "-auth"
|
||||||
anubis.TestCookieName = *cookiePrefix + "-cookie-verification"
|
anubis.TestCookieName = *cookiePrefix + "-cookie-verification"
|
||||||
anubis.ForcedLanguage = *forcedLanguage
|
anubis.ForcedLanguage = *forcedLanguage
|
||||||
anubis.UseSimplifiedExplanation = *useSimplifiedExplanation
|
|
||||||
|
|
||||||
// If OpenGraph configuration values are not set in the config file, use the
|
// If OpenGraph configuration values are not set in the config file, use the
|
||||||
// values from flags / envvars.
|
// values from flags / envvars.
|
||||||
@@ -449,9 +402,6 @@ func main() {
|
|||||||
StripBasePrefix: *stripBasePrefix,
|
StripBasePrefix: *stripBasePrefix,
|
||||||
Next: rp,
|
Next: rp,
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
TargetHost: *targetHost,
|
|
||||||
TargetSNI: *targetSNI,
|
|
||||||
TargetInsecureSkipVerify: *targetInsecureSkipVerify,
|
|
||||||
ServeRobotsTXT: *robotsTxt,
|
ServeRobotsTXT: *robotsTxt,
|
||||||
ED25519PrivateKey: ed25519Priv,
|
ED25519PrivateKey: ed25519Priv,
|
||||||
HS512Secret: []byte(*hs512Secret),
|
HS512Secret: []byte(*hs512Secret),
|
||||||
@@ -464,11 +414,8 @@ func main() {
|
|||||||
WebmasterEmail: *webmasterEmail,
|
WebmasterEmail: *webmasterEmail,
|
||||||
OpenGraph: policy.OpenGraph,
|
OpenGraph: policy.OpenGraph,
|
||||||
CookieSecure: *cookieSecure,
|
CookieSecure: *cookieSecure,
|
||||||
CookieSameSite: parseSameSite(*cookieSameSite),
|
|
||||||
PublicUrl: *publicUrl,
|
PublicUrl: *publicUrl,
|
||||||
JWTRestrictionHeader: *jwtRestrictionHeader,
|
JWTRestrictionHeader: *jwtRestrictionHeader,
|
||||||
Logger: policy.Logger.With("subsystem", "anubis"),
|
|
||||||
DifficultyInJWT: *difficultyInJWT,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't construct libanubis.Server: %v", err)
|
log.Fatalf("can't construct libanubis.Server: %v", err)
|
||||||
@@ -476,7 +423,6 @@ func main() {
|
|||||||
|
|
||||||
var h http.Handler
|
var h http.Handler
|
||||||
h = s
|
h = s
|
||||||
h = internal.CustomRealIPHeader(*customRealIPHeader, h)
|
|
||||||
h = internal.RemoteXRealIP(*useRemoteAddress, *bindNetwork, h)
|
h = internal.RemoteXRealIP(*useRemoteAddress, *bindNetwork, h)
|
||||||
h = internal.XForwardedForToXRealIP(h)
|
h = internal.XForwardedForToXRealIP(h)
|
||||||
h = internal.XForwardedForUpdate(*xffStripPrivate, h)
|
h = internal.XForwardedForUpdate(*xffStripPrivate, h)
|
||||||
@@ -484,7 +430,7 @@ func main() {
|
|||||||
|
|
||||||
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
|
srv := http.Server{Handler: h, ErrorLog: internal.GetFilteredHTTPLogger()}
|
||||||
listener, listenerUrl := setupListener(*bindNetwork, *bind)
|
listener, listenerUrl := setupListener(*bindNetwork, *bind)
|
||||||
lg.Info(
|
slog.Info(
|
||||||
"listening",
|
"listening",
|
||||||
"url", listenerUrl,
|
"url", listenerUrl,
|
||||||
"difficulty", *challengeDifficulty,
|
"difficulty", *challengeDifficulty,
|
||||||
@@ -518,7 +464,7 @@ func main() {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func metricsServer(ctx context.Context, lg slog.Logger, done func()) {
|
func metricsServer(ctx context.Context, done func()) {
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
@@ -544,7 +490,7 @@ func metricsServer(ctx context.Context, lg slog.Logger, done func()) {
|
|||||||
|
|
||||||
srv := http.Server{Handler: mux, ErrorLog: internal.GetFilteredHTTPLogger()}
|
srv := http.Server{Handler: mux, ErrorLog: internal.GetFilteredHTTPLogger()}
|
||||||
listener, metricsUrl := setupListener(*metricsBindNetwork, *metricsBind)
|
listener, metricsUrl := setupListener(*metricsBindNetwork, *metricsBind)
|
||||||
lg.Debug("listening for metrics", "url", metricsUrl)
|
slog.Debug("listening for metrics", "url", metricsUrl)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func main() {
|
|||||||
flagenv.Parse()
|
flagenv.Parse()
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
slog.SetDefault(internal.InitSlog(*slogLevel, os.Stderr))
|
internal.InitSlog(*slogLevel)
|
||||||
|
|
||||||
koDockerRepo := strings.TrimSuffix(*dockerRepo, "/"+filepath.Base(*dockerRepo))
|
koDockerRepo := strings.TrimSuffix(*dockerRepo, "/"+filepath.Base(*dockerRepo))
|
||||||
|
|
||||||
@@ -46,11 +46,6 @@ func main() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(*dockerTags, ",") {
|
|
||||||
newTags := strings.Join(strings.Split(*dockerTags, ","), "\n")
|
|
||||||
dockerTags = &newTags
|
|
||||||
}
|
|
||||||
|
|
||||||
setOutput("docker_image", strings.SplitN(*dockerTags, "\n", 2)[0])
|
setOutput("docker_image", strings.SplitN(*dockerTags, "\n", 2)[0])
|
||||||
|
|
||||||
version, err := run("git describe --tags --always --dirty")
|
version, err := run("git describe --tags --always --dirty")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis/lib/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
@@ -29,7 +29,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RobotsRule struct {
|
type RobotsRule struct {
|
||||||
UserAgents []string
|
UserAgent string
|
||||||
Disallows []string
|
Disallows []string
|
||||||
Allows []string
|
Allows []string
|
||||||
CrawlDelay int
|
CrawlDelay int
|
||||||
@@ -130,26 +130,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRuleFromAccumulated(userAgents, disallows, allows []string, crawlDelay int) RobotsRule {
|
|
||||||
rule := RobotsRule{
|
|
||||||
UserAgents: make([]string, len(userAgents)),
|
|
||||||
Disallows: make([]string, len(disallows)),
|
|
||||||
Allows: make([]string, len(allows)),
|
|
||||||
CrawlDelay: crawlDelay,
|
|
||||||
}
|
|
||||||
copy(rule.UserAgents, userAgents)
|
|
||||||
copy(rule.Disallows, disallows)
|
|
||||||
copy(rule.Allows, allows)
|
|
||||||
return rule
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseRobotsTxt(input io.Reader) ([]RobotsRule, error) {
|
func parseRobotsTxt(input io.Reader) ([]RobotsRule, error) {
|
||||||
scanner := bufio.NewScanner(input)
|
scanner := bufio.NewScanner(input)
|
||||||
var rules []RobotsRule
|
var rules []RobotsRule
|
||||||
var currentUserAgents []string
|
var currentRule *RobotsRule
|
||||||
var currentDisallows []string
|
|
||||||
var currentAllows []string
|
|
||||||
var currentCrawlDelay int
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := strings.TrimSpace(scanner.Text())
|
line := strings.TrimSpace(scanner.Text())
|
||||||
@@ -170,42 +154,38 @@ func parseRobotsTxt(input io.Reader) ([]RobotsRule, error) {
|
|||||||
|
|
||||||
switch directive {
|
switch directive {
|
||||||
case "user-agent":
|
case "user-agent":
|
||||||
// If we have accumulated rules with directives and encounter a new user-agent,
|
// Start a new rule section
|
||||||
// flush the current rules
|
if currentRule != nil {
|
||||||
if len(currentUserAgents) > 0 && (len(currentDisallows) > 0 || len(currentAllows) > 0 || currentCrawlDelay > 0) {
|
rules = append(rules, *currentRule)
|
||||||
rule := createRuleFromAccumulated(currentUserAgents, currentDisallows, currentAllows, currentCrawlDelay)
|
}
|
||||||
rules = append(rules, rule)
|
currentRule = &RobotsRule{
|
||||||
// Reset for next group
|
UserAgent: value,
|
||||||
currentUserAgents = nil
|
Disallows: make([]string, 0),
|
||||||
currentDisallows = nil
|
Allows: make([]string, 0),
|
||||||
currentAllows = nil
|
|
||||||
currentCrawlDelay = 0
|
|
||||||
}
|
}
|
||||||
currentUserAgents = append(currentUserAgents, value)
|
|
||||||
|
|
||||||
case "disallow":
|
case "disallow":
|
||||||
if len(currentUserAgents) > 0 && value != "" {
|
if currentRule != nil && value != "" {
|
||||||
currentDisallows = append(currentDisallows, value)
|
currentRule.Disallows = append(currentRule.Disallows, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "allow":
|
case "allow":
|
||||||
if len(currentUserAgents) > 0 && value != "" {
|
if currentRule != nil && value != "" {
|
||||||
currentAllows = append(currentAllows, value)
|
currentRule.Allows = append(currentRule.Allows, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "crawl-delay":
|
case "crawl-delay":
|
||||||
if len(currentUserAgents) > 0 {
|
if currentRule != nil {
|
||||||
if delay, err := parseIntSafe(value); err == nil {
|
if delay, err := parseIntSafe(value); err == nil {
|
||||||
currentCrawlDelay = delay
|
currentRule.CrawlDelay = delay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't forget the last group of rules
|
// Don't forget the last rule
|
||||||
if len(currentUserAgents) > 0 {
|
if currentRule != nil {
|
||||||
rule := createRuleFromAccumulated(currentUserAgents, currentDisallows, currentAllows, currentCrawlDelay)
|
rules = append(rules, *currentRule)
|
||||||
rules = append(rules, rule)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark blacklisted user agents (those with "Disallow: /")
|
// Mark blacklisted user agents (those with "Disallow: /")
|
||||||
@@ -231,11 +211,10 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
var anubisRules []AnubisRule
|
var anubisRules []AnubisRule
|
||||||
ruleCounter := 0
|
ruleCounter := 0
|
||||||
|
|
||||||
// Process each robots rule individually
|
|
||||||
for _, robotsRule := range robotsRules {
|
for _, robotsRule := range robotsRules {
|
||||||
userAgents := robotsRule.UserAgents
|
userAgent := robotsRule.UserAgent
|
||||||
|
|
||||||
// Handle crawl delay
|
// Handle crawl delay as weight adjustment (do this first before any continues)
|
||||||
if robotsRule.CrawlDelay > 0 && *crawlDelay > 0 {
|
if robotsRule.CrawlDelay > 0 && *crawlDelay > 0 {
|
||||||
ruleCounter++
|
ruleCounter++
|
||||||
rule := AnubisRule{
|
rule := AnubisRule{
|
||||||
@@ -244,32 +223,20 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
Weight: &config.Weight{Adjust: *crawlDelay},
|
Weight: &config.Weight{Adjust: *crawlDelay},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(userAgents) == 1 && userAgents[0] == "*" {
|
if userAgent == "*" {
|
||||||
rule.Expression = &config.ExpressionOrList{
|
rule.Expression = &config.ExpressionOrList{
|
||||||
All: []string{"true"}, // Always applies
|
All: []string{"true"}, // Always applies
|
||||||
}
|
}
|
||||||
} else if len(userAgents) == 1 {
|
|
||||||
rule.Expression = &config.ExpressionOrList{
|
|
||||||
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgents[0])},
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Multiple user agents - use any block
|
|
||||||
var expressions []string
|
|
||||||
for _, ua := range userAgents {
|
|
||||||
if ua == "*" {
|
|
||||||
expressions = append(expressions, "true")
|
|
||||||
} else {
|
|
||||||
expressions = append(expressions, fmt.Sprintf("userAgent.contains(%q)", ua))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rule.Expression = &config.ExpressionOrList{
|
rule.Expression = &config.ExpressionOrList{
|
||||||
Any: expressions,
|
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anubisRules = append(anubisRules, rule)
|
anubisRules = append(anubisRules, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle blacklisted user agents
|
// Handle blacklisted user agents (complete deny/challenge)
|
||||||
if robotsRule.IsBlacklist {
|
if robotsRule.IsBlacklist {
|
||||||
ruleCounter++
|
ruleCounter++
|
||||||
rule := AnubisRule{
|
rule := AnubisRule{
|
||||||
@@ -277,8 +244,6 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
Action: *userAgentDeny,
|
Action: *userAgentDeny,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(userAgents) == 1 {
|
|
||||||
userAgent := userAgents[0]
|
|
||||||
if userAgent == "*" {
|
if userAgent == "*" {
|
||||||
// This would block everything - convert to a weight adjustment instead
|
// This would block everything - convert to a weight adjustment instead
|
||||||
rule.Name = fmt.Sprintf("%s-global-restriction-%d", *policyName, ruleCounter)
|
rule.Name = fmt.Sprintf("%s-global-restriction-%d", *policyName, ruleCounter)
|
||||||
@@ -292,21 +257,8 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)},
|
All: []string{fmt.Sprintf("userAgent.contains(%q)", userAgent)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Multiple user agents - use any block
|
|
||||||
var expressions []string
|
|
||||||
for _, ua := range userAgents {
|
|
||||||
if ua == "*" {
|
|
||||||
expressions = append(expressions, "true")
|
|
||||||
} else {
|
|
||||||
expressions = append(expressions, fmt.Sprintf("userAgent.contains(%q)", ua))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rule.Expression = &config.ExpressionOrList{
|
|
||||||
Any: expressions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anubisRules = append(anubisRules, rule)
|
anubisRules = append(anubisRules, rule)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle specific disallow rules
|
// Handle specific disallow rules
|
||||||
@@ -324,33 +276,9 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
// Build CEL expression
|
// Build CEL expression
|
||||||
var conditions []string
|
var conditions []string
|
||||||
|
|
||||||
// Add user agent conditions
|
// Add user agent condition if not wildcard
|
||||||
if len(userAgents) == 1 && userAgents[0] == "*" {
|
if userAgent != "*" {
|
||||||
// Wildcard user agent - no user agent condition needed
|
conditions = append(conditions, fmt.Sprintf("userAgent.contains(%q)", userAgent))
|
||||||
} else if len(userAgents) == 1 {
|
|
||||||
conditions = append(conditions, fmt.Sprintf("userAgent.contains(%q)", userAgents[0]))
|
|
||||||
} else {
|
|
||||||
// For multiple user agents, we need to use a more complex expression
|
|
||||||
// This is a limitation - we can't easily combine any for user agents with all for path
|
|
||||||
// So we'll create separate rules for each user agent
|
|
||||||
for _, ua := range userAgents {
|
|
||||||
if ua == "*" {
|
|
||||||
continue // Skip wildcard as it's handled separately
|
|
||||||
}
|
|
||||||
ruleCounter++
|
|
||||||
subRule := AnubisRule{
|
|
||||||
Name: fmt.Sprintf("%s-disallow-%d", *policyName, ruleCounter),
|
|
||||||
Action: *baseAction,
|
|
||||||
Expression: &config.ExpressionOrList{
|
|
||||||
All: []string{
|
|
||||||
fmt.Sprintf("userAgent.contains(%q)", ua),
|
|
||||||
buildPathCondition(disallow),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
anubisRules = append(anubisRules, subRule)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add path condition
|
// Add path condition
|
||||||
@@ -363,6 +291,7 @@ func convertToAnubisRules(robotsRules []RobotsRule) []AnubisRule {
|
|||||||
|
|
||||||
anubisRules = append(anubisRules, rule)
|
anubisRules = append(anubisRules, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return anubisRules
|
return anubisRules
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ type TestCase struct {
|
|||||||
type TestOptions struct {
|
type TestOptions struct {
|
||||||
format string
|
format string
|
||||||
action string
|
action string
|
||||||
|
crawlDelayWeight int
|
||||||
policyName string
|
policyName string
|
||||||
deniedAction string
|
deniedAction string
|
||||||
crawlDelayWeight int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDataFileConversion(t *testing.T) {
|
func TestDataFileConversion(t *testing.T) {
|
||||||
@@ -78,12 +78,6 @@ func TestDataFileConversion(t *testing.T) {
|
|||||||
expectedFile: "complex.yaml",
|
expectedFile: "complex.yaml",
|
||||||
options: TestOptions{format: "yaml", crawlDelayWeight: 5},
|
options: TestOptions{format: "yaml", crawlDelayWeight: 5},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "consecutive_user_agents",
|
|
||||||
robotsFile: "consecutive.robots.txt",
|
|
||||||
expectedFile: "consecutive.yaml",
|
|
||||||
options: TestOptions{format: "yaml", crawlDelayWeight: 3},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
# Test consecutive user agents that should be grouped into any: blocks
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /admin
|
|
||||||
Crawl-delay: 10
|
|
||||||
|
|
||||||
# Multiple consecutive user agents - should be grouped
|
|
||||||
User-agent: BadBot
|
|
||||||
User-agent: SpamBot
|
|
||||||
User-agent: EvilBot
|
|
||||||
Disallow: /
|
|
||||||
|
|
||||||
# Single user agent - should be separate
|
|
||||||
User-agent: GoodBot
|
|
||||||
Disallow: /private
|
|
||||||
|
|
||||||
# Multiple consecutive user agents with crawl delay
|
|
||||||
User-agent: SlowBot1
|
|
||||||
User-agent: SlowBot2
|
|
||||||
Crawl-delay: 5
|
|
||||||
|
|
||||||
# Multiple consecutive user agents with specific path
|
|
||||||
User-agent: SearchBot1
|
|
||||||
User-agent: SearchBot2
|
|
||||||
User-agent: SearchBot3
|
|
||||||
Disallow: /search
|
|
||||||
47
cmd/robots2policy/testdata/consecutive.yaml
vendored
47
cmd/robots2policy/testdata/consecutive.yaml
vendored
@@ -1,47 +0,0 @@
|
|||||||
- action: WEIGH
|
|
||||||
expression: "true"
|
|
||||||
name: robots-txt-policy-crawl-delay-1
|
|
||||||
weight:
|
|
||||||
adjust: 3
|
|
||||||
- action: CHALLENGE
|
|
||||||
expression: path.startsWith("/admin")
|
|
||||||
name: robots-txt-policy-disallow-2
|
|
||||||
- action: DENY
|
|
||||||
expression:
|
|
||||||
any:
|
|
||||||
- userAgent.contains("BadBot")
|
|
||||||
- userAgent.contains("SpamBot")
|
|
||||||
- userAgent.contains("EvilBot")
|
|
||||||
name: robots-txt-policy-blacklist-3
|
|
||||||
- action: CHALLENGE
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("GoodBot")
|
|
||||||
- path.startsWith("/private")
|
|
||||||
name: robots-txt-policy-disallow-4
|
|
||||||
- action: WEIGH
|
|
||||||
expression:
|
|
||||||
any:
|
|
||||||
- userAgent.contains("SlowBot1")
|
|
||||||
- userAgent.contains("SlowBot2")
|
|
||||||
name: robots-txt-policy-crawl-delay-5
|
|
||||||
weight:
|
|
||||||
adjust: 3
|
|
||||||
- action: CHALLENGE
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("SearchBot1")
|
|
||||||
- path.startsWith("/search")
|
|
||||||
name: robots-txt-policy-disallow-7
|
|
||||||
- action: CHALLENGE
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("SearchBot2")
|
|
||||||
- path.startsWith("/search")
|
|
||||||
name: robots-txt-policy-disallow-8
|
|
||||||
- action: CHALLENGE
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("SearchBot3")
|
|
||||||
- path.startsWith("/search")
|
|
||||||
name: robots-txt-policy-disallow-9
|
|
||||||
8
cmd/robots2policy/testdata/simple.json
vendored
8
cmd/robots2policy/testdata/simple.json
vendored
@@ -1,12 +1,12 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"action": "CHALLENGE",
|
||||||
"expression": "path.startsWith(\"/admin/\")",
|
"expression": "path.startsWith(\"/admin/\")",
|
||||||
"name": "robots-txt-policy-disallow-1",
|
"name": "robots-txt-policy-disallow-1"
|
||||||
"action": "CHALLENGE"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"action": "CHALLENGE",
|
||||||
"expression": "path.startsWith(\"/private\")",
|
"expression": "path.startsWith(\"/private\")",
|
||||||
"name": "robots-txt-policy-disallow-2",
|
"name": "robots-txt-policy-disallow-2"
|
||||||
"action": "CHALLENGE"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -3,6 +3,5 @@
|
|||||||
- name: qualys-ssl-labs
|
- name: qualys-ssl-labs
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
remote_addresses:
|
remote_addresses:
|
||||||
- 69.67.183.0/24
|
- 64.41.200.0/24
|
||||||
- 2600:C02:1020:4202::/64
|
- 2600:C02:1020:4202::/64
|
||||||
- 2602:fdaa:c6:2::/64
|
|
||||||
|
|||||||
@@ -11,12 +11,9 @@
|
|||||||
## /usr/share/docs/anubis/data or in the tarball you extracted Anubis from.
|
## /usr/share/docs/anubis/data or in the tarball you extracted Anubis from.
|
||||||
|
|
||||||
bots:
|
bots:
|
||||||
# You can import the entire default config with this macro:
|
|
||||||
# - import: (data)/meta/default-config.yaml
|
|
||||||
|
|
||||||
# Pathological bots to deny
|
# Pathological bots to deny
|
||||||
- # This correlates to data/bots/_deny-pathological.yaml in the source tree
|
- # This correlates to data/bots/deny-pathological.yaml in the source tree
|
||||||
# https://github.com/TecharoHQ/anubis/blob/main/data/bots/_deny-pathological.yaml
|
# https://github.com/TecharoHQ/anubis/blob/main/data/bots/deny-pathological.yaml
|
||||||
import: (data)/bots/_deny-pathological.yaml
|
import: (data)/bots/_deny-pathological.yaml
|
||||||
- import: (data)/bots/aggressive-brazilian-scrapers.yaml
|
- import: (data)/bots/aggressive-brazilian-scrapers.yaml
|
||||||
|
|
||||||
@@ -51,6 +48,7 @@ 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
|
||||||
|
|
||||||
# Requires a subscription to Thoth to use, see
|
# Requires a subscription to Thoth to use, see
|
||||||
@@ -204,6 +202,7 @@ 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
|
||||||
@@ -216,21 +215,13 @@ 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
|
||||||
- name: mild-proof-of-work
|
report_as: 2
|
||||||
expression:
|
# For clients that are browser like and have gained many points from custom rules
|
||||||
all:
|
- name: extreme-suspicion
|
||||||
- weight >= 20
|
expression: weight >= 20
|
||||||
- weight < 30
|
|
||||||
action: CHALLENGE
|
action: CHALLENGE
|
||||||
challenge:
|
challenge:
|
||||||
# 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
|
||||||
# For clients that are browser like and have gained many points from custom rules
|
report_as: 4
|
||||||
- name: extreme-suspicion
|
|
||||||
expression: weight >= 30
|
|
||||||
action: CHALLENGE
|
|
||||||
challenge:
|
|
||||||
# https://anubis.techaro.lol/docs/admin/configuration/challenges/proof-of-work
|
|
||||||
algorithm: fast
|
|
||||||
difficulty: 6
|
|
||||||
|
|||||||
@@ -2,5 +2,3 @@
|
|||||||
- import: (data)/bots/headless-browsers.yaml
|
- import: (data)/bots/headless-browsers.yaml
|
||||||
- import: (data)/bots/us-ai-scraper.yaml
|
- import: (data)/bots/us-ai-scraper.yaml
|
||||||
- import: (data)/bots/custom-async-http-client.yaml
|
- import: (data)/bots/custom-async-http-client.yaml
|
||||||
- import: (data)/crawlers/alibaba-cloud.yaml
|
|
||||||
- import: (data)/crawlers/huawei-cloud.yaml
|
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# CCBot is allowed because if Common Crawl is allowed, then scrapers don't need to scrape to get the data.
|
# CCBot is allowed because if Common Crawl is allowed, then scrapers don't need to scrape to get the data.
|
||||||
- name: "ai-robots-txt"
|
- name: "ai-robots-txt"
|
||||||
user_agent_regex: >-
|
user_agent_regex: >-
|
||||||
AddSearchBot|AI2Bot|Ai2Bot-Dolma|aiHitBot|Amazonbot|Andibot|anthropic-ai|Applebot|Applebot-Extended|Awario|bedrockbot|bigsur.ai|Brightbot 1.0|Bytespider|CCBot|ChatGPT Agent|ChatGPT-User|Claude-SearchBot|Claude-User|Claude-Web|ClaudeBot|CloudVertexBot|cohere-ai|cohere-training-data-crawler|Cotoyogi|Crawlspace|Datenbank Crawler|Devin|Diffbot|DuckAssistBot|Echobot Bot|EchoboxBot|FacebookBot|facebookexternalhit|Factset_spyderbot|FirecrawlAgent|FriendlyCrawler|Gemini-Deep-Research|Google-CloudVertexBot|Google-Extended|GoogleAgent-Mariner|GoogleOther|GoogleOther-Image|GoogleOther-Video|GPTBot|iaskspider/2.0|ICC-Crawler|ImagesiftBot|img2dataset|ISSCyberRiskCrawler|Kangaroo Bot|LinerBot|meta-externalagent|Meta-ExternalAgent|meta-externalfetcher|Meta-ExternalFetcher|MistralAI-User|MistralAI-User/1.0|MyCentralAIScraperBot|netEstate Imprint Crawler|NovaAct|OAI-SearchBot|omgili|omgilibot|OpenAI|Operator|PanguBot|Panscient|panscient.com|Perplexity-User|PerplexityBot|PetalBot|PhindBot|Poseidon Research Crawler|QualifiedBot|QuillBot|quillbot.com|SBIntuitionsBot|Scrapy|SemrushBot-OCOB|SemrushBot-SWA|Sidetrade indexer bot|Thinkbot|TikTokSpider|Timpibot|VelenPublicWebCrawler|WARDBot|Webzio-Extended|wpbot|YaK|YandexAdditional|YandexAdditionalBot|YouBot
|
AI2Bot|Ai2Bot-Dolma|aiHitBot|Amazonbot|Andibot|anthropic-ai|Applebot|Applebot-Extended|bedrockbot|Brightbot 1.0|Bytespider|ChatGPT-User|Claude-SearchBot|Claude-User|Claude-Web|ClaudeBot|cohere-ai|cohere-training-data-crawler|Cotoyogi|Crawlspace|Diffbot|DuckAssistBot|EchoboxBot|FacebookBot|facebookexternalhit|Factset_spyderbot|FirecrawlAgent|FriendlyCrawler|Google-CloudVertexBot|Google-Extended|GoogleOther|GoogleOther-Image|GoogleOther-Video|GPTBot|iaskspider/2.0|ICC-Crawler|ImagesiftBot|img2dataset|ISSCyberRiskCrawler|Kangaroo Bot|meta-externalagent|Meta-ExternalAgent|meta-externalfetcher|Meta-ExternalFetcher|MistralAI-User/1.0|MyCentralAIScraperBot|NovaAct|OAI-SearchBot|omgili|omgilibot|Operator|PanguBot|Panscient|panscient.com|Perplexity-User|PerplexityBot|PetalBot|PhindBot|Poseidon Research Crawler|QualifiedBot|QuillBot|quillbot.com|SBIntuitionsBot|Scrapy|SemrushBot|SemrushBot-BA|SemrushBot-CT|SemrushBot-OCOB|SemrushBot-SI|SemrushBot-SWA|Sidetrade indexer bot|TikTokSpider|Timpibot|VelenPublicWebCrawler|Webzio-Extended|wpbot|YandexAdditional|YandexAdditionalBot|YouBot
|
||||||
action: DENY
|
action: DENY
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# - Claude-User: No published IP allowlist
|
# - Claude-User: No published IP allowlist
|
||||||
- name: "ai-clients"
|
- name: "ai-clients"
|
||||||
user_agent_regex: >-
|
user_agent_regex: >-
|
||||||
ChatGPT-User|Claude-User|MistralAI-User|Perplexity-User
|
ChatGPT-User|Claude-User|MistralAI-User
|
||||||
action: DENY
|
action: DENY
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
- name: allow-docker-client
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("docker/")
|
|
||||||
- userAgent.contains("git-commit/")
|
|
||||||
- '"Accept" in headers'
|
|
||||||
- headers["Accept"].contains("vnd.docker.distribution")
|
|
||||||
- '"Baggage" in headers'
|
|
||||||
- headers["Baggage"].contains("trigger")
|
|
||||||
|
|
||||||
- name: allow-crane-client
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("crane/")
|
|
||||||
- userAgent.contains("go-containerregistry/")
|
|
||||||
|
|
||||||
- name: allow-docker-distribution-api-client
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- '"Docker-Distribution-Api-Version" in headers'
|
|
||||||
- '!(userAgent.contains("Mozilla"))'
|
|
||||||
|
|
||||||
- name: allow-go-containerregistry-client
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("go-containerregistry/")
|
|
||||||
|
|
||||||
- name: allow-buildah
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("Buildah/")
|
|
||||||
|
|
||||||
- name: allow-podman
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("containers/")
|
|
||||||
|
|
||||||
- name: allow-containerd
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("containerd/")
|
|
||||||
|
|
||||||
- name: allow-renovate
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- path.startsWith("/v2/")
|
|
||||||
- userAgent.contains("Renovate/")
|
|
||||||
@@ -10,11 +10,5 @@
|
|||||||
userAgent.startsWith("JGit/") ||
|
userAgent.startsWith("JGit/") ||
|
||||||
userAgent.startsWith("JGit-")
|
userAgent.startsWith("JGit-")
|
||||||
)
|
)
|
||||||
- '"Accept" in headers'
|
- '"Git-Protocol" in headers'
|
||||||
- headers["Accept"] == "*/*"
|
- headers["Git-Protocol"] == "version=2"
|
||||||
- '"Cache-Control" in headers'
|
|
||||||
- headers["Cache-Control"] == "no-cache"
|
|
||||||
- '"Pragma" in headers'
|
|
||||||
- headers["Pragma"] == "no-cache"
|
|
||||||
- '"Accept-Encoding" in headers'
|
|
||||||
- headers["Accept-Encoding"].contains("gzip")
|
|
||||||
@@ -4,4 +4,7 @@
|
|||||||
user_agent_regex: MistralAI-User/.+; \+https\://docs\.mistral\.ai/robots
|
user_agent_regex: MistralAI-User/.+; \+https\://docs\.mistral\.ai/robots
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://mistral.ai/mistralai-user-ips.json
|
# https://mistral.ai/mistralai-user-ips.json
|
||||||
remote_addresses: ["20.240.160.161/32", "20.240.160.1/32"]
|
remote_addresses: [
|
||||||
|
"20.240.160.161/32",
|
||||||
|
"20.240.160.1/32",
|
||||||
|
]
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://openai.com/chatgpt-user.json
|
# https://openai.com/chatgpt-user.json
|
||||||
# curl 'https://openai.com/chatgpt-user.json' | jq '.prefixes.[].ipv4Prefix' | sed 's/$/,/'
|
# curl 'https://openai.com/chatgpt-user.json' | jq '.prefixes.[].ipv4Prefix' | sed 's/$/,/'
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"13.65.138.112/28",
|
"13.65.138.112/28",
|
||||||
"23.98.179.16/28",
|
"23.98.179.16/28",
|
||||||
"13.65.138.96/28",
|
"13.65.138.96/28",
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# Acts on behalf of user requests
|
|
||||||
# https://docs.perplexity.ai/guides/bots
|
|
||||||
- name: perplexity-user
|
|
||||||
user_agent_regex: Perplexity-User/.+; \+https\://perplexity\.ai/perplexity-user
|
|
||||||
action: ALLOW
|
|
||||||
# https://www.perplexity.com/perplexity-user.json
|
|
||||||
remote_addresses:
|
|
||||||
["44.208.221.197/32", "34.193.163.52/32", "18.97.21.0/30", "18.97.43.80/29"]
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
- name: telegrambot
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.matches("TelegramBot")
|
|
||||||
- verifyFCrDNS(remoteAddress, "ptr\\.telegram\\.org$")
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
- name: vkbot
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.matches("vkShare[^+]+\\+http\\://vk\\.com/dev/Share")
|
|
||||||
- verifyFCrDNS(remoteAddress, "^snipster\\d+\\.go\\.mail\\.ru$")
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# Assert behaviour that only genuine browsers display. This ensures that modern Chrome
|
|
||||||
# or Firefox versions will get through without a challenge.
|
|
||||||
#
|
|
||||||
# These rules have been known to be bypassed by some of the worst automated scrapers.
|
|
||||||
# Use at your own risk.
|
|
||||||
|
|
||||||
- name: realistic-browser-catchall
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- '"User-Agent" in headers'
|
|
||||||
- '( userAgent.contains("Firefox") ) || ( userAgent.contains("Chrome") ) || ( userAgent.contains("Safari") )'
|
|
||||||
- '"Accept" in headers'
|
|
||||||
- '"Sec-Fetch-Dest" in headers'
|
|
||||||
- '"Sec-Fetch-Mode" in headers'
|
|
||||||
- '"Sec-Fetch-Site" in headers'
|
|
||||||
- '"Accept-Encoding" in headers'
|
|
||||||
- '( headers["Accept-Encoding"].contains("zstd") || headers["Accept-Encoding"].contains("br") )'
|
|
||||||
- '"Accept-Language" in headers'
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: -10
|
|
||||||
|
|
||||||
# The Upgrade-Insecure-Requests header is typically sent by browsers, but not always
|
|
||||||
- name: upgrade-insecure-requests
|
|
||||||
expression: '"Upgrade-Insecure-Requests" in headers'
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: -2
|
|
||||||
|
|
||||||
# Chrome should behave like Chrome
|
|
||||||
- name: chrome-is-proper
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.contains("Chrome")
|
|
||||||
- '"Sec-Ch-Ua" in headers'
|
|
||||||
- 'headers["Sec-Ch-Ua"].contains("Chromium")'
|
|
||||||
- '"Sec-Ch-Ua-Mobile" in headers'
|
|
||||||
- '"Sec-Ch-Ua-Platform" in headers'
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: -5
|
|
||||||
|
|
||||||
- name: should-have-accept
|
|
||||||
expression: '!("Accept" in headers)'
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: 5
|
|
||||||
|
|
||||||
# Generic catchall rule
|
|
||||||
- name: generic-browser
|
|
||||||
user_agent_regex: >-
|
|
||||||
Mozilla|Opera
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: 10
|
|
||||||
@@ -8,4 +8,3 @@
|
|||||||
- 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
|
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# - Claude-SearchBot: No published IP allowlist
|
# - Claude-SearchBot: No published IP allowlist
|
||||||
- name: "ai-crawlers-search"
|
- name: "ai-crawlers-search"
|
||||||
user_agent_regex: >-
|
user_agent_regex: >-
|
||||||
OAI-SearchBot|Claude-SearchBot|PerplexityBot
|
OAI-SearchBot|Claude-SearchBot
|
||||||
action: DENY
|
action: DENY
|
||||||
|
|||||||
@@ -1,881 +0,0 @@
|
|||||||
- name: alibaba-cloud
|
|
||||||
action: DENY
|
|
||||||
# Updated 2025-08-20 from IP addresses for AS45102
|
|
||||||
remote_addresses:
|
|
||||||
- 103.81.186.0/23
|
|
||||||
- 110.76.21.0/24
|
|
||||||
- 110.76.23.0/24
|
|
||||||
- 116.251.64.0/18
|
|
||||||
- 139.95.0.0/23
|
|
||||||
- 139.95.10.0/23
|
|
||||||
- 139.95.12.0/23
|
|
||||||
- 139.95.14.0/23
|
|
||||||
- 139.95.16.0/23
|
|
||||||
- 139.95.18.0/23
|
|
||||||
- 139.95.2.0/23
|
|
||||||
- 139.95.4.0/23
|
|
||||||
- 139.95.6.0/23
|
|
||||||
- 139.95.64.0/24
|
|
||||||
- 139.95.8.0/23
|
|
||||||
- 14.1.112.0/22
|
|
||||||
- 14.1.115.0/24
|
|
||||||
- 140.205.1.0/24
|
|
||||||
- 140.205.122.0/24
|
|
||||||
- 147.139.0.0/17
|
|
||||||
- 147.139.0.0/18
|
|
||||||
- 147.139.128.0/17
|
|
||||||
- 147.139.128.0/18
|
|
||||||
- 147.139.155.0/24
|
|
||||||
- 147.139.192.0/18
|
|
||||||
- 147.139.64.0/18
|
|
||||||
- 149.129.0.0/20
|
|
||||||
- 149.129.0.0/21
|
|
||||||
- 149.129.16.0/23
|
|
||||||
- 149.129.192.0/18
|
|
||||||
- 149.129.192.0/19
|
|
||||||
- 149.129.224.0/19
|
|
||||||
- 149.129.32.0/19
|
|
||||||
- 149.129.64.0/18
|
|
||||||
- 149.129.64.0/19
|
|
||||||
- 149.129.8.0/21
|
|
||||||
- 149.129.96.0/19
|
|
||||||
- 156.227.20.0/24
|
|
||||||
- 156.236.12.0/24
|
|
||||||
- 156.236.17.0/24
|
|
||||||
- 156.240.76.0/23
|
|
||||||
- 156.245.1.0/24
|
|
||||||
- 161.117.0.0/16
|
|
||||||
- 161.117.0.0/17
|
|
||||||
- 161.117.126.0/24
|
|
||||||
- 161.117.127.0/24
|
|
||||||
- 161.117.128.0/17
|
|
||||||
- 161.117.128.0/24
|
|
||||||
- 161.117.129.0/24
|
|
||||||
- 161.117.138.0/24
|
|
||||||
- 161.117.143.0/24
|
|
||||||
- 170.33.104.0/24
|
|
||||||
- 170.33.105.0/24
|
|
||||||
- 170.33.106.0/24
|
|
||||||
- 170.33.107.0/24
|
|
||||||
- 170.33.136.0/24
|
|
||||||
- 170.33.137.0/24
|
|
||||||
- 170.33.138.0/24
|
|
||||||
- 170.33.20.0/24
|
|
||||||
- 170.33.21.0/24
|
|
||||||
- 170.33.22.0/24
|
|
||||||
- 170.33.23.0/24
|
|
||||||
- 170.33.24.0/24
|
|
||||||
- 170.33.29.0/24
|
|
||||||
- 170.33.30.0/24
|
|
||||||
- 170.33.31.0/24
|
|
||||||
- 170.33.32.0/24
|
|
||||||
- 170.33.33.0/24
|
|
||||||
- 170.33.34.0/24
|
|
||||||
- 170.33.35.0/24
|
|
||||||
- 170.33.64.0/24
|
|
||||||
- 170.33.65.0/24
|
|
||||||
- 170.33.66.0/24
|
|
||||||
- 170.33.68.0/24
|
|
||||||
- 170.33.69.0/24
|
|
||||||
- 170.33.72.0/24
|
|
||||||
- 170.33.73.0/24
|
|
||||||
- 170.33.76.0/24
|
|
||||||
- 170.33.77.0/24
|
|
||||||
- 170.33.78.0/24
|
|
||||||
- 170.33.79.0/24
|
|
||||||
- 170.33.80.0/24
|
|
||||||
- 170.33.81.0/24
|
|
||||||
- 170.33.82.0/24
|
|
||||||
- 170.33.83.0/24
|
|
||||||
- 170.33.84.0/24
|
|
||||||
- 170.33.85.0/24
|
|
||||||
- 170.33.86.0/24
|
|
||||||
- 170.33.88.0/24
|
|
||||||
- 170.33.90.0/24
|
|
||||||
- 170.33.92.0/24
|
|
||||||
- 170.33.93.0/24
|
|
||||||
- 185.78.106.0/23
|
|
||||||
- 198.11.128.0/18
|
|
||||||
- 198.11.137.0/24
|
|
||||||
- 198.11.184.0/21
|
|
||||||
- 202.144.199.0/24
|
|
||||||
- 203.107.64.0/24
|
|
||||||
- 203.107.65.0/24
|
|
||||||
- 203.107.66.0/24
|
|
||||||
- 203.107.67.0/24
|
|
||||||
- 203.107.68.0/24
|
|
||||||
- 205.204.102.0/23
|
|
||||||
- 205.204.111.0/24
|
|
||||||
- 205.204.117.0/24
|
|
||||||
- 205.204.125.0/24
|
|
||||||
- 205.204.96.0/19
|
|
||||||
- 223.5.5.0/24
|
|
||||||
- 223.6.6.0/24
|
|
||||||
- 2400:3200::/48
|
|
||||||
- 2400:3200:baba::/48
|
|
||||||
- 2400:b200:4100::/48
|
|
||||||
- 2400:b200:4101::/48
|
|
||||||
- 2400:b200:4102::/48
|
|
||||||
- 2400:b200:4103::/48
|
|
||||||
- 2401:8680:4100::/48
|
|
||||||
- 2401:b180:4100::/48
|
|
||||||
- 2404:2280:1000::/36
|
|
||||||
- 2404:2280:1000::/37
|
|
||||||
- 2404:2280:1800::/37
|
|
||||||
- 2404:2280:2000::/36
|
|
||||||
- 2404:2280:2000::/37
|
|
||||||
- 2404:2280:2800::/37
|
|
||||||
- 2404:2280:3000::/36
|
|
||||||
- 2404:2280:3000::/37
|
|
||||||
- 2404:2280:3800::/37
|
|
||||||
- 2404:2280:4000::/36
|
|
||||||
- 2404:2280:4000::/37
|
|
||||||
- 2404:2280:4800::/37
|
|
||||||
- 2408:4000:1000::/48
|
|
||||||
- 2408:4009:500::/48
|
|
||||||
- 240b:4000::/32
|
|
||||||
- 240b:4000::/33
|
|
||||||
- 240b:4000:8000::/33
|
|
||||||
- 240b:4000:fffe::/48
|
|
||||||
- 240b:4001::/32
|
|
||||||
- 240b:4001::/33
|
|
||||||
- 240b:4001:8000::/33
|
|
||||||
- 240b:4002::/32
|
|
||||||
- 240b:4002::/33
|
|
||||||
- 240b:4002:8000::/33
|
|
||||||
- 240b:4004::/32
|
|
||||||
- 240b:4004::/33
|
|
||||||
- 240b:4004:8000::/33
|
|
||||||
- 240b:4005::/32
|
|
||||||
- 240b:4005::/33
|
|
||||||
- 240b:4005:8000::/33
|
|
||||||
- 240b:4006::/48
|
|
||||||
- 240b:4006:1000::/44
|
|
||||||
- 240b:4006:1000::/45
|
|
||||||
- 240b:4006:1000::/47
|
|
||||||
- 240b:4006:1002::/47
|
|
||||||
- 240b:4006:1008::/45
|
|
||||||
- 240b:4006:1010::/44
|
|
||||||
- 240b:4006:1010::/45
|
|
||||||
- 240b:4006:1018::/45
|
|
||||||
- 240b:4006:1020::/44
|
|
||||||
- 240b:4006:1020::/45
|
|
||||||
- 240b:4006:1028::/45
|
|
||||||
- 240b:4007::/32
|
|
||||||
- 240b:4007::/33
|
|
||||||
- 240b:4007:8000::/33
|
|
||||||
- 240b:4009::/32
|
|
||||||
- 240b:4009::/33
|
|
||||||
- 240b:4009:8000::/33
|
|
||||||
- 240b:400b::/32
|
|
||||||
- 240b:400b::/33
|
|
||||||
- 240b:400b:8000::/33
|
|
||||||
- 240b:400c::/32
|
|
||||||
- 240b:400c::/33
|
|
||||||
- 240b:400c::/40
|
|
||||||
- 240b:400c::/41
|
|
||||||
- 240b:400c:100::/40
|
|
||||||
- 240b:400c:100::/41
|
|
||||||
- 240b:400c:180::/41
|
|
||||||
- 240b:400c:80::/41
|
|
||||||
- 240b:400c:8000::/33
|
|
||||||
- 240b:400c:f00::/48
|
|
||||||
- 240b:400c:f01::/48
|
|
||||||
- 240b:400c:ffff::/48
|
|
||||||
- 240b:400d::/32
|
|
||||||
- 240b:400d::/33
|
|
||||||
- 240b:400d:8000::/33
|
|
||||||
- 240b:400e::/32
|
|
||||||
- 240b:400e::/33
|
|
||||||
- 240b:400e:8000::/33
|
|
||||||
- 240b:400f::/32
|
|
||||||
- 240b:400f::/33
|
|
||||||
- 240b:400f:8000::/33
|
|
||||||
- 240b:4011::/32
|
|
||||||
- 240b:4011::/33
|
|
||||||
- 240b:4011:8000::/33
|
|
||||||
- 240b:4012::/48
|
|
||||||
- 240b:4013::/32
|
|
||||||
- 240b:4013::/33
|
|
||||||
- 240b:4013:8000::/33
|
|
||||||
- 240b:4014::/32
|
|
||||||
- 240b:4014::/33
|
|
||||||
- 240b:4014:8000::/33
|
|
||||||
- 43.100.0.0/15
|
|
||||||
- 43.100.0.0/16
|
|
||||||
- 43.101.0.0/16
|
|
||||||
- 43.102.0.0/20
|
|
||||||
- 43.102.112.0/20
|
|
||||||
- 43.102.16.0/20
|
|
||||||
- 43.102.32.0/20
|
|
||||||
- 43.102.48.0/20
|
|
||||||
- 43.102.64.0/20
|
|
||||||
- 43.102.80.0/20
|
|
||||||
- 43.102.96.0/20
|
|
||||||
- 43.103.0.0/17
|
|
||||||
- 43.103.0.0/18
|
|
||||||
- 43.103.64.0/18
|
|
||||||
- 43.104.0.0/15
|
|
||||||
- 43.104.0.0/16
|
|
||||||
- 43.105.0.0/16
|
|
||||||
- 43.108.0.0/17
|
|
||||||
- 43.108.0.0/18
|
|
||||||
- 43.108.64.0/18
|
|
||||||
- 43.91.0.0/16
|
|
||||||
- 43.91.0.0/17
|
|
||||||
- 43.91.128.0/17
|
|
||||||
- 43.96.10.0/24
|
|
||||||
- 43.96.100.0/24
|
|
||||||
- 43.96.101.0/24
|
|
||||||
- 43.96.102.0/24
|
|
||||||
- 43.96.104.0/24
|
|
||||||
- 43.96.11.0/24
|
|
||||||
- 43.96.20.0/24
|
|
||||||
- 43.96.21.0/24
|
|
||||||
- 43.96.23.0/24
|
|
||||||
- 43.96.24.0/24
|
|
||||||
- 43.96.25.0/24
|
|
||||||
- 43.96.3.0/24
|
|
||||||
- 43.96.32.0/24
|
|
||||||
- 43.96.33.0/24
|
|
||||||
- 43.96.34.0/24
|
|
||||||
- 43.96.35.0/24
|
|
||||||
- 43.96.4.0/24
|
|
||||||
- 43.96.40.0/24
|
|
||||||
- 43.96.5.0/24
|
|
||||||
- 43.96.52.0/24
|
|
||||||
- 43.96.6.0/24
|
|
||||||
- 43.96.66.0/24
|
|
||||||
- 43.96.67.0/24
|
|
||||||
- 43.96.68.0/24
|
|
||||||
- 43.96.69.0/24
|
|
||||||
- 43.96.7.0/24
|
|
||||||
- 43.96.70.0/24
|
|
||||||
- 43.96.71.0/24
|
|
||||||
- 43.96.72.0/24
|
|
||||||
- 43.96.73.0/24
|
|
||||||
- 43.96.74.0/24
|
|
||||||
- 43.96.75.0/24
|
|
||||||
- 43.96.8.0/24
|
|
||||||
- 43.96.80.0/24
|
|
||||||
- 43.96.81.0/24
|
|
||||||
- 43.96.84.0/24
|
|
||||||
- 43.96.85.0/24
|
|
||||||
- 43.96.86.0/24
|
|
||||||
- 43.96.88.0/24
|
|
||||||
- 43.96.9.0/24
|
|
||||||
- 43.96.96.0/24
|
|
||||||
- 43.98.0.0/16
|
|
||||||
- 43.98.0.0/17
|
|
||||||
- 43.98.128.0/17
|
|
||||||
- 43.99.0.0/16
|
|
||||||
- 43.99.0.0/17
|
|
||||||
- 43.99.128.0/17
|
|
||||||
- 45.199.179.0/24
|
|
||||||
- 47.235.0.0/22
|
|
||||||
- 47.235.0.0/23
|
|
||||||
- 47.235.1.0/24
|
|
||||||
- 47.235.10.0/23
|
|
||||||
- 47.235.10.0/24
|
|
||||||
- 47.235.11.0/24
|
|
||||||
- 47.235.12.0/23
|
|
||||||
- 47.235.12.0/24
|
|
||||||
- 47.235.13.0/24
|
|
||||||
- 47.235.16.0/23
|
|
||||||
- 47.235.16.0/24
|
|
||||||
- 47.235.18.0/23
|
|
||||||
- 47.235.18.0/24
|
|
||||||
- 47.235.19.0/24
|
|
||||||
- 47.235.2.0/23
|
|
||||||
- 47.235.20.0/24
|
|
||||||
- 47.235.21.0/24
|
|
||||||
- 47.235.22.0/24
|
|
||||||
- 47.235.23.0/24
|
|
||||||
- 47.235.24.0/22
|
|
||||||
- 47.235.24.0/23
|
|
||||||
- 47.235.26.0/23
|
|
||||||
- 47.235.28.0/23
|
|
||||||
- 47.235.28.0/24
|
|
||||||
- 47.235.29.0/24
|
|
||||||
- 47.235.30.0/24
|
|
||||||
- 47.235.31.0/24
|
|
||||||
- 47.235.4.0/24
|
|
||||||
- 47.235.5.0/24
|
|
||||||
- 47.235.6.0/23
|
|
||||||
- 47.235.6.0/24
|
|
||||||
- 47.235.7.0/24
|
|
||||||
- 47.235.8.0/24
|
|
||||||
- 47.235.9.0/24
|
|
||||||
- 47.236.0.0/15
|
|
||||||
- 47.236.0.0/16
|
|
||||||
- 47.237.0.0/16
|
|
||||||
- 47.237.32.0/20
|
|
||||||
- 47.237.34.0/24
|
|
||||||
- 47.238.0.0/15
|
|
||||||
- 47.238.0.0/16
|
|
||||||
- 47.239.0.0/16
|
|
||||||
- 47.240.0.0/16
|
|
||||||
- 47.240.0.0/17
|
|
||||||
- 47.240.128.0/17
|
|
||||||
- 47.241.0.0/16
|
|
||||||
- 47.241.0.0/17
|
|
||||||
- 47.241.128.0/17
|
|
||||||
- 47.242.0.0/15
|
|
||||||
- 47.242.0.0/16
|
|
||||||
- 47.243.0.0/16
|
|
||||||
- 47.244.0.0/16
|
|
||||||
- 47.244.0.0/17
|
|
||||||
- 47.244.128.0/17
|
|
||||||
- 47.244.73.0/24
|
|
||||||
- 47.245.0.0/18
|
|
||||||
- 47.245.0.0/19
|
|
||||||
- 47.245.128.0/17
|
|
||||||
- 47.245.128.0/18
|
|
||||||
- 47.245.192.0/18
|
|
||||||
- 47.245.32.0/19
|
|
||||||
- 47.245.64.0/18
|
|
||||||
- 47.245.64.0/19
|
|
||||||
- 47.245.96.0/19
|
|
||||||
- 47.246.100.0/22
|
|
||||||
- 47.246.104.0/21
|
|
||||||
- 47.246.104.0/22
|
|
||||||
- 47.246.108.0/22
|
|
||||||
- 47.246.120.0/24
|
|
||||||
- 47.246.122.0/24
|
|
||||||
- 47.246.123.0/24
|
|
||||||
- 47.246.124.0/24
|
|
||||||
- 47.246.125.0/24
|
|
||||||
- 47.246.128.0/22
|
|
||||||
- 47.246.128.0/23
|
|
||||||
- 47.246.130.0/23
|
|
||||||
- 47.246.132.0/22
|
|
||||||
- 47.246.132.0/23
|
|
||||||
- 47.246.134.0/23
|
|
||||||
- 47.246.136.0/21
|
|
||||||
- 47.246.136.0/22
|
|
||||||
- 47.246.140.0/22
|
|
||||||
- 47.246.144.0/23
|
|
||||||
- 47.246.144.0/24
|
|
||||||
- 47.246.145.0/24
|
|
||||||
- 47.246.146.0/23
|
|
||||||
- 47.246.146.0/24
|
|
||||||
- 47.246.147.0/24
|
|
||||||
- 47.246.150.0/23
|
|
||||||
- 47.246.150.0/24
|
|
||||||
- 47.246.151.0/24
|
|
||||||
- 47.246.152.0/23
|
|
||||||
- 47.246.152.0/24
|
|
||||||
- 47.246.153.0/24
|
|
||||||
- 47.246.154.0/24
|
|
||||||
- 47.246.155.0/24
|
|
||||||
- 47.246.156.0/22
|
|
||||||
- 47.246.156.0/23
|
|
||||||
- 47.246.158.0/23
|
|
||||||
- 47.246.160.0/20
|
|
||||||
- 47.246.160.0/21
|
|
||||||
- 47.246.168.0/21
|
|
||||||
- 47.246.176.0/20
|
|
||||||
- 47.246.176.0/21
|
|
||||||
- 47.246.184.0/21
|
|
||||||
- 47.246.192.0/22
|
|
||||||
- 47.246.192.0/23
|
|
||||||
- 47.246.194.0/23
|
|
||||||
- 47.246.196.0/22
|
|
||||||
- 47.246.196.0/23
|
|
||||||
- 47.246.198.0/23
|
|
||||||
- 47.246.32.0/22
|
|
||||||
- 47.246.66.0/24
|
|
||||||
- 47.246.67.0/24
|
|
||||||
- 47.246.68.0/23
|
|
||||||
- 47.246.68.0/24
|
|
||||||
- 47.246.69.0/24
|
|
||||||
- 47.246.72.0/21
|
|
||||||
- 47.246.72.0/22
|
|
||||||
- 47.246.76.0/22
|
|
||||||
- 47.246.80.0/24
|
|
||||||
- 47.246.82.0/23
|
|
||||||
- 47.246.82.0/24
|
|
||||||
- 47.246.83.0/24
|
|
||||||
- 47.246.84.0/22
|
|
||||||
- 47.246.84.0/23
|
|
||||||
- 47.246.86.0/23
|
|
||||||
- 47.246.88.0/22
|
|
||||||
- 47.246.88.0/23
|
|
||||||
- 47.246.90.0/23
|
|
||||||
- 47.246.92.0/23
|
|
||||||
- 47.246.92.0/24
|
|
||||||
- 47.246.93.0/24
|
|
||||||
- 47.246.96.0/21
|
|
||||||
- 47.246.96.0/22
|
|
||||||
- 47.250.0.0/17
|
|
||||||
- 47.250.0.0/18
|
|
||||||
- 47.250.128.0/17
|
|
||||||
- 47.250.128.0/18
|
|
||||||
- 47.250.192.0/18
|
|
||||||
- 47.250.64.0/18
|
|
||||||
- 47.250.99.0/24
|
|
||||||
- 47.251.0.0/16
|
|
||||||
- 47.251.0.0/17
|
|
||||||
- 47.251.128.0/17
|
|
||||||
- 47.251.224.0/22
|
|
||||||
- 47.252.0.0/17
|
|
||||||
- 47.252.0.0/18
|
|
||||||
- 47.252.128.0/17
|
|
||||||
- 47.252.128.0/18
|
|
||||||
- 47.252.192.0/18
|
|
||||||
- 47.252.64.0/18
|
|
||||||
- 47.252.67.0/24
|
|
||||||
- 47.253.0.0/16
|
|
||||||
- 47.253.0.0/17
|
|
||||||
- 47.253.128.0/17
|
|
||||||
- 47.254.0.0/17
|
|
||||||
- 47.254.0.0/18
|
|
||||||
- 47.254.113.0/24
|
|
||||||
- 47.254.128.0/18
|
|
||||||
- 47.254.128.0/19
|
|
||||||
- 47.254.160.0/19
|
|
||||||
- 47.254.192.0/18
|
|
||||||
- 47.254.192.0/19
|
|
||||||
- 47.254.224.0/19
|
|
||||||
- 47.254.64.0/18
|
|
||||||
- 47.52.0.0/16
|
|
||||||
- 47.52.0.0/17
|
|
||||||
- 47.52.128.0/17
|
|
||||||
- 47.56.0.0/15
|
|
||||||
- 47.56.0.0/16
|
|
||||||
- 47.57.0.0/16
|
|
||||||
- 47.74.0.0/18
|
|
||||||
- 47.74.0.0/19
|
|
||||||
- 47.74.0.0/21
|
|
||||||
- 47.74.128.0/17
|
|
||||||
- 47.74.128.0/18
|
|
||||||
- 47.74.192.0/18
|
|
||||||
- 47.74.32.0/19
|
|
||||||
- 47.74.64.0/18
|
|
||||||
- 47.74.64.0/19
|
|
||||||
- 47.74.96.0/19
|
|
||||||
- 47.75.0.0/16
|
|
||||||
- 47.75.0.0/17
|
|
||||||
- 47.75.128.0/17
|
|
||||||
- 47.76.0.0/16
|
|
||||||
- 47.76.0.0/17
|
|
||||||
- 47.76.128.0/17
|
|
||||||
- 47.77.0.0/22
|
|
||||||
- 47.77.0.0/23
|
|
||||||
- 47.77.104.0/21
|
|
||||||
- 47.77.12.0/22
|
|
||||||
- 47.77.128.0/17
|
|
||||||
- 47.77.128.0/18
|
|
||||||
- 47.77.128.0/21
|
|
||||||
- 47.77.136.0/21
|
|
||||||
- 47.77.144.0/21
|
|
||||||
- 47.77.152.0/21
|
|
||||||
- 47.77.16.0/21
|
|
||||||
- 47.77.16.0/22
|
|
||||||
- 47.77.192.0/18
|
|
||||||
- 47.77.2.0/23
|
|
||||||
- 47.77.20.0/22
|
|
||||||
- 47.77.24.0/22
|
|
||||||
- 47.77.24.0/23
|
|
||||||
- 47.77.26.0/23
|
|
||||||
- 47.77.32.0/19
|
|
||||||
- 47.77.32.0/20
|
|
||||||
- 47.77.4.0/22
|
|
||||||
- 47.77.4.0/23
|
|
||||||
- 47.77.48.0/20
|
|
||||||
- 47.77.6.0/23
|
|
||||||
- 47.77.64.0/19
|
|
||||||
- 47.77.64.0/20
|
|
||||||
- 47.77.8.0/21
|
|
||||||
- 47.77.8.0/22
|
|
||||||
- 47.77.80.0/20
|
|
||||||
- 47.77.96.0/20
|
|
||||||
- 47.77.96.0/21
|
|
||||||
- 47.78.0.0/17
|
|
||||||
- 47.78.128.0/17
|
|
||||||
- 47.79.0.0/20
|
|
||||||
- 47.79.0.0/21
|
|
||||||
- 47.79.104.0/21
|
|
||||||
- 47.79.112.0/20
|
|
||||||
- 47.79.128.0/19
|
|
||||||
- 47.79.128.0/20
|
|
||||||
- 47.79.144.0/20
|
|
||||||
- 47.79.16.0/20
|
|
||||||
- 47.79.16.0/21
|
|
||||||
- 47.79.192.0/18
|
|
||||||
- 47.79.192.0/19
|
|
||||||
- 47.79.224.0/19
|
|
||||||
- 47.79.24.0/21
|
|
||||||
- 47.79.32.0/20
|
|
||||||
- 47.79.32.0/21
|
|
||||||
- 47.79.40.0/21
|
|
||||||
- 47.79.48.0/20
|
|
||||||
- 47.79.48.0/21
|
|
||||||
- 47.79.52.0/23
|
|
||||||
- 47.79.54.0/23
|
|
||||||
- 47.79.56.0/21
|
|
||||||
- 47.79.56.0/23
|
|
||||||
- 47.79.58.0/23
|
|
||||||
- 47.79.60.0/23
|
|
||||||
- 47.79.62.0/23
|
|
||||||
- 47.79.64.0/20
|
|
||||||
- 47.79.64.0/21
|
|
||||||
- 47.79.72.0/21
|
|
||||||
- 47.79.8.0/21
|
|
||||||
- 47.79.80.0/20
|
|
||||||
- 47.79.80.0/21
|
|
||||||
- 47.79.83.0/24
|
|
||||||
- 47.79.88.0/21
|
|
||||||
- 47.79.96.0/19
|
|
||||||
- 47.79.96.0/20
|
|
||||||
- 47.80.0.0/18
|
|
||||||
- 47.80.0.0/19
|
|
||||||
- 47.80.128.0/17
|
|
||||||
- 47.80.128.0/18
|
|
||||||
- 47.80.192.0/18
|
|
||||||
- 47.80.32.0/19
|
|
||||||
- 47.80.64.0/18
|
|
||||||
- 47.80.64.0/19
|
|
||||||
- 47.80.96.0/19
|
|
||||||
- 47.81.0.0/18
|
|
||||||
- 47.81.0.0/19
|
|
||||||
- 47.81.128.0/17
|
|
||||||
- 47.81.128.0/18
|
|
||||||
- 47.81.192.0/18
|
|
||||||
- 47.81.32.0/19
|
|
||||||
- 47.81.64.0/18
|
|
||||||
- 47.81.64.0/19
|
|
||||||
- 47.81.96.0/19
|
|
||||||
- 47.82.0.0/18
|
|
||||||
- 47.82.0.0/19
|
|
||||||
- 47.82.10.0/23
|
|
||||||
- 47.82.12.0/23
|
|
||||||
- 47.82.128.0/17
|
|
||||||
- 47.82.128.0/18
|
|
||||||
- 47.82.14.0/23
|
|
||||||
- 47.82.192.0/18
|
|
||||||
- 47.82.32.0/19
|
|
||||||
- 47.82.32.0/21
|
|
||||||
- 47.82.40.0/21
|
|
||||||
- 47.82.48.0/21
|
|
||||||
- 47.82.56.0/21
|
|
||||||
- 47.82.64.0/18
|
|
||||||
- 47.82.64.0/19
|
|
||||||
- 47.82.8.0/23
|
|
||||||
- 47.82.96.0/19
|
|
||||||
- 47.83.0.0/16
|
|
||||||
- 47.83.0.0/17
|
|
||||||
- 47.83.128.0/17
|
|
||||||
- 47.83.32.0/21
|
|
||||||
- 47.83.40.0/21
|
|
||||||
- 47.83.48.0/21
|
|
||||||
- 47.83.56.0/21
|
|
||||||
- 47.84.0.0/16
|
|
||||||
- 47.84.0.0/17
|
|
||||||
- 47.84.128.0/17
|
|
||||||
- 47.84.144.0/21
|
|
||||||
- 47.84.152.0/21
|
|
||||||
- 47.84.160.0/21
|
|
||||||
- 47.84.168.0/21
|
|
||||||
- 47.85.0.0/16
|
|
||||||
- 47.85.0.0/17
|
|
||||||
- 47.85.112.0/22
|
|
||||||
- 47.85.112.0/23
|
|
||||||
- 47.85.114.0/23
|
|
||||||
- 47.85.128.0/17
|
|
||||||
- 47.86.0.0/16
|
|
||||||
- 47.86.0.0/17
|
|
||||||
- 47.86.128.0/17
|
|
||||||
- 47.87.0.0/18
|
|
||||||
- 47.87.0.0/19
|
|
||||||
- 47.87.128.0/18
|
|
||||||
- 47.87.128.0/19
|
|
||||||
- 47.87.160.0/19
|
|
||||||
- 47.87.192.0/22
|
|
||||||
- 47.87.192.0/23
|
|
||||||
- 47.87.194.0/23
|
|
||||||
- 47.87.196.0/22
|
|
||||||
- 47.87.196.0/23
|
|
||||||
- 47.87.198.0/23
|
|
||||||
- 47.87.200.0/22
|
|
||||||
- 47.87.200.0/23
|
|
||||||
- 47.87.202.0/23
|
|
||||||
- 47.87.204.0/22
|
|
||||||
- 47.87.204.0/23
|
|
||||||
- 47.87.206.0/23
|
|
||||||
- 47.87.208.0/22
|
|
||||||
- 47.87.208.0/23
|
|
||||||
- 47.87.210.0/23
|
|
||||||
- 47.87.212.0/22
|
|
||||||
- 47.87.212.0/23
|
|
||||||
- 47.87.214.0/23
|
|
||||||
- 47.87.216.0/22
|
|
||||||
- 47.87.216.0/23
|
|
||||||
- 47.87.218.0/23
|
|
||||||
- 47.87.220.0/22
|
|
||||||
- 47.87.220.0/23
|
|
||||||
- 47.87.222.0/23
|
|
||||||
- 47.87.224.0/22
|
|
||||||
- 47.87.224.0/23
|
|
||||||
- 47.87.226.0/23
|
|
||||||
- 47.87.228.0/22
|
|
||||||
- 47.87.228.0/23
|
|
||||||
- 47.87.230.0/23
|
|
||||||
- 47.87.232.0/22
|
|
||||||
- 47.87.232.0/23
|
|
||||||
- 47.87.234.0/23
|
|
||||||
- 47.87.236.0/22
|
|
||||||
- 47.87.236.0/23
|
|
||||||
- 47.87.238.0/23
|
|
||||||
- 47.87.240.0/22
|
|
||||||
- 47.87.240.0/23
|
|
||||||
- 47.87.242.0/23
|
|
||||||
- 47.87.32.0/19
|
|
||||||
- 47.87.64.0/18
|
|
||||||
- 47.87.64.0/19
|
|
||||||
- 47.87.96.0/19
|
|
||||||
- 47.88.0.0/17
|
|
||||||
- 47.88.0.0/18
|
|
||||||
- 47.88.109.0/24
|
|
||||||
- 47.88.128.0/17
|
|
||||||
- 47.88.128.0/18
|
|
||||||
- 47.88.135.0/24
|
|
||||||
- 47.88.192.0/18
|
|
||||||
- 47.88.41.0/24
|
|
||||||
- 47.88.42.0/24
|
|
||||||
- 47.88.43.0/24
|
|
||||||
- 47.88.64.0/18
|
|
||||||
- 47.89.0.0/18
|
|
||||||
- 47.89.0.0/19
|
|
||||||
- 47.89.100.0/24
|
|
||||||
- 47.89.101.0/24
|
|
||||||
- 47.89.102.0/24
|
|
||||||
- 47.89.103.0/24
|
|
||||||
- 47.89.104.0/21
|
|
||||||
- 47.89.104.0/22
|
|
||||||
- 47.89.108.0/22
|
|
||||||
- 47.89.122.0/24
|
|
||||||
- 47.89.123.0/24
|
|
||||||
- 47.89.124.0/23
|
|
||||||
- 47.89.124.0/24
|
|
||||||
- 47.89.125.0/24
|
|
||||||
- 47.89.128.0/18
|
|
||||||
- 47.89.128.0/19
|
|
||||||
- 47.89.160.0/19
|
|
||||||
- 47.89.192.0/18
|
|
||||||
- 47.89.192.0/19
|
|
||||||
- 47.89.221.0/24
|
|
||||||
- 47.89.224.0/19
|
|
||||||
- 47.89.32.0/19
|
|
||||||
- 47.89.72.0/22
|
|
||||||
- 47.89.72.0/23
|
|
||||||
- 47.89.74.0/23
|
|
||||||
- 47.89.76.0/22
|
|
||||||
- 47.89.76.0/23
|
|
||||||
- 47.89.78.0/23
|
|
||||||
- 47.89.80.0/23
|
|
||||||
- 47.89.82.0/23
|
|
||||||
- 47.89.84.0/24
|
|
||||||
- 47.89.88.0/22
|
|
||||||
- 47.89.88.0/23
|
|
||||||
- 47.89.90.0/23
|
|
||||||
- 47.89.92.0/22
|
|
||||||
- 47.89.92.0/23
|
|
||||||
- 47.89.94.0/23
|
|
||||||
- 47.89.96.0/24
|
|
||||||
- 47.89.97.0/24
|
|
||||||
- 47.89.98.0/23
|
|
||||||
- 47.89.99.0/24
|
|
||||||
- 47.90.0.0/17
|
|
||||||
- 47.90.0.0/18
|
|
||||||
- 47.90.128.0/17
|
|
||||||
- 47.90.128.0/18
|
|
||||||
- 47.90.172.0/24
|
|
||||||
- 47.90.173.0/24
|
|
||||||
- 47.90.174.0/24
|
|
||||||
- 47.90.175.0/24
|
|
||||||
- 47.90.192.0/18
|
|
||||||
- 47.90.64.0/18
|
|
||||||
- 47.91.0.0/19
|
|
||||||
- 47.91.0.0/20
|
|
||||||
- 47.91.112.0/20
|
|
||||||
- 47.91.128.0/17
|
|
||||||
- 47.91.128.0/18
|
|
||||||
- 47.91.16.0/20
|
|
||||||
- 47.91.192.0/18
|
|
||||||
- 47.91.32.0/19
|
|
||||||
- 47.91.32.0/20
|
|
||||||
- 47.91.48.0/20
|
|
||||||
- 47.91.64.0/19
|
|
||||||
- 47.91.64.0/20
|
|
||||||
- 47.91.80.0/20
|
|
||||||
- 47.91.96.0/19
|
|
||||||
- 47.91.96.0/20
|
|
||||||
- 5.181.224.0/23
|
|
||||||
- 59.82.136.0/23
|
|
||||||
- 8.208.0.0/16
|
|
||||||
- 8.208.0.0/17
|
|
||||||
- 8.208.0.0/18
|
|
||||||
- 8.208.0.0/19
|
|
||||||
- 8.208.128.0/17
|
|
||||||
- 8.208.141.0/24
|
|
||||||
- 8.208.32.0/19
|
|
||||||
- 8.209.0.0/19
|
|
||||||
- 8.209.0.0/20
|
|
||||||
- 8.209.128.0/18
|
|
||||||
- 8.209.128.0/19
|
|
||||||
- 8.209.16.0/20
|
|
||||||
- 8.209.160.0/19
|
|
||||||
- 8.209.192.0/18
|
|
||||||
- 8.209.192.0/19
|
|
||||||
- 8.209.224.0/19
|
|
||||||
- 8.209.36.0/23
|
|
||||||
- 8.209.36.0/24
|
|
||||||
- 8.209.37.0/24
|
|
||||||
- 8.209.38.0/23
|
|
||||||
- 8.209.38.0/24
|
|
||||||
- 8.209.39.0/24
|
|
||||||
- 8.209.40.0/22
|
|
||||||
- 8.209.40.0/23
|
|
||||||
- 8.209.42.0/23
|
|
||||||
- 8.209.44.0/22
|
|
||||||
- 8.209.44.0/23
|
|
||||||
- 8.209.46.0/23
|
|
||||||
- 8.209.48.0/20
|
|
||||||
- 8.209.48.0/21
|
|
||||||
- 8.209.56.0/21
|
|
||||||
- 8.209.64.0/18
|
|
||||||
- 8.209.64.0/19
|
|
||||||
- 8.209.96.0/19
|
|
||||||
- 8.210.0.0/16
|
|
||||||
- 8.210.0.0/17
|
|
||||||
- 8.210.128.0/17
|
|
||||||
- 8.210.240.0/24
|
|
||||||
- 8.211.0.0/17
|
|
||||||
- 8.211.0.0/18
|
|
||||||
- 8.211.104.0/21
|
|
||||||
- 8.211.128.0/18
|
|
||||||
- 8.211.128.0/19
|
|
||||||
- 8.211.160.0/19
|
|
||||||
- 8.211.192.0/18
|
|
||||||
- 8.211.192.0/19
|
|
||||||
- 8.211.224.0/19
|
|
||||||
- 8.211.226.0/24
|
|
||||||
- 8.211.64.0/18
|
|
||||||
- 8.211.80.0/21
|
|
||||||
- 8.211.88.0/21
|
|
||||||
- 8.211.96.0/21
|
|
||||||
- 8.212.0.0/17
|
|
||||||
- 8.212.0.0/18
|
|
||||||
- 8.212.128.0/18
|
|
||||||
- 8.212.128.0/19
|
|
||||||
- 8.212.160.0/19
|
|
||||||
- 8.212.192.0/18
|
|
||||||
- 8.212.192.0/19
|
|
||||||
- 8.212.224.0/19
|
|
||||||
- 8.212.64.0/18
|
|
||||||
- 8.213.0.0/17
|
|
||||||
- 8.213.0.0/18
|
|
||||||
- 8.213.128.0/19
|
|
||||||
- 8.213.128.0/20
|
|
||||||
- 8.213.144.0/20
|
|
||||||
- 8.213.160.0/21
|
|
||||||
- 8.213.160.0/22
|
|
||||||
- 8.213.164.0/22
|
|
||||||
- 8.213.176.0/20
|
|
||||||
- 8.213.176.0/21
|
|
||||||
- 8.213.184.0/21
|
|
||||||
- 8.213.192.0/18
|
|
||||||
- 8.213.192.0/19
|
|
||||||
- 8.213.224.0/19
|
|
||||||
- 8.213.251.0/24
|
|
||||||
- 8.213.252.0/24
|
|
||||||
- 8.213.253.0/24
|
|
||||||
- 8.213.64.0/18
|
|
||||||
- 8.214.0.0/16
|
|
||||||
- 8.214.0.0/17
|
|
||||||
- 8.214.128.0/17
|
|
||||||
- 8.215.0.0/16
|
|
||||||
- 8.215.0.0/17
|
|
||||||
- 8.215.128.0/17
|
|
||||||
- 8.215.160.0/24
|
|
||||||
- 8.215.162.0/23
|
|
||||||
- 8.215.168.0/24
|
|
||||||
- 8.215.169.0/24
|
|
||||||
- 8.216.0.0/17
|
|
||||||
- 8.216.0.0/18
|
|
||||||
- 8.216.128.0/17
|
|
||||||
- 8.216.128.0/18
|
|
||||||
- 8.216.148.0/24
|
|
||||||
- 8.216.192.0/18
|
|
||||||
- 8.216.64.0/18
|
|
||||||
- 8.216.69.0/24
|
|
||||||
- 8.216.74.0/24
|
|
||||||
- 8.217.0.0/16
|
|
||||||
- 8.217.0.0/17
|
|
||||||
- 8.217.128.0/17
|
|
||||||
- 8.218.0.0/16
|
|
||||||
- 8.218.0.0/17
|
|
||||||
- 8.218.128.0/17
|
|
||||||
- 8.219.0.0/16
|
|
||||||
- 8.219.0.0/17
|
|
||||||
- 8.219.128.0/17
|
|
||||||
- 8.219.40.0/21
|
|
||||||
- 8.220.116.0/24
|
|
||||||
- 8.220.128.0/18
|
|
||||||
- 8.220.128.0/19
|
|
||||||
- 8.220.147.0/24
|
|
||||||
- 8.220.160.0/19
|
|
||||||
- 8.220.192.0/18
|
|
||||||
- 8.220.192.0/19
|
|
||||||
- 8.220.224.0/19
|
|
||||||
- 8.220.229.0/24
|
|
||||||
- 8.220.64.0/18
|
|
||||||
- 8.220.64.0/19
|
|
||||||
- 8.220.96.0/19
|
|
||||||
- 8.221.0.0/17
|
|
||||||
- 8.221.0.0/18
|
|
||||||
- 8.221.0.0/21
|
|
||||||
- 8.221.128.0/17
|
|
||||||
- 8.221.128.0/18
|
|
||||||
- 8.221.184.0/22
|
|
||||||
- 8.221.188.0/22
|
|
||||||
- 8.221.192.0/18
|
|
||||||
- 8.221.192.0/21
|
|
||||||
- 8.221.200.0/21
|
|
||||||
- 8.221.208.0/21
|
|
||||||
- 8.221.216.0/21
|
|
||||||
- 8.221.48.0/21
|
|
||||||
- 8.221.56.0/21
|
|
||||||
- 8.221.64.0/18
|
|
||||||
- 8.221.8.0/21
|
|
||||||
- 8.222.0.0/20
|
|
||||||
- 8.222.0.0/21
|
|
||||||
- 8.222.112.0/20
|
|
||||||
- 8.222.128.0/17
|
|
||||||
- 8.222.128.0/18
|
|
||||||
- 8.222.16.0/20
|
|
||||||
- 8.222.16.0/21
|
|
||||||
- 8.222.192.0/18
|
|
||||||
- 8.222.24.0/21
|
|
||||||
- 8.222.32.0/20
|
|
||||||
- 8.222.32.0/21
|
|
||||||
- 8.222.40.0/21
|
|
||||||
- 8.222.48.0/20
|
|
||||||
- 8.222.48.0/21
|
|
||||||
- 8.222.56.0/21
|
|
||||||
- 8.222.64.0/20
|
|
||||||
- 8.222.64.0/21
|
|
||||||
- 8.222.72.0/21
|
|
||||||
- 8.222.8.0/21
|
|
||||||
- 8.222.80.0/20
|
|
||||||
- 8.222.80.0/21
|
|
||||||
- 8.222.88.0/21
|
|
||||||
- 8.222.96.0/19
|
|
||||||
- 8.222.96.0/20
|
|
||||||
- 8.223.0.0/17
|
|
||||||
- 8.223.0.0/18
|
|
||||||
- 8.223.128.0/17
|
|
||||||
- 8.223.128.0/18
|
|
||||||
- 8.223.192.0/18
|
|
||||||
- 8.223.64.0/18
|
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
user_agent_regex: Applebot
|
user_agent_regex: Applebot
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://search.developer.apple.com/applebot.json
|
# https://search.developer.apple.com/applebot.json
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"17.241.208.160/27",
|
"17.241.208.160/27",
|
||||||
"17.241.193.160/27",
|
"17.241.193.160/27",
|
||||||
"17.241.200.160/27",
|
"17.241.200.160/27",
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
user_agent_regex: \+http\://www\.bing\.com/bingbot\.htm
|
user_agent_regex: \+http\://www\.bing\.com/bingbot\.htm
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://www.bing.com/toolbox/bingbot.json
|
# https://www.bing.com/toolbox/bingbot.json
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"157.55.39.0/24",
|
"157.55.39.0/24",
|
||||||
"207.46.13.0/24",
|
"207.46.13.0/24",
|
||||||
"40.77.167.0/24",
|
"40.77.167.0/24",
|
||||||
@@ -31,5 +30,5 @@
|
|||||||
"20.74.197.0/28",
|
"20.74.197.0/28",
|
||||||
"20.15.133.160/27",
|
"20.15.133.160/27",
|
||||||
"40.77.177.0/24",
|
"40.77.177.0/24",
|
||||||
"40.77.178.0/23",
|
"40.77.178.0/23"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
user_agent_regex: DuckDuckBot/1\.1; \(\+http\://duckduckgo\.com/duckduckbot\.html\)
|
user_agent_regex: DuckDuckBot/1\.1; \(\+http\://duckduckgo\.com/duckduckbot\.html\)
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot
|
# https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"57.152.72.128/32",
|
"57.152.72.128/32",
|
||||||
"51.8.253.152/32",
|
"51.8.253.152/32",
|
||||||
"40.80.242.63/32",
|
"40.80.242.63/32",
|
||||||
@@ -272,5 +271,5 @@
|
|||||||
"4.213.46.14/32",
|
"4.213.46.14/32",
|
||||||
"172.169.17.165/32",
|
"172.169.17.165/32",
|
||||||
"51.8.71.117/32",
|
"51.8.71.117/32",
|
||||||
"20.3.1.178/32",
|
"20.3.1.178/32"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
user_agent_regex: \+http\://www\.google\.com/bot\.html
|
user_agent_regex: \+http\://www\.google\.com/bot\.html
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://developers.google.com/static/search/apis/ipranges/googlebot.json
|
# https://developers.google.com/static/search/apis/ipranges/googlebot.json
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"2001:4860:4801:10::/64",
|
"2001:4860:4801:10::/64",
|
||||||
"2001:4860:4801:11::/64",
|
"2001:4860:4801:11::/64",
|
||||||
"2001:4860:4801:12::/64",
|
"2001:4860:4801:12::/64",
|
||||||
@@ -260,5 +259,5 @@
|
|||||||
"66.249.79.224/27",
|
"66.249.79.224/27",
|
||||||
"66.249.79.32/27",
|
"66.249.79.32/27",
|
||||||
"66.249.79.64/27",
|
"66.249.79.64/27",
|
||||||
"66.249.79.96/27",
|
"66.249.79.96/27"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,617 +0,0 @@
|
|||||||
- name: huawei-cloud
|
|
||||||
action: DENY
|
|
||||||
# Updated 2025-08-20 from IP addresses for AS136907
|
|
||||||
remote_addresses:
|
|
||||||
- 1.178.32.0/20
|
|
||||||
- 1.178.48.0/20
|
|
||||||
- 101.44.0.0/20
|
|
||||||
- 101.44.144.0/20
|
|
||||||
- 101.44.16.0/20
|
|
||||||
- 101.44.160.0/20
|
|
||||||
- 101.44.173.0/24
|
|
||||||
- 101.44.176.0/20
|
|
||||||
- 101.44.192.0/20
|
|
||||||
- 101.44.208.0/22
|
|
||||||
- 101.44.212.0/22
|
|
||||||
- 101.44.216.0/22
|
|
||||||
- 101.44.220.0/22
|
|
||||||
- 101.44.224.0/22
|
|
||||||
- 101.44.228.0/22
|
|
||||||
- 101.44.232.0/22
|
|
||||||
- 101.44.236.0/22
|
|
||||||
- 101.44.240.0/22
|
|
||||||
- 101.44.244.0/22
|
|
||||||
- 101.44.248.0/22
|
|
||||||
- 101.44.252.0/24
|
|
||||||
- 101.44.253.0/24
|
|
||||||
- 101.44.254.0/24
|
|
||||||
- 101.44.255.0/24
|
|
||||||
- 101.44.32.0/20
|
|
||||||
- 101.44.48.0/20
|
|
||||||
- 101.44.64.0/20
|
|
||||||
- 101.44.80.0/20
|
|
||||||
- 101.44.96.0/20
|
|
||||||
- 101.46.0.0/20
|
|
||||||
- 101.46.128.0/21
|
|
||||||
- 101.46.136.0/21
|
|
||||||
- 101.46.144.0/21
|
|
||||||
- 101.46.152.0/21
|
|
||||||
- 101.46.160.0/21
|
|
||||||
- 101.46.168.0/21
|
|
||||||
- 101.46.176.0/21
|
|
||||||
- 101.46.184.0/21
|
|
||||||
- 101.46.192.0/21
|
|
||||||
- 101.46.200.0/21
|
|
||||||
- 101.46.208.0/21
|
|
||||||
- 101.46.216.0/21
|
|
||||||
- 101.46.224.0/22
|
|
||||||
- 101.46.232.0/22
|
|
||||||
- 101.46.236.0/22
|
|
||||||
- 101.46.240.0/22
|
|
||||||
- 101.46.244.0/22
|
|
||||||
- 101.46.248.0/22
|
|
||||||
- 101.46.252.0/24
|
|
||||||
- 101.46.253.0/24
|
|
||||||
- 101.46.254.0/24
|
|
||||||
- 101.46.255.0/24
|
|
||||||
- 101.46.32.0/20
|
|
||||||
- 101.46.48.0/20
|
|
||||||
- 101.46.64.0/20
|
|
||||||
- 101.46.80.0/20
|
|
||||||
- 103.198.203.0/24
|
|
||||||
- 103.215.0.0/24
|
|
||||||
- 103.215.1.0/24
|
|
||||||
- 103.215.3.0/24
|
|
||||||
- 103.240.156.0/22
|
|
||||||
- 103.240.157.0/24
|
|
||||||
- 103.255.60.0/22
|
|
||||||
- 103.255.60.0/24
|
|
||||||
- 103.255.61.0/24
|
|
||||||
- 103.255.62.0/24
|
|
||||||
- 103.255.63.0/24
|
|
||||||
- 103.40.100.0/23
|
|
||||||
- 103.84.110.0/24
|
|
||||||
- 110.238.100.0/22
|
|
||||||
- 110.238.104.0/21
|
|
||||||
- 110.238.112.0/21
|
|
||||||
- 110.238.120.0/22
|
|
||||||
- 110.238.124.0/22
|
|
||||||
- 110.238.64.0/21
|
|
||||||
- 110.238.72.0/21
|
|
||||||
- 110.238.80.0/20
|
|
||||||
- 110.238.96.0/24
|
|
||||||
- 110.238.98.0/24
|
|
||||||
- 110.238.99.0/24
|
|
||||||
- 110.239.127.0/24
|
|
||||||
- 110.239.184.0/22
|
|
||||||
- 110.239.188.0/23
|
|
||||||
- 110.239.190.0/23
|
|
||||||
- 110.239.64.0/19
|
|
||||||
- 110.239.96.0/19
|
|
||||||
- 110.41.208.0/24
|
|
||||||
- 110.41.209.0/24
|
|
||||||
- 110.41.210.0/24
|
|
||||||
- 111.119.192.0/20
|
|
||||||
- 111.119.208.0/20
|
|
||||||
- 111.119.224.0/20
|
|
||||||
- 111.119.240.0/20
|
|
||||||
- 111.91.0.0/20
|
|
||||||
- 111.91.112.0/20
|
|
||||||
- 111.91.16.0/20
|
|
||||||
- 111.91.32.0/20
|
|
||||||
- 111.91.48.0/20
|
|
||||||
- 111.91.64.0/20
|
|
||||||
- 111.91.80.0/20
|
|
||||||
- 111.91.96.0/20
|
|
||||||
- 114.119.128.0/19
|
|
||||||
- 114.119.160.0/21
|
|
||||||
- 114.119.168.0/24
|
|
||||||
- 114.119.169.0/24
|
|
||||||
- 114.119.170.0/24
|
|
||||||
- 114.119.171.0/24
|
|
||||||
- 114.119.172.0/22
|
|
||||||
- 114.119.176.0/20
|
|
||||||
- 115.30.32.0/20
|
|
||||||
- 115.30.48.0/20
|
|
||||||
- 119.12.160.0/20
|
|
||||||
- 119.13.112.0/20
|
|
||||||
- 119.13.160.0/24
|
|
||||||
- 119.13.161.0/24
|
|
||||||
- 119.13.162.0/23
|
|
||||||
- 119.13.163.0/24
|
|
||||||
- 119.13.164.0/22
|
|
||||||
- 119.13.168.0/21
|
|
||||||
- 119.13.168.0/24
|
|
||||||
- 119.13.169.0/24
|
|
||||||
- 119.13.170.0/24
|
|
||||||
- 119.13.172.0/24
|
|
||||||
- 119.13.173.0/24
|
|
||||||
- 119.13.32.0/22
|
|
||||||
- 119.13.36.0/22
|
|
||||||
- 119.13.64.0/24
|
|
||||||
- 119.13.65.0/24
|
|
||||||
- 119.13.66.0/23
|
|
||||||
- 119.13.68.0/22
|
|
||||||
- 119.13.72.0/22
|
|
||||||
- 119.13.76.0/22
|
|
||||||
- 119.13.80.0/21
|
|
||||||
- 119.13.88.0/22
|
|
||||||
- 119.13.92.0/22
|
|
||||||
- 119.13.96.0/20
|
|
||||||
- 119.8.0.0/21
|
|
||||||
- 119.8.128.0/24
|
|
||||||
- 119.8.129.0/24
|
|
||||||
- 119.8.130.0/23
|
|
||||||
- 119.8.132.0/22
|
|
||||||
- 119.8.136.0/21
|
|
||||||
- 119.8.144.0/20
|
|
||||||
- 119.8.160.0/19
|
|
||||||
- 119.8.18.0/24
|
|
||||||
- 119.8.192.0/20
|
|
||||||
- 119.8.192.0/21
|
|
||||||
- 119.8.200.0/21
|
|
||||||
- 119.8.208.0/20
|
|
||||||
- 119.8.21.0/24
|
|
||||||
- 119.8.22.0/24
|
|
||||||
- 119.8.224.0/24
|
|
||||||
- 119.8.227.0/24
|
|
||||||
- 119.8.228.0/22
|
|
||||||
- 119.8.23.0/24
|
|
||||||
- 119.8.232.0/21
|
|
||||||
- 119.8.24.0/21
|
|
||||||
- 119.8.240.0/23
|
|
||||||
- 119.8.242.0/23
|
|
||||||
- 119.8.244.0/24
|
|
||||||
- 119.8.245.0/24
|
|
||||||
- 119.8.246.0/24
|
|
||||||
- 119.8.247.0/24
|
|
||||||
- 119.8.248.0/24
|
|
||||||
- 119.8.249.0/24
|
|
||||||
- 119.8.250.0/24
|
|
||||||
- 119.8.253.0/24
|
|
||||||
- 119.8.254.0/23
|
|
||||||
- 119.8.32.0/19
|
|
||||||
- 119.8.4.0/24
|
|
||||||
- 119.8.64.0/22
|
|
||||||
- 119.8.68.0/24
|
|
||||||
- 119.8.69.0/24
|
|
||||||
- 119.8.70.0/24
|
|
||||||
- 119.8.71.0/24
|
|
||||||
- 119.8.72.0/21
|
|
||||||
- 119.8.8.0/21
|
|
||||||
- 119.8.80.0/20
|
|
||||||
- 119.8.96.0/19
|
|
||||||
- 121.91.152.0/21
|
|
||||||
- 121.91.168.0/21
|
|
||||||
- 121.91.200.0/21
|
|
||||||
- 121.91.200.0/24
|
|
||||||
- 121.91.201.0/24
|
|
||||||
- 121.91.204.0/24
|
|
||||||
- 121.91.205.0/24
|
|
||||||
- 122.8.128.0/20
|
|
||||||
- 122.8.144.0/20
|
|
||||||
- 122.8.160.0/20
|
|
||||||
- 122.8.176.0/21
|
|
||||||
- 122.8.184.0/22
|
|
||||||
- 122.8.188.0/22
|
|
||||||
- 124.243.128.0/18
|
|
||||||
- 124.243.156.0/24
|
|
||||||
- 124.243.157.0/24
|
|
||||||
- 124.243.158.0/24
|
|
||||||
- 124.243.159.0/24
|
|
||||||
- 124.71.248.0/24
|
|
||||||
- 124.71.249.0/24
|
|
||||||
- 124.71.250.0/24
|
|
||||||
- 124.71.252.0/24
|
|
||||||
- 124.71.253.0/24
|
|
||||||
- 124.81.0.0/20
|
|
||||||
- 124.81.112.0/20
|
|
||||||
- 124.81.128.0/20
|
|
||||||
- 124.81.144.0/20
|
|
||||||
- 124.81.16.0/20
|
|
||||||
- 124.81.160.0/20
|
|
||||||
- 124.81.176.0/20
|
|
||||||
- 124.81.192.0/20
|
|
||||||
- 124.81.208.0/20
|
|
||||||
- 124.81.224.0/20
|
|
||||||
- 124.81.240.0/20
|
|
||||||
- 124.81.32.0/20
|
|
||||||
- 124.81.48.0/20
|
|
||||||
- 124.81.64.0/20
|
|
||||||
- 124.81.80.0/20
|
|
||||||
- 124.81.96.0/20
|
|
||||||
- 139.9.98.0/24
|
|
||||||
- 139.9.99.0/24
|
|
||||||
- 14.137.132.0/22
|
|
||||||
- 14.137.136.0/22
|
|
||||||
- 14.137.140.0/22
|
|
||||||
- 14.137.152.0/24
|
|
||||||
- 14.137.153.0/24
|
|
||||||
- 14.137.154.0/24
|
|
||||||
- 14.137.155.0/24
|
|
||||||
- 14.137.156.0/24
|
|
||||||
- 14.137.157.0/24
|
|
||||||
- 14.137.161.0/24
|
|
||||||
- 14.137.163.0/24
|
|
||||||
- 14.137.169.0/24
|
|
||||||
- 14.137.170.0/23
|
|
||||||
- 14.137.172.0/22
|
|
||||||
- 146.174.128.0/20
|
|
||||||
- 146.174.144.0/20
|
|
||||||
- 146.174.160.0/20
|
|
||||||
- 146.174.176.0/20
|
|
||||||
- 148.145.160.0/20
|
|
||||||
- 148.145.192.0/20
|
|
||||||
- 148.145.208.0/20
|
|
||||||
- 148.145.224.0/23
|
|
||||||
- 148.145.234.0/23
|
|
||||||
- 148.145.236.0/23
|
|
||||||
- 148.145.238.0/23
|
|
||||||
- 149.232.128.0/20
|
|
||||||
- 149.232.144.0/20
|
|
||||||
- 150.40.128.0/20
|
|
||||||
- 150.40.144.0/20
|
|
||||||
- 150.40.160.0/20
|
|
||||||
- 150.40.176.0/20
|
|
||||||
- 150.40.182.0/24
|
|
||||||
- 150.40.192.0/20
|
|
||||||
- 150.40.208.0/20
|
|
||||||
- 150.40.224.0/20
|
|
||||||
- 150.40.240.0/20
|
|
||||||
- 154.220.192.0/19
|
|
||||||
- 154.81.16.0/20
|
|
||||||
- 154.83.0.0/23
|
|
||||||
- 154.86.32.0/20
|
|
||||||
- 154.86.48.0/20
|
|
||||||
- 154.93.100.0/23
|
|
||||||
- 154.93.104.0/23
|
|
||||||
- 156.227.22.0/23
|
|
||||||
- 156.230.32.0/21
|
|
||||||
- 156.230.40.0/21
|
|
||||||
- 156.230.64.0/18
|
|
||||||
- 156.232.16.0/20
|
|
||||||
- 156.240.128.0/18
|
|
||||||
- 156.249.32.0/20
|
|
||||||
- 156.253.16.0/20
|
|
||||||
- 157.254.211.0/24
|
|
||||||
- 157.254.212.0/24
|
|
||||||
- 159.138.0.0/20
|
|
||||||
- 159.138.112.0/21
|
|
||||||
- 159.138.114.0/24
|
|
||||||
- 159.138.120.0/22
|
|
||||||
- 159.138.124.0/24
|
|
||||||
- 159.138.125.0/24
|
|
||||||
- 159.138.126.0/23
|
|
||||||
- 159.138.128.0/20
|
|
||||||
- 159.138.144.0/20
|
|
||||||
- 159.138.152.0/21
|
|
||||||
- 159.138.16.0/22
|
|
||||||
- 159.138.160.0/20
|
|
||||||
- 159.138.176.0/23
|
|
||||||
- 159.138.178.0/24
|
|
||||||
- 159.138.179.0/24
|
|
||||||
- 159.138.180.0/24
|
|
||||||
- 159.138.181.0/24
|
|
||||||
- 159.138.182.0/23
|
|
||||||
- 159.138.188.0/23
|
|
||||||
- 159.138.190.0/23
|
|
||||||
- 159.138.192.0/20
|
|
||||||
- 159.138.20.0/22
|
|
||||||
- 159.138.208.0/21
|
|
||||||
- 159.138.216.0/22
|
|
||||||
- 159.138.220.0/23
|
|
||||||
- 159.138.224.0/20
|
|
||||||
- 159.138.24.0/21
|
|
||||||
- 159.138.240.0/20
|
|
||||||
- 159.138.32.0/20
|
|
||||||
- 159.138.48.0/20
|
|
||||||
- 159.138.64.0/21
|
|
||||||
- 159.138.67.0/24
|
|
||||||
- 159.138.76.0/24
|
|
||||||
- 159.138.77.0/24
|
|
||||||
- 159.138.78.0/24
|
|
||||||
- 159.138.79.0/24
|
|
||||||
- 159.138.80.0/20
|
|
||||||
- 159.138.96.0/20
|
|
||||||
- 166.108.192.0/20
|
|
||||||
- 166.108.208.0/20
|
|
||||||
- 166.108.224.0/20
|
|
||||||
- 166.108.240.0/20
|
|
||||||
- 176.52.128.0/20
|
|
||||||
- 176.52.144.0/20
|
|
||||||
- 180.87.192.0/20
|
|
||||||
- 180.87.208.0/20
|
|
||||||
- 180.87.224.0/20
|
|
||||||
- 180.87.240.0/20
|
|
||||||
- 182.160.0.0/20
|
|
||||||
- 182.160.16.0/24
|
|
||||||
- 182.160.17.0/24
|
|
||||||
- 182.160.18.0/23
|
|
||||||
- 182.160.20.0/22
|
|
||||||
- 182.160.20.0/24
|
|
||||||
- 182.160.24.0/21
|
|
||||||
- 182.160.36.0/22
|
|
||||||
- 182.160.49.0/24
|
|
||||||
- 182.160.52.0/22
|
|
||||||
- 182.160.56.0/21
|
|
||||||
- 182.160.56.0/24
|
|
||||||
- 182.160.57.0/24
|
|
||||||
- 182.160.58.0/24
|
|
||||||
- 182.160.59.0/24
|
|
||||||
- 182.160.60.0/24
|
|
||||||
- 182.160.61.0/24
|
|
||||||
- 182.160.62.0/24
|
|
||||||
- 183.87.112.0/20
|
|
||||||
- 183.87.128.0/20
|
|
||||||
- 183.87.144.0/20
|
|
||||||
- 183.87.32.0/20
|
|
||||||
- 183.87.48.0/20
|
|
||||||
- 183.87.64.0/20
|
|
||||||
- 183.87.80.0/20
|
|
||||||
- 183.87.96.0/20
|
|
||||||
- 188.119.192.0/20
|
|
||||||
- 188.119.208.0/20
|
|
||||||
- 188.119.224.0/20
|
|
||||||
- 188.119.240.0/20
|
|
||||||
- 188.239.0.0/20
|
|
||||||
- 188.239.16.0/20
|
|
||||||
- 188.239.32.0/20
|
|
||||||
- 188.239.48.0/20
|
|
||||||
- 189.1.192.0/20
|
|
||||||
- 189.1.208.0/20
|
|
||||||
- 189.1.224.0/20
|
|
||||||
- 189.1.240.0/20
|
|
||||||
- 189.28.112.0/20
|
|
||||||
- 189.28.96.0/20
|
|
||||||
- 190.92.192.0/19
|
|
||||||
- 190.92.224.0/19
|
|
||||||
- 190.92.248.0/24
|
|
||||||
- 190.92.252.0/24
|
|
||||||
- 190.92.253.0/24
|
|
||||||
- 190.92.254.0/24
|
|
||||||
- 201.77.32.0/20
|
|
||||||
- 202.170.88.0/21
|
|
||||||
- 202.76.128.0/20
|
|
||||||
- 202.76.144.0/20
|
|
||||||
- 202.76.160.0/20
|
|
||||||
- 202.76.176.0/20
|
|
||||||
- 203.123.80.0/20
|
|
||||||
- 203.167.20.0/23
|
|
||||||
- 203.167.22.0/24
|
|
||||||
- 212.34.192.0/20
|
|
||||||
- 212.34.208.0/20
|
|
||||||
- 213.250.128.0/20
|
|
||||||
- 213.250.144.0/20
|
|
||||||
- 213.250.160.0/20
|
|
||||||
- 213.250.176.0/21
|
|
||||||
- 213.250.184.0/21
|
|
||||||
- 219.83.0.0/20
|
|
||||||
- 219.83.112.0/22
|
|
||||||
- 219.83.116.0/23
|
|
||||||
- 219.83.118.0/23
|
|
||||||
- 219.83.121.0/24
|
|
||||||
- 219.83.122.0/24
|
|
||||||
- 219.83.123.0/24
|
|
||||||
- 219.83.124.0/24
|
|
||||||
- 219.83.16.0/20
|
|
||||||
- 219.83.32.0/20
|
|
||||||
- 219.83.76.0/23
|
|
||||||
- 2404:a140:43::/48
|
|
||||||
- 2405:f080::/39
|
|
||||||
- 2405:f080:1::/48
|
|
||||||
- 2405:f080:1000::/39
|
|
||||||
- 2405:f080:1200::/39
|
|
||||||
- 2405:f080:1400::/48
|
|
||||||
- 2405:f080:1401::/48
|
|
||||||
- 2405:f080:1402::/48
|
|
||||||
- 2405:f080:1403::/48
|
|
||||||
- 2405:f080:1500::/40
|
|
||||||
- 2405:f080:1600::/48
|
|
||||||
- 2405:f080:1602::/48
|
|
||||||
- 2405:f080:1603::/48
|
|
||||||
- 2405:f080:1800::/39
|
|
||||||
- 2405:f080:1800::/44
|
|
||||||
- 2405:f080:1810::/48
|
|
||||||
- 2405:f080:1811::/48
|
|
||||||
- 2405:f080:1812::/48
|
|
||||||
- 2405:f080:1813::/48
|
|
||||||
- 2405:f080:1814::/48
|
|
||||||
- 2405:f080:1815::/48
|
|
||||||
- 2405:f080:1900::/40
|
|
||||||
- 2405:f080:1e02::/47
|
|
||||||
- 2405:f080:1e04::/47
|
|
||||||
- 2405:f080:1e06::/47
|
|
||||||
- 2405:f080:1e1e::/47
|
|
||||||
- 2405:f080:1e20::/47
|
|
||||||
- 2405:f080:200::/48
|
|
||||||
- 2405:f080:2000::/39
|
|
||||||
- 2405:f080:201::/48
|
|
||||||
- 2405:f080:202::/48
|
|
||||||
- 2405:f080:2040::/48
|
|
||||||
- 2405:f080:2200::/39
|
|
||||||
- 2405:f080:2280::/48
|
|
||||||
- 2405:f080:2281::/48
|
|
||||||
- 2405:f080:2282::/48
|
|
||||||
- 2405:f080:2283::/48
|
|
||||||
- 2405:f080:2284::/48
|
|
||||||
- 2405:f080:2285::/48
|
|
||||||
- 2405:f080:2286::/48
|
|
||||||
- 2405:f080:2287::/48
|
|
||||||
- 2405:f080:2288::/48
|
|
||||||
- 2405:f080:2289::/48
|
|
||||||
- 2405:f080:228a::/48
|
|
||||||
- 2405:f080:228b::/48
|
|
||||||
- 2405:f080:228c::/48
|
|
||||||
- 2405:f080:228d::/48
|
|
||||||
- 2405:f080:228e::/48
|
|
||||||
- 2405:f080:228f::/48
|
|
||||||
- 2405:f080:2400::/39
|
|
||||||
- 2405:f080:2600::/39
|
|
||||||
- 2405:f080:2800::/48
|
|
||||||
- 2405:f080:2a00::/48
|
|
||||||
- 2405:f080:2e00::/47
|
|
||||||
- 2405:f080:3000::/38
|
|
||||||
- 2405:f080:3000::/40
|
|
||||||
- 2405:f080:3100::/40
|
|
||||||
- 2405:f080:3200::/48
|
|
||||||
- 2405:f080:3201::/48
|
|
||||||
- 2405:f080:3202::/48
|
|
||||||
- 2405:f080:3203::/48
|
|
||||||
- 2405:f080:3204::/48
|
|
||||||
- 2405:f080:3205::/48
|
|
||||||
- 2405:f080:3400::/38
|
|
||||||
- 2405:f080:3400::/40
|
|
||||||
- 2405:f080:3500::/40
|
|
||||||
- 2405:f080:3600::/48
|
|
||||||
- 2405:f080:3601::/48
|
|
||||||
- 2405:f080:3602::/48
|
|
||||||
- 2405:f080:3603::/48
|
|
||||||
- 2405:f080:3604::/48
|
|
||||||
- 2405:f080:3605::/48
|
|
||||||
- 2405:f080:400::/39
|
|
||||||
- 2405:f080:4000::/40
|
|
||||||
- 2405:f080:4100::/48
|
|
||||||
- 2405:f080:4102::/48
|
|
||||||
- 2405:f080:4103::/48
|
|
||||||
- 2405:f080:4104::/48
|
|
||||||
- 2405:f080:4200::/40
|
|
||||||
- 2405:f080:4300::/40
|
|
||||||
- 2405:f080:600::/48
|
|
||||||
- 2405:f080:800::/40
|
|
||||||
- 2405:f080:810::/44
|
|
||||||
- 2405:f080:a00::/39
|
|
||||||
- 2405:f080:a11::/48
|
|
||||||
- 2405:f080:e02::/48
|
|
||||||
- 2405:f080:e03::/48
|
|
||||||
- 2405:f080:e04::/47
|
|
||||||
- 2405:f080:e05::/48
|
|
||||||
- 2405:f080:e06::/48
|
|
||||||
- 2405:f080:e07::/48
|
|
||||||
- 2405:f080:e0e::/47
|
|
||||||
- 2405:f080:e10::/47
|
|
||||||
- 2405:f080:edff::/48
|
|
||||||
- 27.106.0.0/20
|
|
||||||
- 27.106.112.0/20
|
|
||||||
- 27.106.16.0/20
|
|
||||||
- 27.106.32.0/20
|
|
||||||
- 27.106.48.0/20
|
|
||||||
- 27.106.64.0/20
|
|
||||||
- 27.106.80.0/20
|
|
||||||
- 27.106.96.0/20
|
|
||||||
- 27.255.0.0/23
|
|
||||||
- 27.255.10.0/23
|
|
||||||
- 27.255.12.0/23
|
|
||||||
- 27.255.14.0/23
|
|
||||||
- 27.255.16.0/23
|
|
||||||
- 27.255.18.0/23
|
|
||||||
- 27.255.2.0/23
|
|
||||||
- 27.255.20.0/23
|
|
||||||
- 27.255.22.0/23
|
|
||||||
- 27.255.26.0/23
|
|
||||||
- 27.255.28.0/23
|
|
||||||
- 27.255.30.0/23
|
|
||||||
- 27.255.32.0/23
|
|
||||||
- 27.255.34.0/23
|
|
||||||
- 27.255.36.0/23
|
|
||||||
- 27.255.38.0/23
|
|
||||||
- 27.255.4.0/23
|
|
||||||
- 27.255.40.0/23
|
|
||||||
- 27.255.42.0/23
|
|
||||||
- 27.255.44.0/23
|
|
||||||
- 27.255.46.0/23
|
|
||||||
- 27.255.48.0/23
|
|
||||||
- 27.255.50.0/23
|
|
||||||
- 27.255.52.0/23
|
|
||||||
- 27.255.54.0/23
|
|
||||||
- 27.255.58.0/23
|
|
||||||
- 27.255.6.0/23
|
|
||||||
- 27.255.60.0/23
|
|
||||||
- 27.255.62.0/23
|
|
||||||
- 27.255.8.0/23
|
|
||||||
- 42.201.128.0/20
|
|
||||||
- 42.201.144.0/20
|
|
||||||
- 42.201.160.0/20
|
|
||||||
- 42.201.176.0/20
|
|
||||||
- 42.201.192.0/20
|
|
||||||
- 42.201.208.0/20
|
|
||||||
- 42.201.224.0/20
|
|
||||||
- 42.201.240.0/20
|
|
||||||
- 43.225.140.0/22
|
|
||||||
- 43.255.104.0/22
|
|
||||||
- 45.194.104.0/21
|
|
||||||
- 45.199.144.0/22
|
|
||||||
- 45.202.128.0/19
|
|
||||||
- 45.202.160.0/20
|
|
||||||
- 45.202.176.0/21
|
|
||||||
- 45.202.184.0/21
|
|
||||||
- 45.203.40.0/21
|
|
||||||
- 46.250.160.0/20
|
|
||||||
- 46.250.176.0/20
|
|
||||||
- 49.0.192.0/21
|
|
||||||
- 49.0.200.0/21
|
|
||||||
- 49.0.224.0/22
|
|
||||||
- 49.0.228.0/22
|
|
||||||
- 49.0.232.0/21
|
|
||||||
- 49.0.240.0/20
|
|
||||||
- 62.245.0.0/20
|
|
||||||
- 62.245.16.0/20
|
|
||||||
- 80.238.128.0/22
|
|
||||||
- 80.238.132.0/22
|
|
||||||
- 80.238.136.0/22
|
|
||||||
- 80.238.140.0/22
|
|
||||||
- 80.238.144.0/22
|
|
||||||
- 80.238.148.0/22
|
|
||||||
- 80.238.152.0/22
|
|
||||||
- 80.238.156.0/22
|
|
||||||
- 80.238.164.0/22
|
|
||||||
- 80.238.164.0/24
|
|
||||||
- 80.238.165.0/24
|
|
||||||
- 80.238.168.0/22
|
|
||||||
- 80.238.168.0/24
|
|
||||||
- 80.238.169.0/24
|
|
||||||
- 80.238.170.0/24
|
|
||||||
- 80.238.171.0/24
|
|
||||||
- 80.238.172.0/22
|
|
||||||
- 80.238.176.0/22
|
|
||||||
- 80.238.180.0/24
|
|
||||||
- 80.238.181.0/24
|
|
||||||
- 80.238.183.0/24
|
|
||||||
- 80.238.184.0/24
|
|
||||||
- 80.238.185.0/24
|
|
||||||
- 80.238.186.0/24
|
|
||||||
- 80.238.190.0/24
|
|
||||||
- 80.238.192.0/20
|
|
||||||
- 80.238.208.0/20
|
|
||||||
- 80.238.224.0/20
|
|
||||||
- 80.238.240.0/20
|
|
||||||
- 83.101.0.0/21
|
|
||||||
- 83.101.104.0/21
|
|
||||||
- 83.101.16.0/21
|
|
||||||
- 83.101.24.0/21
|
|
||||||
- 83.101.32.0/21
|
|
||||||
- 83.101.48.0/21
|
|
||||||
- 83.101.56.0/23
|
|
||||||
- 83.101.58.0/23
|
|
||||||
- 83.101.64.0/21
|
|
||||||
- 83.101.72.0/21
|
|
||||||
- 83.101.8.0/23
|
|
||||||
- 83.101.80.0/21
|
|
||||||
- 83.101.88.0/24
|
|
||||||
- 83.101.89.0/24
|
|
||||||
- 83.101.96.0/21
|
|
||||||
- 87.119.12.0/24
|
|
||||||
- 89.150.192.0/20
|
|
||||||
- 89.150.208.0/20
|
|
||||||
- 94.244.128.0/20
|
|
||||||
- 94.244.144.0/20
|
|
||||||
- 94.244.160.0/20
|
|
||||||
- 94.244.176.0/20
|
|
||||||
- 94.45.160.0/19
|
|
||||||
- 94.45.160.0/24
|
|
||||||
- 94.45.161.0/24
|
|
||||||
- 94.45.163.0/24
|
|
||||||
- 94.74.112.0/21
|
|
||||||
- 94.74.120.0/21
|
|
||||||
- 94.74.64.0/20
|
|
||||||
- 94.74.80.0/20
|
|
||||||
- 94.74.96.0/20
|
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
- name: internet-archive
|
- name: internet-archive
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://ipinfo.io/AS7941
|
# https://ipinfo.io/AS7941
|
||||||
remote_addresses: ["207.241.224.0/20", "208.70.24.0/21", "2620:0:9c0::/48"]
|
remote_addresses: [
|
||||||
|
"207.241.224.0/20",
|
||||||
|
"208.70.24.0/21",
|
||||||
|
"2620:0:9c0::/48"
|
||||||
|
]
|
||||||
@@ -2,10 +2,9 @@
|
|||||||
user_agent_regex: \+https\://kagi\.com/bot
|
user_agent_regex: \+https\://kagi\.com/bot
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://kagi.com/bot
|
# https://kagi.com/bot
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"216.18.205.234/32",
|
"216.18.205.234/32",
|
||||||
"35.212.27.76/32",
|
"35.212.27.76/32",
|
||||||
"104.254.65.50/32",
|
"104.254.65.50/32",
|
||||||
"209.151.156.194/32",
|
"209.151.156.194/32"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
user_agent_regex: search\.marginalia\.nu
|
user_agent_regex: search\.marginalia\.nu
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# Received directly over email
|
# Received directly over email
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"193.183.0.162/31",
|
"193.183.0.162/31",
|
||||||
"193.183.0.164/30",
|
"193.183.0.164/30",
|
||||||
"193.183.0.168/30",
|
"193.183.0.168/30",
|
||||||
"193.183.0.172/31",
|
"193.183.0.172/31",
|
||||||
"193.183.0.174/32",
|
"193.183.0.174/32"
|
||||||
]
|
]
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
user_agent_regex: \+https\://www\.mojeek\.com/bot\.html
|
user_agent_regex: \+https\://www\.mojeek\.com/bot\.html
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://www.mojeek.com/bot.html
|
# https://www.mojeek.com/bot.html
|
||||||
remote_addresses: ["5.102.173.71/32"]
|
remote_addresses: [ "5.102.173.71/32" ]
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
user_agent_regex: GPTBot/1\.1; \+https\://openai\.com/gptbot
|
user_agent_regex: GPTBot/1\.1; \+https\://openai\.com/gptbot
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://openai.com/gptbot.json
|
# https://openai.com/gptbot.json
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"52.230.152.0/24",
|
"52.230.152.0/24",
|
||||||
"20.171.206.0/24",
|
"20.171.206.0/24",
|
||||||
"20.171.207.0/24",
|
"20.171.207.0/24",
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
user_agent_regex: OAI-SearchBot/1\.0; \+https\://openai\.com/searchbot
|
user_agent_regex: OAI-SearchBot/1\.0; \+https\://openai\.com/searchbot
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://openai.com/searchbot.json
|
# https://openai.com/searchbot.json
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"20.42.10.176/28",
|
"20.42.10.176/28",
|
||||||
"172.203.190.128/28",
|
"172.203.190.128/28",
|
||||||
"104.210.140.128/28",
|
"104.210.140.128/28",
|
||||||
"51.8.102.0/24",
|
"51.8.102.0/24",
|
||||||
"135.234.64.0/24",
|
"135.234.64.0/24"
|
||||||
]
|
]
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Indexing for search, does not collect training data
|
|
||||||
# https://docs.perplexity.ai/guides/bots
|
|
||||||
- name: perplexitybot
|
|
||||||
user_agent_regex: PerplexityBot/.+; \+https\://perplexity\.ai/perplexitybot
|
|
||||||
action: ALLOW
|
|
||||||
# https://www.perplexity.com/perplexitybot.json
|
|
||||||
remote_addresses:
|
|
||||||
[
|
|
||||||
"107.20.236.150/32",
|
|
||||||
"3.224.62.45/32",
|
|
||||||
"18.210.92.235/32",
|
|
||||||
"3.222.232.239/32",
|
|
||||||
"3.211.124.183/32",
|
|
||||||
"3.231.139.107/32",
|
|
||||||
"18.97.1.228/30",
|
|
||||||
"18.97.9.96/29",
|
|
||||||
]
|
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
user_agent_regex: \+https\://help\.qwant\.com/bot/
|
user_agent_regex: \+https\://help\.qwant\.com/bot/
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://help.qwant.com/wp-content/uploads/sites/2/2025/01/qwantbot.json
|
# https://help.qwant.com/wp-content/uploads/sites/2/2025/01/qwantbot.json
|
||||||
remote_addresses: ["91.242.162.0/24"]
|
remote_addresses: [ "91.242.162.0/24" ]
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
# Tencent Cloud crawler IP ranges
|
|
||||||
- name: tencent-cloud
|
|
||||||
action: DENY
|
|
||||||
remote_addresses:
|
|
||||||
- 101.32.0.0/17
|
|
||||||
- 101.32.176.0/20
|
|
||||||
- 101.32.192.0/18
|
|
||||||
- 101.33.116.0/22
|
|
||||||
- 101.33.120.0/21
|
|
||||||
- 101.33.16.0/20
|
|
||||||
- 101.33.2.0/23
|
|
||||||
- 101.33.32.0/19
|
|
||||||
- 101.33.4.0/22
|
|
||||||
- 101.33.64.0/19
|
|
||||||
- 101.33.8.0/21
|
|
||||||
- 101.33.96.0/20
|
|
||||||
- 119.28.28.0/24
|
|
||||||
- 119.29.29.0/24
|
|
||||||
- 124.156.0.0/16
|
|
||||||
- 129.226.0.0/18
|
|
||||||
- 129.226.128.0/18
|
|
||||||
- 129.226.224.0/19
|
|
||||||
- 129.226.96.0/19
|
|
||||||
- 150.109.0.0/18
|
|
||||||
- 150.109.128.0/20
|
|
||||||
- 150.109.160.0/19
|
|
||||||
- 150.109.192.0/18
|
|
||||||
- 150.109.64.0/20
|
|
||||||
- 150.109.80.0/21
|
|
||||||
- 150.109.88.0/22
|
|
||||||
- 150.109.96.0/19
|
|
||||||
- 162.14.60.0/22
|
|
||||||
- 162.62.0.0/18
|
|
||||||
- 162.62.128.0/20
|
|
||||||
- 162.62.144.0/21
|
|
||||||
- 162.62.152.0/22
|
|
||||||
- 162.62.172.0/22
|
|
||||||
- 162.62.176.0/20
|
|
||||||
- 162.62.192.0/19
|
|
||||||
- 162.62.255.0/24
|
|
||||||
- 162.62.80.0/20
|
|
||||||
- 162.62.96.0/19
|
|
||||||
- 170.106.0.0/16
|
|
||||||
- 43.128.0.0/14
|
|
||||||
- 43.132.0.0/22
|
|
||||||
- 43.132.12.0/22
|
|
||||||
- 43.132.128.0/17
|
|
||||||
- 43.132.16.0/22
|
|
||||||
- 43.132.28.0/22
|
|
||||||
- 43.132.32.0/22
|
|
||||||
- 43.132.40.0/22
|
|
||||||
- 43.132.52.0/22
|
|
||||||
- 43.132.60.0/24
|
|
||||||
- 43.132.64.0/22
|
|
||||||
- 43.132.69.0/24
|
|
||||||
- 43.132.70.0/23
|
|
||||||
- 43.132.72.0/21
|
|
||||||
- 43.132.80.0/21
|
|
||||||
- 43.132.88.0/22
|
|
||||||
- 43.132.92.0/23
|
|
||||||
- 43.132.96.0/19
|
|
||||||
- 43.133.0.0/16
|
|
||||||
- 43.134.0.0/16
|
|
||||||
- 43.135.0.0/17
|
|
||||||
- 43.135.128.0/18
|
|
||||||
- 43.135.192.0/19
|
|
||||||
- 43.152.0.0/21
|
|
||||||
- 43.152.11.0/24
|
|
||||||
- 43.152.12.0/22
|
|
||||||
- 43.152.128.0/22
|
|
||||||
- 43.152.133.0/24
|
|
||||||
- 43.152.134.0/23
|
|
||||||
- 43.152.136.0/21
|
|
||||||
- 43.152.144.0/20
|
|
||||||
- 43.152.160.0/22
|
|
||||||
- 43.152.16.0/21
|
|
||||||
- 43.152.164.0/23
|
|
||||||
- 43.152.166.0/24
|
|
||||||
- 43.152.168.0/21
|
|
||||||
- 43.152.178.0/23
|
|
||||||
- 43.152.180.0/22
|
|
||||||
- 43.152.184.0/21
|
|
||||||
- 43.152.192.0/18
|
|
||||||
- 43.152.24.0/22
|
|
||||||
- 43.152.31.0/24
|
|
||||||
- 43.152.32.0/23
|
|
||||||
- 43.152.35.0/24
|
|
||||||
- 43.152.36.0/22
|
|
||||||
- 43.152.40.0/21
|
|
||||||
- 43.152.48.0/20
|
|
||||||
- 43.152.74.0/23
|
|
||||||
- 43.152.76.0/22
|
|
||||||
- 43.152.80.0/22
|
|
||||||
- 43.152.8.0/23
|
|
||||||
- 43.152.92.0/23
|
|
||||||
- 43.153.0.0/16
|
|
||||||
- 43.154.0.0/15
|
|
||||||
- 43.156.0.0/15
|
|
||||||
- 43.158.0.0/16
|
|
||||||
- 43.159.0.0/20
|
|
||||||
- 43.159.128.0/17
|
|
||||||
- 43.159.64.0/23
|
|
||||||
- 43.159.70.0/23
|
|
||||||
- 43.159.72.0/21
|
|
||||||
- 43.159.81.0/24
|
|
||||||
- 43.159.82.0/23
|
|
||||||
- 43.159.85.0/24
|
|
||||||
- 43.159.86.0/23
|
|
||||||
- 43.159.88.0/21
|
|
||||||
- 43.159.96.0/19
|
|
||||||
- 43.160.0.0/15
|
|
||||||
- 43.162.0.0/16
|
|
||||||
- 43.163.0.0/17
|
|
||||||
- 43.163.128.0/18
|
|
||||||
- 43.163.192.255/32
|
|
||||||
- 43.163.193.0/24
|
|
||||||
- 43.163.194.0/23
|
|
||||||
- 43.163.196.0/22
|
|
||||||
- 43.163.200.0/21
|
|
||||||
- 43.163.208.0/20
|
|
||||||
- 43.163.224.0/19
|
|
||||||
- 43.164.0.0/18
|
|
||||||
- 43.164.128.0/17
|
|
||||||
- 43.165.0.0/16
|
|
||||||
- 43.166.128.0/18
|
|
||||||
- 43.166.224.0/19
|
|
||||||
- 43.168.0.0/20
|
|
||||||
- 43.168.16.0/21
|
|
||||||
- 43.168.24.0/22
|
|
||||||
- 43.168.255.0/24
|
|
||||||
- 43.168.32.0/19
|
|
||||||
- 43.168.64.0/20
|
|
||||||
- 43.168.80.0/22
|
|
||||||
- 43.169.0.0/16
|
|
||||||
- 43.170.0.0/16
|
|
||||||
- 43.174.0.0/18
|
|
||||||
- 43.174.128.0/17
|
|
||||||
- 43.174.64.0/22
|
|
||||||
- 43.174.68.0/23
|
|
||||||
- 43.174.71.0/24
|
|
||||||
- 43.174.74.0/23
|
|
||||||
- 43.174.76.0/22
|
|
||||||
- 43.174.80.0/20
|
|
||||||
- 43.174.96.0/19
|
|
||||||
- 43.175.0.0/20
|
|
||||||
- 43.175.113.0/24
|
|
||||||
- 43.175.114.0/23
|
|
||||||
- 43.175.116.0/22
|
|
||||||
- 43.175.120.0/21
|
|
||||||
- 43.175.128.0/18
|
|
||||||
- 43.175.16.0/22
|
|
||||||
- 43.175.192.0/20
|
|
||||||
- 43.175.20.0/23
|
|
||||||
- 43.175.208.0/21
|
|
||||||
- 43.175.216.0/22
|
|
||||||
- 43.175.220.0/23
|
|
||||||
- 43.175.22.0/24
|
|
||||||
- 43.175.222.0/24
|
|
||||||
- 43.175.224.0/20
|
|
||||||
- 43.175.25.0/24
|
|
||||||
- 43.175.26.0/23
|
|
||||||
- 43.175.28.0/22
|
|
||||||
- 43.175.32.0/19
|
|
||||||
- 43.175.64.0/19
|
|
||||||
- 43.175.96.0/20
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
- name: yandexbot
|
|
||||||
action: ALLOW
|
|
||||||
expression:
|
|
||||||
all:
|
|
||||||
- userAgent.matches("\\+http\\://yandex\\.com/bots")
|
|
||||||
- verifyFCrDNS(remoteAddress, "^.*\\.yandex\\.(ru|com|net)$")
|
|
||||||
@@ -3,6 +3,6 @@ package data
|
|||||||
import "embed"
|
import "embed"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
//go:embed botPolicies.yaml all:apps all:bots all:clients all:common all:crawlers all:meta all:services
|
//go:embed botPolicies.yaml all:apps all:bots all:clients all:common all:crawlers all:meta
|
||||||
BotPolicies embed.FS
|
BotPolicies embed.FS
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package data
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestBotPoliciesEmbed ensures all YAML files in the directory tree
|
|
||||||
// are accessible in the embedded BotPolicies filesystem.
|
|
||||||
func TestBotPoliciesEmbed(t *testing.T) {
|
|
||||||
yamlFiles, err := filepath.Glob("./**/*.yaml")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to glob YAML files: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(yamlFiles) == 0 {
|
|
||||||
t.Fatal("No YAML files found in directory tree")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Found %d YAML files to verify", len(yamlFiles))
|
|
||||||
|
|
||||||
for _, filePath := range yamlFiles {
|
|
||||||
embeddedPath := strings.TrimPrefix(filePath, "./")
|
|
||||||
|
|
||||||
t.Run(embeddedPath, func(t *testing.T) {
|
|
||||||
content, err := BotPolicies.ReadFile(embeddedPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to read %s from embedded filesystem: %v", embeddedPath, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(content) == 0 {
|
|
||||||
t.Errorf("File %s exists in embedded filesystem but is empty", embeddedPath)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,5 @@
|
|||||||
- import: (data)/bots/ai-catchall.yaml
|
- import: (data)/bots/ai-catchall.yaml
|
||||||
- import: (data)/crawlers/ai-training.yaml
|
- import: (data)/crawlers/ai-training.yaml
|
||||||
- import: (data)/crawlers/openai-searchbot.yaml
|
- import: (data)/crawlers/openai-searchbot.yaml
|
||||||
- import: (data)/crawlers/perplexitybot.yaml
|
|
||||||
- import: (data)/clients/openai-chatgpt-user.yaml
|
- import: (data)/clients/openai-chatgpt-user.yaml
|
||||||
- import: (data)/clients/mistral-mistralai-user.yaml
|
- import: (data)/clients/mistral-mistralai-user.yaml
|
||||||
- import: (data)/clients/perplexity-user.yaml
|
|
||||||
|
|||||||
@@ -2,7 +2,5 @@
|
|||||||
- import: (data)/bots/ai-catchall.yaml
|
- import: (data)/bots/ai-catchall.yaml
|
||||||
- import: (data)/crawlers/openai-searchbot.yaml
|
- import: (data)/crawlers/openai-searchbot.yaml
|
||||||
- import: (data)/crawlers/openai-gptbot.yaml
|
- import: (data)/crawlers/openai-gptbot.yaml
|
||||||
- import: (data)/crawlers/perplexitybot.yaml
|
|
||||||
- import: (data)/clients/openai-chatgpt-user.yaml
|
- import: (data)/clients/openai-chatgpt-user.yaml
|
||||||
- import: (data)/clients/mistral-mistralai-user.yaml
|
- import: (data)/clients/mistral-mistralai-user.yaml
|
||||||
- import: (data)/clients/perplexity-user.yaml
|
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
- # Pathological bots to deny
|
|
||||||
# This correlates to data/bots/_deny-pathological.yaml in the source tree
|
|
||||||
# https://github.com/TecharoHQ/anubis/blob/main/data/bots/_deny-pathological.yaml
|
|
||||||
import: (data)/bots/_deny-pathological.yaml
|
|
||||||
- import: (data)/bots/aggressive-brazilian-scrapers.yaml
|
|
||||||
|
|
||||||
# Aggressively block AI/LLM related bots/agents by default
|
|
||||||
- import: (data)/meta/ai-block-aggressive.yaml
|
|
||||||
|
|
||||||
# Consider replacing the aggressive AI policy with more selective policies:
|
|
||||||
# - import: (data)/meta/ai-block-moderate.yaml
|
|
||||||
# - import: (data)/meta/ai-block-permissive.yaml
|
|
||||||
|
|
||||||
# Search engine crawlers to allow, defaults to:
|
|
||||||
# - Google (so they don't try to bypass Anubis)
|
|
||||||
# - Apple
|
|
||||||
# - Bing
|
|
||||||
# - DuckDuckGo
|
|
||||||
# - Qwant
|
|
||||||
# - The Internet Archive
|
|
||||||
# - Kagi
|
|
||||||
# - Marginalia
|
|
||||||
# - Mojeek
|
|
||||||
- import: (data)/crawlers/_allow-good.yaml
|
|
||||||
# Challenge Firefox AI previews
|
|
||||||
- import: (data)/clients/x-firefox-ai.yaml
|
|
||||||
|
|
||||||
# Allow common "keeping the internet working" routes (well-known, favicon, robots.txt)
|
|
||||||
- import: (data)/common/keep-internet-working.yaml
|
|
||||||
|
|
||||||
# # 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
|
|
||||||
# algorithm: slow # intentionally waste CPU cycles and time
|
|
||||||
|
|
||||||
# Requires a subscription to Thoth to use, see
|
|
||||||
# https://anubis.techaro.lol/docs/admin/thoth#geoip-based-filtering
|
|
||||||
- name: countries-with-aggressive-scrapers
|
|
||||||
action: WEIGH
|
|
||||||
geoip:
|
|
||||||
countries:
|
|
||||||
- BR
|
|
||||||
- CN
|
|
||||||
weight:
|
|
||||||
adjust: 10
|
|
||||||
|
|
||||||
# Requires a subscription to Thoth to use, see
|
|
||||||
# https://anubis.techaro.lol/docs/admin/thoth#asn-based-filtering
|
|
||||||
- name: aggressive-asns-without-functional-abuse-contact
|
|
||||||
action: WEIGH
|
|
||||||
asns:
|
|
||||||
match:
|
|
||||||
- 13335 # Cloudflare
|
|
||||||
- 136907 # Huawei Cloud
|
|
||||||
- 45102 # Alibaba Cloud
|
|
||||||
weight:
|
|
||||||
adjust: 10
|
|
||||||
|
|
||||||
# ## System load based checks.
|
|
||||||
# # If the system is under high load, add weight.
|
|
||||||
# - name: high-load-average
|
|
||||||
# action: WEIGH
|
|
||||||
# expression: load_1m >= 10.0 # make sure to end the load comparison in a .0
|
|
||||||
# weight:
|
|
||||||
# adjust: 20
|
|
||||||
|
|
||||||
## If your backend service is running on the same operating system as Anubis,
|
|
||||||
## you can uncomment this rule to make the challenge easier when the system is
|
|
||||||
## under low load.
|
|
||||||
##
|
|
||||||
## If it is not, remove weight.
|
|
||||||
# - name: low-load-average
|
|
||||||
# action: WEIGH
|
|
||||||
# expression: load_15m <= 4.0 # make sure to end the load comparison in a .0
|
|
||||||
# weight:
|
|
||||||
# adjust: -10
|
|
||||||
|
|
||||||
# Generic catchall rule
|
|
||||||
- name: generic-browser
|
|
||||||
user_agent_regex: >-
|
|
||||||
Mozilla|Opera
|
|
||||||
action: WEIGH
|
|
||||||
weight:
|
|
||||||
adjust: 10
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
- import: (data)/clients/telegram-preview.yaml
|
|
||||||
- import: (data)/clients/vk-preview.yaml
|
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
user_agent_regex: UptimeRobot
|
user_agent_regex: UptimeRobot
|
||||||
action: ALLOW
|
action: ALLOW
|
||||||
# https://api.uptimerobot.com/meta/ips
|
# https://api.uptimerobot.com/meta/ips
|
||||||
remote_addresses:
|
remote_addresses: [
|
||||||
[
|
|
||||||
"3.12.251.153/32",
|
"3.12.251.153/32",
|
||||||
"3.20.63.178/32",
|
"3.20.63.178/32",
|
||||||
"3.77.67.4/32",
|
"3.77.67.4/32",
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ func Zilch[T any]() T {
|
|||||||
// Impl is a lazy key->value map. It's a wrapper around a map and a mutex. If values exceed their time-to-live, they are pruned at Get time.
|
// Impl is a lazy key->value map. It's a wrapper around a map and a mutex. If values exceed their time-to-live, they are pruned at Get time.
|
||||||
type Impl[K comparable, V any] struct {
|
type Impl[K comparable, V any] struct {
|
||||||
data map[K]decayMapEntry[V]
|
data map[K]decayMapEntry[V]
|
||||||
|
|
||||||
// deleteCh receives decay-deletion requests from readers.
|
|
||||||
deleteCh chan deleteReq[K]
|
|
||||||
// stopCh stops the background cleanup worker.
|
|
||||||
stopCh chan struct{}
|
|
||||||
wg sync.WaitGroup
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,38 +21,30 @@ type decayMapEntry[V any] struct {
|
|||||||
expiry time.Time
|
expiry time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteReq is a request to remove a key if its expiry timestamp still matches
|
|
||||||
// the observed one. This prevents racing with concurrent Set updates.
|
|
||||||
type deleteReq[K comparable] struct {
|
|
||||||
key K
|
|
||||||
expiry time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new DecayMap of key type K and value type V.
|
// New creates a new DecayMap of key type K and value type V.
|
||||||
//
|
//
|
||||||
// Key types must be comparable to work with maps.
|
// Key types must be comparable to work with maps.
|
||||||
func New[K comparable, V any]() *Impl[K, V] {
|
func New[K comparable, V any]() *Impl[K, V] {
|
||||||
m := &Impl[K, V]{
|
return &Impl[K, V]{
|
||||||
data: make(map[K]decayMapEntry[V]),
|
data: make(map[K]decayMapEntry[V]),
|
||||||
deleteCh: make(chan deleteReq[K], 1024),
|
|
||||||
stopCh: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
m.wg.Add(1)
|
|
||||||
go m.cleanupWorker()
|
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// expire forcibly expires a key by setting its time-to-live one second in the past.
|
// expire forcibly expires a key by setting its time-to-live one second in the past.
|
||||||
func (m *Impl[K, V]) expire(key K) bool {
|
func (m *Impl[K, V]) expire(key K) bool {
|
||||||
// Use a single write lock to avoid RUnlock->Lock convoy.
|
m.lock.RLock()
|
||||||
m.lock.Lock()
|
|
||||||
defer m.lock.Unlock()
|
|
||||||
val, ok := m.data[key]
|
val, ok := m.data[key]
|
||||||
|
m.lock.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.lock.Lock()
|
||||||
val.expiry = time.Now().Add(-1 * time.Second)
|
val.expiry = time.Now().Add(-1 * time.Second)
|
||||||
m.data[key] = val
|
m.data[key] = val
|
||||||
|
m.lock.Unlock()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,14 +53,19 @@ func (m *Impl[K, V]) expire(key K) bool {
|
|||||||
// If the value does not exist, return false. Return true after
|
// If the value does not exist, return false. Return true after
|
||||||
// deletion.
|
// deletion.
|
||||||
func (m *Impl[K, V]) Delete(key K) bool {
|
func (m *Impl[K, V]) Delete(key K) bool {
|
||||||
// Use a single write lock to avoid RUnlock->Lock convoy.
|
m.lock.RLock()
|
||||||
m.lock.Lock()
|
|
||||||
defer m.lock.Unlock()
|
|
||||||
_, ok := m.data[key]
|
_, ok := m.data[key]
|
||||||
if ok {
|
m.lock.RUnlock()
|
||||||
delete(m.data, key)
|
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return ok
|
|
||||||
|
m.lock.Lock()
|
||||||
|
delete(m.data, key)
|
||||||
|
m.lock.Unlock()
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get gets a value from the DecayMap by key.
|
// Get gets a value from the DecayMap by key.
|
||||||
@@ -90,12 +81,13 @@ func (m *Impl[K, V]) Get(key K) (V, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if time.Now().After(value.expiry) {
|
if time.Now().After(value.expiry) {
|
||||||
// Defer decay deletion to the background worker to avoid convoy.
|
m.lock.Lock()
|
||||||
select {
|
// Since previously reading m.data[key], the value may have been updated.
|
||||||
case m.deleteCh <- deleteReq[K]{key: key, expiry: value.expiry}:
|
// Delete the entry only if the expiry time is still the same.
|
||||||
default:
|
if m.data[key].expiry.Equal(value.expiry) {
|
||||||
// Channel full: drop request; a future Cleanup() or Get will retry.
|
delete(m.data, key)
|
||||||
}
|
}
|
||||||
|
m.lock.Unlock()
|
||||||
|
|
||||||
return Zilch[V](), false
|
return Zilch[V](), false
|
||||||
}
|
}
|
||||||
@@ -133,64 +125,3 @@ func (m *Impl[K, V]) Len() int {
|
|||||||
defer m.lock.RUnlock()
|
defer m.lock.RUnlock()
|
||||||
return len(m.data)
|
return len(m.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close stops the background cleanup worker. It's optional to call; maps live
|
|
||||||
// for the process lifetime in many cases. Call in tests or when you know you no
|
|
||||||
// longer need the map to avoid goroutine leaks.
|
|
||||||
func (m *Impl[K, V]) Close() {
|
|
||||||
close(m.stopCh)
|
|
||||||
m.wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanupWorker batches decay deletions to minimize lock contention.
|
|
||||||
func (m *Impl[K, V]) cleanupWorker() {
|
|
||||||
defer m.wg.Done()
|
|
||||||
batch := make([]deleteReq[K], 0, 64)
|
|
||||||
ticker := time.NewTicker(500 * time.Millisecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
flush := func() {
|
|
||||||
if len(batch) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.applyDeletes(batch)
|
|
||||||
// reset batch without reallocating
|
|
||||||
batch = batch[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case req := <-m.deleteCh:
|
|
||||||
batch = append(batch, req)
|
|
||||||
case <-ticker.C:
|
|
||||||
flush()
|
|
||||||
case <-m.stopCh:
|
|
||||||
// Drain any remaining requests then exit
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case req := <-m.deleteCh:
|
|
||||||
batch = append(batch, req)
|
|
||||||
default:
|
|
||||||
flush()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Impl[K, V]) applyDeletes(batch []deleteReq[K]) {
|
|
||||||
now := time.Now()
|
|
||||||
m.lock.Lock()
|
|
||||||
for _, req := range batch {
|
|
||||||
entry, ok := m.data[req.key]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Only delete if the expiry is unchanged and already past.
|
|
||||||
if entry.expiry.Equal(req.expiry) && now.After(entry.expiry) {
|
|
||||||
delete(m.data, req.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
func TestImpl(t *testing.T) {
|
func TestImpl(t *testing.T) {
|
||||||
dm := New[string, string]()
|
dm := New[string, string]()
|
||||||
t.Cleanup(dm.Close)
|
|
||||||
|
|
||||||
dm.Set("test", "hi", 5*time.Minute)
|
dm.Set("test", "hi", 5*time.Minute)
|
||||||
|
|
||||||
@@ -29,24 +28,10 @@ func TestImpl(t *testing.T) {
|
|||||||
if ok {
|
if ok {
|
||||||
t.Error("got value even though it was supposed to be expired")
|
t.Error("got value even though it was supposed to be expired")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletion of expired entries after Get is deferred to a background worker.
|
|
||||||
// Assert it eventually disappears from the map.
|
|
||||||
deadline := time.Now().Add(700 * time.Millisecond)
|
|
||||||
for time.Now().Before(deadline) {
|
|
||||||
if dm.Len() == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(5 * time.Millisecond)
|
|
||||||
}
|
|
||||||
if dm.Len() != 0 {
|
|
||||||
t.Fatalf("expected background cleanup to remove expired key; len=%d", dm.Len())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCleanup(t *testing.T) {
|
func TestCleanup(t *testing.T) {
|
||||||
dm := New[string, string]()
|
dm := New[string, string]()
|
||||||
t.Cleanup(dm.Close)
|
|
||||||
|
|
||||||
dm.Set("test1", "hi1", 1*time.Second)
|
dm.Set("test1", "hi1", 1*time.Second)
|
||||||
dm.Set("test2", "hi2", 2*time.Second)
|
dm.Set("test2", "hi2", 2*time.Second)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM docker.io/library/node:lts AS build
|
FROM docker.io/library/node AS build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ So far Anubis supports the following languages:
|
|||||||
|
|
||||||
- English (Simplified and Traditional)
|
- English (Simplified and Traditional)
|
||||||
- French
|
- French
|
||||||
- Portuguese (Brazil)
|
- Portugese (Brazil)
|
||||||
- Spanish
|
- Spanish
|
||||||
|
|
||||||
If you want to contribute translations, please [file an issue](https://github.com/TecharoHQ/anubis/issues/new) with your language of choice or submit a pull request to [the `lib/localization/locales` folder](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). We are about to introduce features to the translation stack, so you may want to hold off a hot minute, but we welcome any and all contributions to making Anubis useful to a global audience.
|
If you want to contribute translations, please [file an issue](https://github.com/TecharoHQ/anubis/issues/new) with your language of choice or submit a pull request to [the `lib/localization/locales` folder](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). We are about to introduce features to the translation stack, so you may want to hold off a hot minute, but we welcome any and all contributions to making Anubis useful to a global audience.
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ I am waiting to hear back from NLNet on if Anubis was selected for funding or no
|
|||||||
|
|
||||||
Anubis now supports localized responses. Locales can be added in [lib/localization/locales/](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). This release includes support for the following languages:
|
Anubis now supports localized responses. Locales can be added in [lib/localization/locales/](https://github.com/TecharoHQ/anubis/tree/main/lib/localization/locales). This release includes support for the following languages:
|
||||||
|
|
||||||
- [Brazilian Portuguese](https://github.com/TecharoHQ/anubis/pull/726)
|
- [Brazilian Portugese](https://github.com/TecharoHQ/anubis/pull/726)
|
||||||
- [Chinese (Simplified)](https://github.com/TecharoHQ/anubis/pull/774)
|
- [Chinese (Simplified)](https://github.com/TecharoHQ/anubis/pull/774)
|
||||||
- [Chinese (Traditional)](https://github.com/TecharoHQ/anubis/pull/759)
|
- [Chinese (Traditional)](https://github.com/TecharoHQ/anubis/pull/759)
|
||||||
- [Czech](https://github.com/TecharoHQ/anubis/pull/849)
|
- [Czech](https://github.com/TecharoHQ/anubis/pull/849)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,60 +0,0 @@
|
|||||||
---
|
|
||||||
slug: 2025/funding-update
|
|
||||||
title: Funding update
|
|
||||||
authors: [xe]
|
|
||||||
tags: [funding]
|
|
||||||
image: around-the-bend.webp
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
As we finish up work on [all of the features in the next release of Anubis](/docs/CHANGELOG#unreleased), I took a moment to add up the financials and here's an update on the recurring revenue of the project. Once I reach the [$5000 per month](https://github.com/TecharoHQ/anubis/discussions/278) mark, I can start reducing hours at my dayjob and start to make working on Anubis my full time job.
|
|
||||||
|
|
||||||
{/* truncate */}
|
|
||||||
|
|
||||||
Note that this only counts _recurring_ revenue (subscriptions to [BotStopper](/docs/admin/botstopper) and monthly repeating donations). Every one of the one-time donations I get is a gift and I am grateful for them, but I cannot make critically important financial decisions off of sporadic one-time donations.
|
|
||||||
|
|
||||||
:::note
|
|
||||||
|
|
||||||
All currency figures in this article are USD (United States Dollars) unless denoted otherwise.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
Here's the funding breakdown by income stream:
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
pie title Funding update August 2025
|
|
||||||
"GitHub Sponsors" : 3500
|
|
||||||
"Patreon" : 1500
|
|
||||||
"Liberapay" : 100
|
|
||||||
"Remaining" : 4800
|
|
||||||
```
|
|
||||||
|
|
||||||
Assuming that some of my private support contracts and other sales effort go through, this will slightly change the shapes of this (a new pie chart segment will emerge for "Manual invoices"), but I am halfway there. This is a huge bar to pass and as it stands right now this is just enough income to pay for my monthly rent (not accounting for tax).
|
|
||||||
|
|
||||||
As a reminder, here's the rough plan for the phases I want to hit based on the _recurring_ donation totals:
|
|
||||||
|
|
||||||
| Monthly donations | Details |
|
|
||||||
| :-------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| $0-5,000 per month | Anubis is a nights and weekends project based on how much spare time and energy I have. |
|
|
||||||
| $5,000-10,000 per month | Anubis gets 1-2 days per week of my time put into it consistently and I go part-time at my dayjob. |
|
|
||||||
| $10,000-15,000 per month | Anubis becomes my full time job. Features that are currently exclusive to [BotStopper](/docs/admin/botstopper/) start to trickle down to the open source version of Anubis. |
|
|
||||||
| $15,000 per month and above | I start planning hiring for Techaro. |
|
|
||||||
|
|
||||||
If your organization benefits from Anubis, please consider donating to the project in order to make this sustainable. The fewer financial problems I have means the more that Anubis can become better.
|
|
||||||
|
|
||||||
## New funding platform: Liberapay
|
|
||||||
|
|
||||||
After many comments about the funding options, I have set up [Liberapay](https://liberapay.com/Xe/) as an option to receive donations. Additional funding targets will be added to Liberapay as soon as I hear back from my accountant with more information. All money received via Liberapay goes directly towards supporting the project.
|
|
||||||
|
|
||||||
## Next goals
|
|
||||||
|
|
||||||
Here's my short term goals for the immediate future:
|
|
||||||
|
|
||||||
1. Finish [Thoth](/docs/admin/thoth/) and run a backfill to mass issue API keys.
|
|
||||||
2. Document and publish the writeup for the multi-region Google Cloud spot instance setup that Thoth is built upon.
|
|
||||||
3. Release v1.22.0 of Anubis with Traefik support and other important fixes.
|
|
||||||
4. Continue growing the project into a sustainable business.
|
|
||||||
5. Work through the [blog backlog](https://github.com/TecharoHQ/anubis/issues?q=is%3Aissue%20state%3Aopen%20label%3Ablog) to document the thoughts behind Anubis and how parts of it work.
|
|
||||||
|
|
||||||
Thank you for supporting Anubis! It's only going to get better from here.
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
import React, { useState, useEffect, useMemo } from "react";
|
|
||||||
import styles from "./styles.module.css";
|
|
||||||
|
|
||||||
// A helper function to perform SHA-256 hashing.
|
|
||||||
// It takes a string, encodes it, hashes it, and returns a hex string.
|
|
||||||
async function sha256(message) {
|
|
||||||
try {
|
|
||||||
const msgBuffer = new TextEncoder().encode(message);
|
|
||||||
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
||||||
const hashHex = hashArray
|
|
||||||
.map((b) => b.toString(16).padStart(2, "0"))
|
|
||||||
.join("");
|
|
||||||
return hashHex;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Hashing failed:", error);
|
|
||||||
return "Error hashing data";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a random hex string of a given byte length
|
|
||||||
const generateRandomHex = (bytes = 16) => {
|
|
||||||
const buffer = new Uint8Array(bytes);
|
|
||||||
crypto.getRandomValues(buffer);
|
|
||||||
return Array.from(buffer)
|
|
||||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
||||||
.join("");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Icon components for better visual feedback
|
|
||||||
const CheckIcon = () => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={styles.iconGreen}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
const XCircleIcon = () => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={styles.iconRed}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
// Main Application Component
|
|
||||||
export default function App() {
|
|
||||||
// State for the challenge, initialized with a random 16-byte hex string.
|
|
||||||
const [challenge, setChallenge] = useState(() => generateRandomHex(16));
|
|
||||||
// State for the nonce, which is the variable we can change
|
|
||||||
const [nonce, setNonce] = useState(0);
|
|
||||||
// State to store the resulting hash
|
|
||||||
const [hash, setHash] = useState("");
|
|
||||||
// A flag to indicate if the current hash is the "winning" one
|
|
||||||
const [isMining, setIsMining] = useState(false);
|
|
||||||
const [isFound, setIsFound] = useState(false);
|
|
||||||
|
|
||||||
// The mining difficulty, i.e., the required number of leading zeros
|
|
||||||
const difficulty = "00";
|
|
||||||
|
|
||||||
// Memoize the combined data to avoid recalculating on every render
|
|
||||||
const combinedData = useMemo(
|
|
||||||
() => `${challenge}${nonce}`,
|
|
||||||
[challenge, nonce],
|
|
||||||
);
|
|
||||||
|
|
||||||
// This effect hook recalculates the hash whenever the combinedData changes.
|
|
||||||
useEffect(() => {
|
|
||||||
let isMounted = true;
|
|
||||||
const calculateHash = async () => {
|
|
||||||
const calculatedHash = await sha256(combinedData);
|
|
||||||
if (isMounted) {
|
|
||||||
setHash(calculatedHash);
|
|
||||||
setIsFound(calculatedHash.startsWith(difficulty));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
calculateHash();
|
|
||||||
return () => {
|
|
||||||
isMounted = false;
|
|
||||||
};
|
|
||||||
}, [combinedData, difficulty]);
|
|
||||||
|
|
||||||
// This effect handles the automatic mining process
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isMining) return;
|
|
||||||
|
|
||||||
let miningNonce = nonce;
|
|
||||||
let continueMining = true;
|
|
||||||
|
|
||||||
const mine = async () => {
|
|
||||||
while (continueMining) {
|
|
||||||
const currentData = `${challenge}${miningNonce}`;
|
|
||||||
const currentHash = await sha256(currentData);
|
|
||||||
|
|
||||||
if (currentHash.startsWith(difficulty)) {
|
|
||||||
setNonce(miningNonce);
|
|
||||||
setIsMining(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
miningNonce++;
|
|
||||||
// Update the UI periodically to avoid freezing the browser
|
|
||||||
if (miningNonce % 100 === 0) {
|
|
||||||
setNonce(miningNonce);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 0)); // Yield to the browser
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mine();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
continueMining = false;
|
|
||||||
};
|
|
||||||
}, [isMining, challenge, nonce, difficulty]);
|
|
||||||
|
|
||||||
const handleMineClick = () => {
|
|
||||||
setIsMining(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStopClick = () => {
|
|
||||||
setIsMining(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleResetClick = () => {
|
|
||||||
setIsMining(false);
|
|
||||||
setNonce(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNewChallengeClick = () => {
|
|
||||||
setIsMining(false);
|
|
||||||
setChallenge(generateRandomHex(16));
|
|
||||||
setNonce(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper to render the hash with colored leading characters
|
|
||||||
const renderHash = () => {
|
|
||||||
if (!hash) return <span>...</span>;
|
|
||||||
const prefix = hash.substring(0, difficulty.length);
|
|
||||||
const suffix = hash.substring(difficulty.length);
|
|
||||||
const prefixColor = isFound ? styles.hashPrefixGreen : styles.hashPrefixRed;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<span className={`${prefixColor} ${styles.hashPrefix}`}>{prefix}</span>
|
|
||||||
<span className={styles.hashSuffix}>{suffix}</span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.innerContainer}>
|
|
||||||
<div className={styles.grid}>
|
|
||||||
{/* Challenge Block */}
|
|
||||||
<div className={styles.block}>
|
|
||||||
<h2 className={styles.blockTitle}>1. Challenge</h2>
|
|
||||||
<p className={styles.challengeText}>{challenge}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Nonce Control Block */}
|
|
||||||
<div className={styles.block}>
|
|
||||||
<h2 className={styles.blockTitle}>2. Nonce</h2>
|
|
||||||
<div className={styles.nonceControls}>
|
|
||||||
<button
|
|
||||||
onClick={() => setNonce((n) => n - 1)}
|
|
||||||
disabled={isMining}
|
|
||||||
className={styles.nonceButton}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={styles.iconSmall}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M20 12H4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<span className={styles.nonceValue}>{nonce}</span>
|
|
||||||
<button
|
|
||||||
onClick={() => setNonce((n) => n + 1)}
|
|
||||||
disabled={isMining}
|
|
||||||
className={styles.nonceButton}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={styles.iconSmall}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M12 4v16m8-8H4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Combined Data Block */}
|
|
||||||
<div className={styles.block}>
|
|
||||||
<h2 className={styles.blockTitle}>3. Combined Data</h2>
|
|
||||||
<p className={styles.combinedDataText}>{combinedData}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Arrow pointing down */}
|
|
||||||
<div className={styles.arrowContainer}>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={styles.iconGray}
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M19 14l-7 7m0 0l-7-7m7 7V3"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hash Output Block */}
|
|
||||||
<div
|
|
||||||
className={`${styles.hashContainer} ${isFound ? styles.hashContainerSuccess : styles.hashContainerError}`}
|
|
||||||
>
|
|
||||||
<div className={styles.hashContent}>
|
|
||||||
<div className={styles.hashText}>
|
|
||||||
<h2 className={styles.blockTitle}>4. Resulting Hash (SHA-256)</h2>
|
|
||||||
<p className={styles.hashValue}>{renderHash()}</p>
|
|
||||||
</div>
|
|
||||||
<div className={styles.hashIcon}>
|
|
||||||
{isFound ? <CheckIcon /> : <XCircleIcon />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Mining Controls */}
|
|
||||||
<div className={styles.buttonContainer}>
|
|
||||||
{!isMining ? (
|
|
||||||
<button
|
|
||||||
onClick={handleMineClick}
|
|
||||||
className={`${styles.button} ${styles.buttonCyan}`}
|
|
||||||
>
|
|
||||||
Auto-Mine
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
onClick={handleStopClick}
|
|
||||||
className={`${styles.button} ${styles.buttonYellow}`}
|
|
||||||
>
|
|
||||||
Stop Mining
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
onClick={handleNewChallengeClick}
|
|
||||||
className={`${styles.button} ${styles.buttonIndigo}`}
|
|
||||||
>
|
|
||||||
New Challenge
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleResetClick}
|
|
||||||
className={`${styles.button} ${styles.buttonGray}`}
|
|
||||||
>
|
|
||||||
Reset Nonce
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,370 +0,0 @@
|
|||||||
/* Main container styles */
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: white;
|
|
||||||
font-family: ui-sans-serif, system-ui, sans-serif;
|
|
||||||
margin-top: 2rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.innerContainer {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 56rem;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header styles */
|
|
||||||
.header {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 2.25rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: rgb(34 211 238);
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
color: rgb(156 163 175);
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grid layout styles */
|
|
||||||
.grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
gap: 1rem;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Block styles */
|
|
||||||
.block {
|
|
||||||
background-color: rgb(31 41 55);
|
|
||||||
padding: 1.5rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
box-shadow:
|
|
||||||
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
||||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blockTitle {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: rgb(34 211 238);
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.challengeText {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: rgb(209 213 219);
|
|
||||||
word-break: break-all;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.combinedDataText {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: rgb(156 163 175);
|
|
||||||
word-break: break-all;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nonce control styles */
|
|
||||||
.nonceControls {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceButton {
|
|
||||||
background-color: rgb(55 65 81);
|
|
||||||
border-radius: 9999px;
|
|
||||||
padding: 0.5rem;
|
|
||||||
transition: background-color 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceButton:hover:not(:disabled) {
|
|
||||||
background-color: rgb(34 211 238);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceButton:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceValue {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
||||||
width: 6rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Icon styles */
|
|
||||||
.icon {
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconGreen {
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
color: rgb(74 222 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconRed {
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
color: rgb(248 113 113);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconSmall {
|
|
||||||
height: 1.5rem;
|
|
||||||
width: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconGray {
|
|
||||||
height: 2.5rem;
|
|
||||||
width: 2.5rem;
|
|
||||||
color: rgb(75 85 99);
|
|
||||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Arrow animation */
|
|
||||||
@keyframes pulse {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrowContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hash output styles */
|
|
||||||
.hashContainer {
|
|
||||||
padding: 1.5rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
box-shadow:
|
|
||||||
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
|
||||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
||||||
transition: all 300ms;
|
|
||||||
border: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContainerSuccess {
|
|
||||||
background-color: rgb(20 83 45 / 0.5);
|
|
||||||
border-color: rgb(74 222 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContainerError {
|
|
||||||
background-color: rgb(127 29 29 / 0.5);
|
|
||||||
border-color: rgb(248 113 113);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContent {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashText {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashTextLg {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashValue {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashValueLg {
|
|
||||||
font-size: 1rem;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashIcon {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashIconLg {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hash highlighting */
|
|
||||||
.hashPrefix {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashPrefixGreen {
|
|
||||||
color: rgb(74 222 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashPrefixRed {
|
|
||||||
color: rgb(248 113 113);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashSuffix {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
||||||
color: rgb(156 163 175);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Button styles */
|
|
||||||
.buttonContainer {
|
|
||||||
margin-top: 2rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 0.75rem 1.5rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
transition: transform 150ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonCyan {
|
|
||||||
background-color: rgb(8 145 178);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonCyan:hover {
|
|
||||||
background-color: rgb(6 182 212);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonYellow {
|
|
||||||
background-color: rgb(202 138 4);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonYellow:hover {
|
|
||||||
background-color: rgb(245 158 11);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonIndigo {
|
|
||||||
background-color: rgb(79 70 229);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonIndigo:hover {
|
|
||||||
background-color: rgb(99 102 241);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonGray {
|
|
||||||
background-color: rgb(55 65 81);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonGray:hover {
|
|
||||||
background-color: rgb(75 85 99);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive styles */
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.title {
|
|
||||||
font-size: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContent {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashText {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashValue {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashIcon {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
.grid {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
.block {
|
|
||||||
background-color: oklch(93% 0.034 272.788);
|
|
||||||
}
|
|
||||||
|
|
||||||
.challengeText {
|
|
||||||
color: oklch(12.9% 0.042 264.695);
|
|
||||||
}
|
|
||||||
|
|
||||||
.combinedDataText {
|
|
||||||
color: oklch(12.9% 0.042 264.695);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceButton {
|
|
||||||
background-color: oklch(88.2% 0.059 254.128);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nonceValue {
|
|
||||||
color: oklch(12.9% 0.042 264.695);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blockTitle {
|
|
||||||
color: oklch(45% 0.085 224.283);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContainerSuccess {
|
|
||||||
background-color: oklch(95% 0.052 163.051);
|
|
||||||
border-color: rgb(74 222 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashContainerError {
|
|
||||||
background-color: oklch(94.1% 0.03 12.58);
|
|
||||||
border-color: rgb(248 113 113);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashPrefixGreen {
|
|
||||||
color: oklch(53.2% 0.157 131.589);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashPrefixRed {
|
|
||||||
color: oklch(45.5% 0.188 13.697);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashSuffix {
|
|
||||||
color: oklch(27.9% 0.041 260.031);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
---
|
|
||||||
slug: 2025/cpu-core-odd
|
|
||||||
title: Sometimes CPU cores are odd
|
|
||||||
description: "TL;DR: all the assumptions you have about processor design are wrong and if you are unlucky you will never run into problems that users do through sheer chance."
|
|
||||||
authors: [xe]
|
|
||||||
tags:
|
|
||||||
- bugfix
|
|
||||||
- implementation
|
|
||||||
image: parc-dsilence.webp
|
|
||||||
---
|
|
||||||
|
|
||||||
import ProofOfWorkDiagram from "./ProofOfWorkDiagram";
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
One of the biggest lessons that I've learned in my career is that all software has bugs, and the more complicated your software gets the more complicated your bugs get. A lot of the time those bugs will be fairly obvious and easy to spot, validate, and replicate. Sometimes, the process of fixing it will uncover your core assumptions about how things work in ways that will leave you feeling like you just got trolled.
|
|
||||||
|
|
||||||
Today I'm going to talk about a single line fix that prevents people on a large number of devices from having weird irreproducible issues with Anubis rejecting people when it frankly shouldn't. Stick around, it's gonna be a wild ride.
|
|
||||||
|
|
||||||
{/* truncate */}
|
|
||||||
|
|
||||||
## How this happened
|
|
||||||
|
|
||||||
Anubis is a web application firewall that tries to make sure that the client is a browser. It uses a few [challenge methods](/docs/admin/configuration/challenges/) to do this determination, but the main method is the [proof of work](/docs/admin/configuration/challenges/proof-of-work/) challenge which makes clients grind away at cryptographic checksums in order to rate limit clients from connecting too eagerly.
|
|
||||||
|
|
||||||
:::note
|
|
||||||
|
|
||||||
In retrospect implementing the proof of work challenge may have been a mistake and it's likely to be supplanted by things like [Proof of React](https://github.com/TecharoHQ/anubis/pull/1038) or other methods that have yet to be developed. Your patience and polite behaviour in the bug tracker is appreciated.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
In order to make sure the proof of work challenge screen _goes away as fast as possible_, the [worker code](https://github.com/TecharoHQ/anubis/tree/main/web/js/worker) is optimized within an inch of its digital life. One of the main ways that this code is optimized is with how it's run. Over the last 10-20 years, the main way that CPUs have gotten fast is via increasing multicore performance. Anubis tries to make sure that it can use as many cores as possible in order to take advantage of your device's CPU as much as it can.
|
|
||||||
|
|
||||||
This strategy sometimes has some issues though, for one Firefox seems to get _much slower_ if you have Anubis try to absolutely saturate all of the cores on the system. It also has a fairly high overhead between JavaScript JIT code and [WebCrypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). I did some testing and found out that Firefox's point of diminishing returns was about half of the CPU cores.
|
|
||||||
|
|
||||||
## Another "invalid response" bug
|
|
||||||
|
|
||||||
One of the complaints I've been getting from users and administrators using Anubis is that they've been running into issues where users get randomly rejected with an error message only saying "invalid response". This happens when the challenge validating process fails. This issue has been blocking the release of the next version of Anubis.
|
|
||||||
|
|
||||||
In order to demonstrate this better, I've made a little interactive diagram for the proof of work process:
|
|
||||||
|
|
||||||
<ProofOfWorkDiagram />
|
|
||||||
|
|
||||||
I've fixed a lot of the easy bugs in Anubis by this point. A lot of what's left is the hard bugs, but also specifically the kinds of hard bugs that involve weird hardware configurations. In order to try and catch these issues before software hits prod, I test Anubis against a bunch of hardware I have locally. Any issues I find and fix before software ships are issues that you don't hit in production.
|
|
||||||
|
|
||||||
Let's consider [the line of code](https://github.com/TecharoHQ/anubis/blob/main/web/js/algorithms/fast.mjs) that was causing this issue:
|
|
||||||
|
|
||||||
```js
|
|
||||||
threads = Math.max(navigator.hardwareConcurrency / 2, 1),
|
|
||||||
```
|
|
||||||
|
|
||||||
This is intended to make your browser spawn a proof of work worker for _half_ of your available CPU cores. If you only have one CPU core, you should only have one worker. Each thread is given this number of threads and uses that to increment the nonce so that each thread doesn't try to find a solution that another worker has already performed.
|
|
||||||
|
|
||||||
One of the subtle problems here is that all of the parts of this assume that the thread ID and nonce are integers without a decimal portion. Famously, [all JavaScript numbers are IEEE 754 floating point numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number). Surely there wouldn't be a case where the thread count could be a _decimal_ number, right?
|
|
||||||
|
|
||||||
Here's all the devices I use to test Anubis _and their core counts_:
|
|
||||||
|
|
||||||
| Device Name | Core Count |
|
|
||||||
| :--------------------------- | :--------- |
|
|
||||||
| MacBook Pro M3 Max | 16 |
|
|
||||||
| MacBook Pro M4 Max | 16 |
|
|
||||||
| AMD Ryzen 9 7950x3D | 32 |
|
|
||||||
| Google Pixel 9a (GrapheneOS) | 8 |
|
|
||||||
| iPhone 15 Pro Max | 6 |
|
|
||||||
| iPad Pro (M1) | 8 |
|
|
||||||
| iPad mini | 6 |
|
|
||||||
| Steam Deck | 8 |
|
|
||||||
| Core i5 10600 (homelab) | 12 |
|
|
||||||
| ROG Ally | 16 |
|
|
||||||
|
|
||||||
Notice something? All of those devices have an _even_ number of cores. Some devices such as the [Pixel 8 Pro](https://www.gsmarena.com/google_pixel_8_pro-12545.php) have an _odd_ number of cores. So what happens with that line of code as the JavaScript engine evaluates it?
|
|
||||||
|
|
||||||
Let's replace the [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) with the Pixel 8 Pro's 9 cores:
|
|
||||||
|
|
||||||
```js
|
|
||||||
threads = Math.max(9 / 2, 1),
|
|
||||||
```
|
|
||||||
|
|
||||||
Then divide it by two:
|
|
||||||
|
|
||||||
```js
|
|
||||||
threads = Math.max(4.5, 1),
|
|
||||||
```
|
|
||||||
|
|
||||||
Oops, that's not ideal. However `4.5` is bigger than `1`, so [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) returns that:
|
|
||||||
|
|
||||||
```js
|
|
||||||
threads = 4.5,
|
|
||||||
```
|
|
||||||
|
|
||||||
This means that each time the proof of work equation is calculated, there is a 50% chance that a valid solution would include a nonce with a decimal portion in it. If the client finds a solution with such a nonce, then it would think the client was successful and submit the solution to the server, but the server only expects whole numbers back so it rejects that as an invalid response.
|
|
||||||
|
|
||||||
I keep telling more junior people that when you have the weirdest, most inconsistent bugs in software that it's going to boil down to the dumbest possible thing you can possibly imagine. People don't believe me, then they encounter bugs like this. Then they suddenly believe me.
|
|
||||||
|
|
||||||
Here is the fix:
|
|
||||||
|
|
||||||
```js
|
|
||||||
threads = Math.trunc(Math.max(navigator.hardwareConcurrency / 2, 1)),
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses [`Math.trunc`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc) to truncate away the decimal portion so that the Pixel 8 Pro has `4` workers instead of `4.5` workers.
|
|
||||||
|
|
||||||
## Today I learned this was possible
|
|
||||||
|
|
||||||
This was a total "today I learned" moment. I didn't actually think that hardware vendors shipped processors with an odd number of cores, however if you look at the core geometry of the Pixel 8 Pro, it has _three_ tiers of processor cores:
|
|
||||||
|
|
||||||
| Core type | Core model | Number |
|
|
||||||
| :----------------- | :------------------- | :----- |
|
|
||||||
| High performance | 3 Ghz Cortex X3 | 1 |
|
|
||||||
| Medium performance | 2.45 Ghz Cortex A715 | 4 |
|
|
||||||
| High efficiency | 2.15 Cortex A510 | 4 |
|
|
||||||
| Total | | 9 |
|
|
||||||
|
|
||||||
I guess every assumption that developers have about CPU design is probably wrong.
|
|
||||||
|
|
||||||
This probably isn't helped by the fact that for most of my career, the core count in phones has been largely irrelevant and most of the desktop / laptop CPUs I've had (where core count does matter) uses [simultaneous multithreading](https://en.wikipedia.org/wiki/Simultaneous_multithreading) to "multiply" the core count by two.
|
|
||||||
|
|
||||||
The client side fix is a bit of an "emergency stop" button to try and mitigate the badness as early as possible. In general I'm quite aware of the terrible UX involved with this flow failing and I'm still noodling through ways to make that UX better and easier for users / administrators to debug.
|
|
||||||
|
|
||||||
I'm looking into the following:
|
|
||||||
|
|
||||||
1. This could have been prevented on the server side by doing less strict input validation in compliance with [Postel's Law](https://en.wikipedia.org/wiki/Robustness_principle). I feel nervous about making such a security-sensitive endpoint _more liberal_ with the inputs it can accept, but it may be fine? I need to consult with a security expert.
|
|
||||||
2. Showing an encrypted error message on the "invalid response" page so that the user and administrator can work together to fix or report the issue. I remember Google doing this at least once, but I can't recall where I've seen it in the past. Either way, this is probably the most robust method even though it would require developing some additional tooling. I think it would be worth it.
|
|
||||||
|
|
||||||
I'm likely going to go with the second option. I will need to figure out a good flow for this. It's likely going to involve [age](https://github.com/FiloSottile/age). I'll say more about this when I have more to say.
|
|
||||||
|
|
||||||
In the meantime though, looks like I need to expense a used Pixel 8 Pro to add to the testing jungle for Anubis. If anyone has a deal out there, please let me know!
|
|
||||||
|
|
||||||
Thank you to the people that have been polite and helpful when trying to root cause and fix this issue.
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,75 +0,0 @@
|
|||||||
---
|
|
||||||
slug: 2025/file-abuse-reports
|
|
||||||
title: Taking steps to end abusive traffic from cloud providers
|
|
||||||
description: "Learn how to effectively file abuse reports with cloud providers to stop malicious traffic at its source and protect your services from automated abuse."
|
|
||||||
authors: [xe]
|
|
||||||
tags: [abuse, cloud, security, networking]
|
|
||||||
image: goose-pond.webp
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
As part of Anubis's ongoing development, I've been working to reduce friction for legitimate users by minimizing unnecessary challenge pages. While this improves the user experience, it can potentially expose services to increased abuse from public cloud infrastructure. To help administrators better protect their services, I want to share my strategies for filing abuse reports with IP space owners, enabling us to address malicious scraping at its source.
|
|
||||||
|
|
||||||
{/* truncate */}
|
|
||||||
|
|
||||||
In general, there are two kinds of IP addresses:
|
|
||||||
|
|
||||||
- Residential IP addresses: IP addresses that are allocated to residential customers such as home internet connections and cellular data plans. These IP addresses are increasingly shared between customers due to technologies like [CGNAT](https://en.wikipedia.org/wiki/Carrier-grade_NAT).
|
|
||||||
- Commercial IP addresses: IP addresses that are allocated to commercial customers such as cloud providers, VPS providers, root server providers, and other such business to business companies. These IP addresses are almost always statically allocated to one customer for a very long period of time (typically the lifetime of the server unless they are using things like dedicated IP addresses).
|
|
||||||
|
|
||||||
In general, filing abuse reports to residential IP addresses is a waste of time. The administrators do appreciate knowing what kinds of abusive traffic is causing grief, but many times the users of those IP addresses don't know that their computer is sending abusive traffic to your services. A lot of malware botnets that used to be used with DDOS for hire services are now being used as residential proxies. Those "free VPN apps" are almost certainly making you pay for your usage by making your computer a zombie in a botnet. At some level I really respect the hustle as they manage to sell other people's bandwidth for rates as ludicrous as $1.00 per gigabyte ingressed and egressed.
|
|
||||||
|
|
||||||
:::note
|
|
||||||
|
|
||||||
Keep in mind, I'm talking about the things you can find by searching "free VPN", not infrastructure for the public good like the Tor browser or I2P.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
What you should really focus on is traffic from commercial IP addresses, such as cloud providers. That's a case where the cloud customer is in direct violation of the acceptable use policy of the provider. Filing abuse reports gets the abuse team of the cloud provider to reach out to that customer and demand corrective action under threat of contractual violence.
|
|
||||||
|
|
||||||
## How to make an abuse report
|
|
||||||
|
|
||||||
In general, the best abuse reports contain the following information:
|
|
||||||
|
|
||||||
- Time of abusive requests.
|
|
||||||
- IP address, User-Agent header, or other unique identifiers that can help the abuse team educate the customer about their misbehaving infrastructure.
|
|
||||||
- Does the abusive IP address request robots.txt? If not, be sure to include that information.
|
|
||||||
- A brief description of the impact to your system such as high system load, pages not rendering, or database system crashes. This helps the provider establish the fact that their customer is causing you measurable harm.
|
|
||||||
- Context as to what your service is, what it does, and why they should care.
|
|
||||||
|
|
||||||
For example, let's say that someone was giving the Anubis docs a series of requests that caused the server to fall over and experience extended downtime. Here's what I would write to the abuse contact:
|
|
||||||
|
|
||||||
> Hello,
|
|
||||||
>
|
|
||||||
> I have received abusive traffic from one of your customers that has resulted in a denial of service to the users of the Anubis documentation website. Anubis is a web application firewall that administrators use to protect their websites against mass scraping and this documentation website helps administrators get started.
|
|
||||||
>
|
|
||||||
> On or about Thursday, October 30th at 04:00 UTC, A flurry of requests from the IP range `127.34.0.0/24` started to hit the `/admin/` routes, which caused unreasonable database load and ended up crashing PostgreSQL. This caused the documentation website to go down for three hours as it happened while the administrators were asleep. Based on logs, this caused 353 distinct users to not be able to load the documentation and the users filed bugs about it.
|
|
||||||
>
|
|
||||||
> I have attached the HTTP frontend logs for the abusive requests from your IP range. To protect our systems in the meantime while we perform additional hardening, I have blocked that IP address range in both our IP firewall and web application firewall configuration. Based on these logs, your customer seems to not have requested the standard `robots.txt` file, which includes instructions to deny access to those routes.
|
|
||||||
>
|
|
||||||
> Please let me know what other information you need on your end.
|
|
||||||
>
|
|
||||||
> Sincerely,
|
|
||||||
>
|
|
||||||
> [normal email signature]
|
|
||||||
|
|
||||||
Then in order to figure out where to send it, look the IP addresses up in the `whois` database. For example, if you want to find the abuse contact for the IP address `1.1.1.1`, use the [whois command](https://packages.debian.org/sid/whois) to find the abuse contact:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ whois 1.1.1.1 | grep -i abuse
|
|
||||||
% Abuse contact for '1.1.1.0 - 1.1.1.255' is 'helpdesk@apnic.net'
|
|
||||||
abuse-c: AA1412-AP
|
|
||||||
remarks: All Cloudflare abuse reporting can be done via
|
|
||||||
remarks: resolver-abuse@cloudflare.com
|
|
||||||
abuse-mailbox: helpdesk@apnic.net
|
|
||||||
role: ABUSE APNICRANDNETAU
|
|
||||||
abuse-mailbox: helpdesk@apnic.net
|
|
||||||
mnt-by: APNIC-ABUSE
|
|
||||||
```
|
|
||||||
|
|
||||||
The abuse contact will be named either `abuse-c` or `abuse-mailbox`. For greatest effect, I suggest including all listed email addresses in your email to the abuse contact.
|
|
||||||
|
|
||||||
Once you send your email, you should expect a response within 2 business days at most. If they don't get back to you, please feel free to [contact me](https://xeiaso.net/contact/) so that the default set of Anubis rules can be edited according to patterns I'm seeing across the ecosystem.
|
|
||||||
|
|
||||||
Just remember that many cloud providers do not know how bad the scraping problem is. Filing abuse complaints makes it their problem. They don't want it to be their problem.
|
|
||||||
@@ -11,286 +11,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
- Add iplist2rule tool that lets admins turn an IP address blocklist into an Anubis ruleset.
|
|
||||||
- Add Polish locale ([#1292](https://github.com/TecharoHQ/anubis/pull/1309))
|
|
||||||
- Fix honeypot and imprint links missing `BASE_PREFIX` when deployed behind a path prefix ([#1402](https://github.com/TecharoHQ/anubis/issues/1402))
|
|
||||||
- Improve idle performance in memory storage
|
|
||||||
|
|
||||||
<!-- This changes the project to: -->
|
<!-- This changes the project to: -->
|
||||||
|
|
||||||
## v1.24.0: Y'shtola Rhul
|
- Downstream consumers can change the default [log/slog#Logger](https://pkg.go.dev/log/slog#Logger) instance that Anubis uses by setting `opts.Logger` to your slog instance of choice ([#864](https://github.com/TecharoHQ/anubis/issues/864)).
|
||||||
|
- The [Thoth client](https://anubis.techaro.lol/docs/admin/thoth) is now public in the repo instead of being an internal package.
|
||||||
Anubis is back and better than ever! Lots of minor fixes with some big ones interspersed.
|
- [Custom-AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client)'s default User-Agent has an increased weight by default ([#852](https://github.com/TecharoHQ/anubis/issues/852)).
|
||||||
|
|
||||||
- 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.
|
|
||||||
- Allow more OCI registry clients [based on feedback](https://github.com/TecharoHQ/anubis/pull/1253#issuecomment-3506744184).
|
|
||||||
- Expose services directory in the embedded `(data)` filesystem.
|
|
||||||
- Add Ukrainian locale ([#1044](https://github.com/TecharoHQ/anubis/pull/1044)).
|
|
||||||
- Allow Renovate as an OCI registry client.
|
|
||||||
- Properly handle 4in6 addresses so that IP matching works with those addresses.
|
|
||||||
- Add support to simple Valkey/Redis cluster mode
|
|
||||||
- Open Graph passthrough now reuses the configured target Host/SNI/TLS settings, so metadata fetches succeed when the upstream certificate differs from the public domain. ([1283](https://github.com/TecharoHQ/anubis/pull/1283))
|
|
||||||
- Stabilize the CVE-2025-24369 regression test by always submitting an invalid proof instead of relying on random POW failures.
|
|
||||||
- Refine the check that ensures the presence of the Accept header to avoid breaking docker clients.
|
|
||||||
- Removed rules intended to reward actual browsers due to abuse in the wild.
|
|
||||||
|
|
||||||
### Dataset poisoning
|
|
||||||
|
|
||||||
Anubis has the ability to engage in [dataset poisoning attacks](https://www.anthropic.com/research/small-samples-poison) using the [dataset poisoning subsystem](./admin/honeypot/overview.mdx). This allows every Anubis instance to be a honeypot to attract and flag abusive scrapers so that no administrator action is required to ban them.
|
|
||||||
|
|
||||||
There is much more information about this feature in [the dataset poisoning subsystem documentation](./admin/honeypot/overview.mdx). Administrators that are interested in learning how this feature works should consult that documentation.
|
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
logging:
|
|
||||||
level: "warn" # much less verbose logging
|
|
||||||
sink: file # log to a file
|
|
||||||
parameters:
|
|
||||||
file: "./var/anubis.log"
|
|
||||||
maxBackups: 3 # keep at least 3 old copies
|
|
||||||
maxBytes: 67108864 # each file can have up to 64 Mi of logs
|
|
||||||
maxAge: 7 # rotate files out every n days
|
|
||||||
oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
|
|
||||||
compress: true # gzip-compress old log files
|
|
||||||
useLocalTime: false # timezone for rotated files is UTC
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
- Fix `SERVE_ROBOTS_TXT` setting after the double slash fix broke it.
|
|
||||||
|
|
||||||
### Potentially breaking changes
|
|
||||||
|
|
||||||
#### Remove default Tencent Cloud block rule
|
|
||||||
|
|
||||||
v1.23.0 added a default rule to block Tencent Cloud. After an email from their abuse team where they promised to take action to clean up their reputation, I have removed the default block rule. If this network causes you problems, please contact [abuse@tencent.com](mailto:abuse@tencent.com) and supply the following information:
|
|
||||||
|
|
||||||
- Time of abusive requests.
|
|
||||||
- IP address, User-Agent header, or other unique identifiers that can help the abuse team educate the customer about their misbehaving infrastructure.
|
|
||||||
- Does the abusive IP address request robots.txt? If not, be sure to include that information.
|
|
||||||
- A brief description of the impact to your system such as high system load, pages not rendering, or database system crashes. This helps the provider establish the fact that their customer is causing you measurable harm.
|
|
||||||
- Context as to what your service is, what it does, and why they should care.
|
|
||||||
|
|
||||||
Mention that you are using Anubis or BotStopper to protect your services. If they do not respond to you, please [contact me](https://xeiaso.net/contact) as soon as possible.
|
|
||||||
|
|
||||||
#### Docker / OCI registry clients
|
|
||||||
|
|
||||||
Anubis v1.23.0 accidentally blocked Docker / OCI registry clients. In order to explicitly allow them, add an import for `(data)/clients/docker-client.yaml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
bots:
|
|
||||||
- import: (data)/meta/default-config.yaml
|
|
||||||
- import: (data)/clients/docker-client.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
This is technically a regression as these clients used to work in Anubis v1.22.0, however it is allowable to make this opt-in as most websites do not expect to be serving Docker / OCI registry client traffic.
|
|
||||||
|
|
||||||
## v1.23.0: Lyse Hext
|
|
||||||
|
|
||||||
- Add default tencent cloud DENY rule.
|
|
||||||
- Added `(data)/meta/default-config.yaml` for importing the entire default configuration at once.
|
|
||||||
- Add `-custom-real-ip-header` flag to get the original request IP from a different header than `x-real-ip`.
|
|
||||||
- Add `contentLength` variable to bot expressions.
|
|
||||||
- Add `COOKIE_SAME_SITE_MODE` to force anubis cookies SameSite value, and downgrade automatically from `None` to `Lax` if cookie is insecure.
|
|
||||||
- Fix lock convoy problem in decaymap ([#1103](https://github.com/TecharoHQ/anubis/issues/1103)).
|
|
||||||
- Fix lock convoy problem in bbolt by implementing the actor pattern ([#1103](https://github.com/TecharoHQ/anubis/issues/1103)).
|
|
||||||
- Remove bbolt actorify implementation due to causing production issues.
|
|
||||||
- Document missing environment variables in installation guide: `SLOG_LEVEL`, `COOKIE_PREFIX`, `FORCED_LANGUAGE`, and `TARGET_DISABLE_KEEPALIVE` ([#1086](https://github.com/TecharoHQ/anubis/pull/1086)).
|
|
||||||
- Add validation warning when persistent storage is used without setting signing keys.
|
|
||||||
- Fixed `robots2policy` to properly group consecutive user agents into `any:` instead of only processing the last one ([#925](https://github.com/TecharoHQ/anubis/pull/925)).
|
|
||||||
- Make the `fast` algorithm prefer purejs when running in an insecure context.
|
|
||||||
- Add the [`s3api` storage backend](./admin/policies.mdx#s3api) to allow Anubis to use S3 API compatible object storage as its storage backend.
|
|
||||||
- Fix a "stutter" in the cookie name prefix so the auth cookie is named `techaro.lol-anubis-auth` instead of `techaro.lol-anubis-auth-auth`.
|
|
||||||
- Make `cmd/containerbuild` support commas for separating elements of the `--docker-tags` argument as well as newlines.
|
|
||||||
- Add the `DIFFICULTY_IN_JWT` option, which allows one to add the `difficulty` field in the JWT claims which indicates the difficulty of the token ([#1063](https://github.com/TecharoHQ/anubis/pull/1063)).
|
|
||||||
- Ported the client-side JS to TypeScript to avoid egregious errors in the future.
|
|
||||||
- Fixes concurrency problems with very old browsers ([#1082](https://github.com/TecharoHQ/anubis/issues/1082)).
|
|
||||||
- Randomly use the Refresh header instead of the meta refresh tag in the metarefresh challenge.
|
|
||||||
- Update OpenRC service to truncate the runtime directory before starting Anubis.
|
|
||||||
- Make the git client profile more strictly match how the git client behaves.
|
|
||||||
- Make the default configuration reward users using normal browsers.
|
|
||||||
- Allow multiple consecutive slashes in a row in application paths ([#754](https://github.com/TecharoHQ/anubis/issues/754)).
|
|
||||||
- Add option to set `targetSNI` to special keyword 'auto' to indicate that it should be automatically set to the request Host name ([424](https://github.com/TecharoHQ/anubis/issues/424)).
|
|
||||||
- The Preact challenge has been removed from the default configuration. It will be deprecated in the future.
|
|
||||||
- An open redirect when in subrequest mode has been fixed.
|
|
||||||
|
|
||||||
### Potentially breaking changes
|
|
||||||
|
|
||||||
#### Multiple checks at once has and-like semantics instead of or-like semantics
|
|
||||||
|
|
||||||
Anubis lets you stack multiple checks at once with blocks like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: allow-prometheus
|
|
||||||
action: ALLOW
|
|
||||||
user_agent_regex: ^prometheus-probe$
|
|
||||||
remote_addresses:
|
|
||||||
- 192.168.2.0/24
|
|
||||||
```
|
|
||||||
|
|
||||||
Previously, this only returned ALLOW if _any one_ of the conditions matched. This behaviour has changed to only return ALLOW if _all_ of the conditions match. I expect this to have some issues with user configs, however this fix is grave enough that it's worth the risk of breaking configs. If this bites you, please let me know so we can make an escape hatch.
|
|
||||||
|
|
||||||
### Better error messages
|
|
||||||
|
|
||||||
In order to make it easier for legitimate clients to debug issues with their browser configuration and Anubis, Anubis will emit internal error detail in base 64 so that administrators can chase down issues. Future versions of this may also include a variant that encrypts the error detail messages.
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
Sometimes the enhanced temporal assurance in [#1038](https://github.com/TecharoHQ/anubis/pull/1038) and [#1068](https://github.com/TecharoHQ/anubis/pull/1068) could backfire because Chromium and its ilk randomize the amount of time they wait in order to avoid a timing side channel attack. This has been fixed by both increasing the amount of time a client has to wait for the metarefresh and preact challenges as well as making the server side logic more permissive.
|
|
||||||
|
|
||||||
## v1.22.0: Yda Hext
|
|
||||||
|
|
||||||
> Someone has to make an effort at reconciliation if these conflicts are ever going to end.
|
|
||||||
|
|
||||||
In this release, we finally fix the odd number of CPU cores bug, pave the way for lighter weight challenges, make Anubis more adaptable, and more.
|
|
||||||
|
|
||||||
### Big ticket items
|
|
||||||
|
|
||||||
#### Proof of React challenge
|
|
||||||
|
|
||||||
A new ["proof of React"](./admin/configuration/challenges/preact.mdx) has been added. It runs a simple app in React that has several chained hooks. It is much more lightweight than the proof of work check.
|
|
||||||
|
|
||||||
#### Smaller features
|
|
||||||
|
|
||||||
- The [`segments`](./admin/configuration/expressions.mdx#segments) function was added for splitting a path into its slash-separated segments.
|
- The [`segments`](./admin/configuration/expressions.mdx#segments) function was added for splitting a path into its slash-separated segments.
|
||||||
- Added possibility to disable HTTP keep-alive to support backends not properly handling it.
|
|
||||||
- When issuing a challenge, Anubis stores information about that challenge into the store. That stored information is later used to validate challenge responses. This works around nondeterminism in bot rules. ([#917](https://github.com/TecharoHQ/anubis/issues/917))
|
- When issuing a challenge, Anubis stores information about that challenge into the store. That stored information is later used to validate challenge responses. This works around nondeterminism in bot rules. ([#917](https://github.com/TecharoHQ/anubis/issues/917))
|
||||||
- One of the biggest sources of lag in Firefox has been eliminated: the use of WebCrypto. Now whenever Anubis detects the client is using Firefox (or Pale Moon), it will swap over to a pure-JS implementation of SHA-256 for speed.
|
- When parsing [Open Graph tags](./admin/configuration/open-graph.mdx), add any URLs found in the responses to a temporary "allow cache" so that social preview images work.
|
||||||
- Proof of work solving has had a complete overhaul and rethink based on feedback from browser engine developers, frontend experts, and overall performance profiling.
|
- Proof of work solving has had a complete overhaul and rethink based on feedback from browser engine developers, frontend experts, and overall performance profiling.
|
||||||
|
- One of the biggest sources of lag in Firefox has been eliminated: the use of WebCrypto. Now whenever Anubis detects the client is using Firefox (or Pale Moon), it will swap over to a pure-JS implementation of SHA-256 for speed.
|
||||||
- Optimize the performance of the pure-JS Anubis solver.
|
- Optimize the performance of the pure-JS Anubis solver.
|
||||||
- Web Workers are stored as dedicated JavaScript files in `static/js/workers/*.mjs`.
|
- Web Workers are stored as dedicated JavaScript files in `static/js/workers/*.mjs`.
|
||||||
- Pave the way for non-SHA256 solver methods and eventually one that uses WebAssembly (or WebAssembly code compiled to JS for those that disable WebAssembly).
|
- Pave the way for non-SHA256 solver methods and eventually one that uses WebAssembly (or WebAssembly code compiled to JS for those that disable WebAssembly).
|
||||||
- Legacy JavaScript code has been eliminated.
|
- Legacy JavaScript code has been eliminated.
|
||||||
- When parsing [Open Graph tags](./admin/configuration/open-graph.mdx), add any URLs found in the responses to a temporary "allow cache" so that social preview images work.
|
|
||||||
- The hard dependency on WebCrypto has been removed, allowing a proof of work challenge to work over plain (unencrypted) HTTP.
|
|
||||||
- The Anubis version number is put in the footer of every page.
|
|
||||||
- Add a default block rule for Huawei Cloud.
|
|
||||||
- Add a default block rule for Alibaba Cloud.
|
|
||||||
- Added support to use Traefik forwardAuth middleware.
|
|
||||||
- Add X-Request-URI support so that Subrequest Authentication has path support.
|
|
||||||
- Added glob matching for `REDIRECT_DOMAINS`. You can pass `*.bugs.techaro.lol` to allow redirecting to anything ending with `.bugs.techaro.lol`. There is a limit of 4 wildcards.
|
|
||||||
|
|
||||||
### Fixes
|
|
||||||
|
|
||||||
#### Odd numbers of CPU cores are properly supported
|
|
||||||
|
|
||||||
Some phones have an odd number of CPU cores. This caused [interesting issues](https://anubis.techaro.lol/blog/2025/cpu-core-odd). This was fixed by [using `Math.trunc` to convert the number of CPU cores back into an integer](https://github.com/TecharoHQ/anubis/issues/1043).
|
|
||||||
|
|
||||||
#### Smaller fixes
|
|
||||||
|
|
||||||
- A standard library HTTP server log message about HTTP pipelining not working has been filtered out of Anubis' logs. There is no action that can be taken about it.
|
|
||||||
- Added a missing link to the Caddy installation environment in the installation documentation.
|
|
||||||
- Downstream consumers can change the default [log/slog#Logger](https://pkg.go.dev/log/slog#Logger) instance that Anubis uses by setting `opts.Logger` to your slog instance of choice ([#864](https://github.com/TecharoHQ/anubis/issues/864)).
|
|
||||||
- The [Thoth client](https://anubis.techaro.lol/docs/admin/thoth) is now public in the repo instead of being an internal package.
|
|
||||||
- [Custom-AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client)'s default User-Agent has an increased weight by default ([#852](https://github.com/TecharoHQ/anubis/issues/852)).
|
|
||||||
- Add option for replacing the default explanation text with a custom one ([#747](https://github.com/TecharoHQ/anubis/pull/747))
|
|
||||||
- The contact email in the LibreJS header has been changed.
|
- The contact email in the LibreJS header has been changed.
|
||||||
|
- The hard dependency on WebCrypto has been removed, allowing a proof of work challenge to work over plain (unencrypted) HTTP.
|
||||||
- Firefox for Android support has been fixed by embedding the challenge ID into the pass-challenge route. This also fixes some inconsistent issues with other mobile browsers.
|
- Firefox for Android support has been fixed by embedding the challenge ID into the pass-challenge route. This also fixes some inconsistent issues with other mobile browsers.
|
||||||
|
- The Anubis version number is put in the footer of every page.
|
||||||
|
- The legacy JSON based policy file example has been removed and all documentation for how to write a policy file in JSON has been deleted. JSON based policy files will still work, but YAML is the superior option for Anubis configuration.
|
||||||
|
- A standard library HTTP server log message about HTTP pipelining not working has been filtered out of Anubis' logs. There is no action that can be taken about it.
|
||||||
- The default `favicon` pattern in `data/common/keep-internet-working.yaml` has been updated to permit requests for png/gif/jpg/svg files as well as ico.
|
- The default `favicon` pattern in `data/common/keep-internet-working.yaml` has been updated to permit requests for png/gif/jpg/svg files as well as ico.
|
||||||
- The `--cookie-prefix` flag has been fixed so that it is fully respected.
|
- The `--cookie-prefix` flag has been fixed so that it is fully respected.
|
||||||
- The default patterns in `data/common/keep-internet-working.yaml` have been updated to appropriately escape the '.' character in the regular expression patterns.
|
- The default patterns in `data/common/keep-internet-working.yaml` have been updated to appropriately escape the '.' character in the regular expression patterns.
|
||||||
- Add optional restrictions for JWT based on the value of a header ([#697](https://github.com/TecharoHQ/anubis/pull/697))
|
- Add optional restrictions for JWT based on the value of a header ([#697](https://github.com/TecharoHQ/anubis/pull/697))
|
||||||
- The word "hack" has been removed from the translation strings for Anubis due to incidents involving people misunderstanding that word and sending particularly horrible things to the project lead over email.
|
- The word "hack" has been removed from the translation strings for Anubis due to incidents involving people misunderstanding that word and sending particularly horrible things to the project lead over email.
|
||||||
- Bump AI-robots.txt to version 1.39
|
|
||||||
- Inject adversarial input to break AI coding assistants.
|
|
||||||
- Add better logging when using Subrequest Authentication.
|
|
||||||
|
|
||||||
### Security-relevant changes
|
|
||||||
|
|
||||||
- Add a server-side check for the meta-refresh challenge that makes sure clients have waited for at least 95% of the time that they should.
|
|
||||||
|
|
||||||
#### Fix potential double-spend for challenges
|
|
||||||
|
|
||||||
Anubis operates by issuing a challenge and having the client present a solution for that challenge. Challenges are identified by a unique UUID, which is stored in the database.
|
|
||||||
|
|
||||||
The problem is that a challenge could potentially be used twice by a dedicated attacker making a targeted attack against Anubis. Challenge records did not have a "spent" or "used" field. In total, a dedicated attacker could solve a challenge once and reuse that solution across multiple sessions in order to mint additional tokens.
|
|
||||||
|
|
||||||
This was fixed by adding a "spent" field to challenges in the data store. When a challenge is solved, that "spent" field gets set to `true`. If a future attempt to solve this challenge is observed, it gets rejected.
|
|
||||||
|
|
||||||
With the advent of store based challenge issuance in [#749](https://github.com/TecharoHQ/anubis/pull/749), this means that these challenge IDs are [only good for 30 minutes](https://github.com/TecharoHQ/anubis/blob/e8dfff635015d6c906dddd49cb0eaf591326092a/lib/anubis.go#L130-L135d). Websites using the most recent version of Anubis have limited exposure to this problem.
|
|
||||||
|
|
||||||
Websites using older versions of Anubis have a much more increased exposure to this problem and are encouraged to keep this software updated as often and as frequently as possible.
|
|
||||||
|
|
||||||
Thanks to [@taviso](https://github.com/taviso) for reporting this issue.
|
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|
||||||
- The "slow" frontend solver has been removed in order to reduce maintenance burden. Any existing uses of it will still work, but issue a warning upon startup asking administrators to upgrade to the "fast" frontend solver.
|
- The "slow" frontend solver has been removed in order to reduce maintenance burden. Any existing uses of it will still work, but issue a warning upon startup asking administrators to upgrade to the "fast" frontend solver.
|
||||||
- The legacy JSON based policy file example has been removed and all documentation for how to write a policy file in JSON has been deleted. JSON based policy files will still work, but YAML is the superior option for Anubis configuration.
|
|
||||||
|
|
||||||
### New Locales
|
|
||||||
|
|
||||||
- Lithuanian [#972](https://github.com/TecharoHQ/anubis/pull/972)
|
|
||||||
- Vietnamese [#926](https://github.com/TecharoHQ/anubis/pull/926)
|
|
||||||
|
|
||||||
## v1.21.3: Minfilia Warde - Echo 3
|
## v1.21.3: Minfilia Warde - Echo 3
|
||||||
|
|
||||||
@@ -514,6 +263,7 @@ And some cleanups/refactors were added:
|
|||||||
- Bump AI-robots.txt to version 1.37
|
- Bump AI-robots.txt to version 1.37
|
||||||
- Make progress bar styling more compatible (UXP, etc)
|
- Make progress bar styling more compatible (UXP, etc)
|
||||||
- Add `--strip-base-prefix` flag/envvar to strip the base prefix from request paths when forwarding to target servers
|
- Add `--strip-base-prefix` flag/envvar to strip the base prefix from request paths when forwarding to target servers
|
||||||
|
- Added support to use Traefik forwardAuth middleware
|
||||||
- Fix an off-by-one in the default threshold config
|
- Fix an off-by-one in the default threshold config
|
||||||
- Add functionality for HS512 JWT algorithm
|
- Add functionality for HS512 JWT algorithm
|
||||||
- Add support for dynamic cookie domains with the `--cookie-dynamic-domain`/`COOKIE_DYNAMIC_DOMAIN` flag/envvar
|
- Add support for dynamic cookie domains with the `--cookie-dynamic-domain`/`COOKIE_DYNAMIC_DOMAIN` flag/envvar
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ If you are using Kubernetes, you will need to create an image pull secret:
|
|||||||
kubectl create secret docker-registry \
|
kubectl create secret docker-registry \
|
||||||
techarohq-botstopper \
|
techarohq-botstopper \
|
||||||
--docker-server ghcr.io \
|
--docker-server ghcr.io \
|
||||||
--docker-username any-username \
|
--docker-username your-username \
|
||||||
--docker-password <your-access-token> \
|
--docker-password your-access-token \
|
||||||
|
--docker-email your@email.address
|
||||||
```
|
```
|
||||||
|
|
||||||
Then attach it to your Deployment:
|
Then attach it to your Deployment:
|
||||||
@@ -84,7 +85,7 @@ Follow [the upstream Docker compose directions](https://anubis.techaro.lol/docs/
|
|||||||
OG_EXPIRY_TIME: "24h"
|
OG_EXPIRY_TIME: "24h"
|
||||||
|
|
||||||
+ # botstopper config here
|
+ # botstopper config here
|
||||||
+ CHALLENGE_TITLE: "Doing math for your connection!"
|
+ CHALLENGE_TITLE: "Doing math for your connnection!"
|
||||||
+ ERROR_TITLE: "Something went wrong!"
|
+ ERROR_TITLE: "Something went wrong!"
|
||||||
+ OVERLAY_FOLDER: /assets
|
+ OVERLAY_FOLDER: /assets
|
||||||
+ volumes:
|
+ volumes:
|
||||||
@@ -125,34 +126,6 @@ Your directory tree should look like this, assuming your data is in `./your_fold
|
|||||||
|
|
||||||
For an example directory tree using some off-the-shelf images the Tango icon set, see the [testdata](https://github.com/TecharoHQ/botstopper/tree/main/testdata/static/img) folder.
|
For an example directory tree using some off-the-shelf images the Tango icon set, see the [testdata](https://github.com/TecharoHQ/botstopper/tree/main/testdata/static/img) folder.
|
||||||
|
|
||||||
### Header-based overlay dispatch
|
|
||||||
|
|
||||||
If you run BotStopper in a multi-tenant environment where each tenant needs its own branding, BotStopper supports the ability to use request header values to direct asset reads to different folders under your `OVERLAY_FOLDER`. One of the most common ways to do this is based on the HTTP Host of the request. For example, if you set `ASSET_LOOKUP_HEADER=Host` in BotStopper's environment:
|
|
||||||
|
|
||||||
```text
|
|
||||||
$OVERLAY_FOLDER
|
|
||||||
├── static
|
|
||||||
│ ├── css
|
|
||||||
│ │ ├── custom.css
|
|
||||||
│ │ └── eyesore.css
|
|
||||||
│ └── img
|
|
||||||
│ ├── happy.webp
|
|
||||||
│ ├── pensive.webp
|
|
||||||
│ └── reject.webp
|
|
||||||
└── test.anubis.techaro.lol
|
|
||||||
└── static
|
|
||||||
├── css
|
|
||||||
│ └── custom.css
|
|
||||||
└── img
|
|
||||||
├── happy.webp
|
|
||||||
├── pensive.webp
|
|
||||||
└── reject.webp
|
|
||||||
```
|
|
||||||
|
|
||||||
Requests to `test.anubis.techaro.lol` will load assets in `$OVERLAY_FOLDER/test.anubis.techaro.lol/static` and all other requests will load them from `$OVERLAY_FOLDER/static`.
|
|
||||||
|
|
||||||
For an example, look at [the testdata folder in the BotStopper repo](https://github.com/TecharoHQ/botstopper/tree/main/testdata).
|
|
||||||
|
|
||||||
### Custom CSS
|
### Custom CSS
|
||||||
|
|
||||||
CSS customization is done mainly with CSS variables. View [the example custom CSS file](https://github.com/TecharoHQ/botstopper/blob/main/testdata/static/css/custom.css) for more information about what can be customized.
|
CSS customization is done mainly with CSS variables. View [the example custom CSS file](https://github.com/TecharoHQ/botstopper/blob/main/testdata/static/css/custom.css) for more information about what can be customized.
|
||||||
@@ -224,104 +197,6 @@ $ du -hs *
|
|||||||
8.0K reject.webp
|
8.0K reject.webp
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom HTML templates
|
|
||||||
|
|
||||||
If you need to completely control the HTML layout of all Anubis pages, you can customize the entire page with `USE_TEMPLATES=true`. This uses Go's standard library [html/template](https://pkg.go.dev/html/template) package to template HTML responses. Your templates can contain whatever HTML you want. The only catch is that you MUST include `{{ .Head }}` in the `<head>` element for challenge pages, and you MUST include `{{ .Body }}` in the `<body>` element for all pages.
|
|
||||||
|
|
||||||
In order to use this, you must define the following templates:
|
|
||||||
|
|
||||||
| Template path | Usage |
|
|
||||||
| :----------------------------------------- | :---------------------------------------------- |
|
|
||||||
| `$OVERLAY_FOLDER/templates/challenge.tmpl` | Challenge pages |
|
|
||||||
| `$OVERLAY_FOLDER/templates/error.tmpl` | Error pages |
|
|
||||||
| `$OVERLAY_FOLDER/templates/impressum.tmpl` | [Impressum](./configuration/impressum.mdx) page |
|
|
||||||
|
|
||||||
:::note
|
|
||||||
|
|
||||||
Currently HTML templates don't work together with [Header-based overlay dispatch](#header-based-overlay-dispatch). This is a known issue that will be fixed soon. If you enable header-based overlay dispatch, BotStopper will use the global `templates` folder instead of using the templates present in the overlay.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
Here are minimal (but working) examples for each template:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>`challenge.tmpl`</summary>
|
|
||||||
|
|
||||||
:::note
|
|
||||||
|
|
||||||
You **MUST** include the `{{.Head}}` segment in a `<head>` tag. It contains important information for challenges to execute. If you don't include this, no clients will be able to pass challenges.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="{{ .Lang }}">
|
|
||||||
<head>
|
|
||||||
{{ .Head }}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{ .Body }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>`error.tmpl`</summary>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="{{ .Lang }}">
|
|
||||||
<body>
|
|
||||||
{{ .Body }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>`impressum.tmpl`</summary>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="{{ .Lang }}">
|
|
||||||
<body>
|
|
||||||
{{ .Body }}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Template functions
|
|
||||||
|
|
||||||
In order to make life easier, the following template functions are defined:
|
|
||||||
|
|
||||||
#### `Asset`
|
|
||||||
|
|
||||||
Constructs the path for a static asset in the [overlay folder](#custom-images-and-css)'s `static` directory.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Asset(string) string
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="{{ Asset "css/example.css" }}" />
|
|
||||||
```
|
|
||||||
|
|
||||||
Generates:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="/.within.website/x/cmd/anubis/static/css/example.css"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Customizing messages
|
## Customizing messages
|
||||||
|
|
||||||
You can customize messages using the following environment variables:
|
You can customize messages using the following environment variables:
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# Client IP Headers
|
|
||||||
|
|
||||||
Currently Anubis will always flatten the `X-Forwarded-For` when it contains multiple IP addresses. From right to left, the first IP address that is not in one of the following categories will be set as `X-Forwarded-For` in the request passed to the upstream.
|
|
||||||
|
|
||||||
- Private (`XFF_STRIP_PRIVATE`, enabled by default)
|
|
||||||
- CGNAT (always stripped)
|
|
||||||
- Link-local Unicast (always stripped)
|
|
||||||
|
|
||||||
```
|
|
||||||
Incoming: X-Forwarded-For: 1.2.3.4, 5.6.7.8, 10.0.0.1
|
|
||||||
Upstream: X-Forwarded-For: 5.6.7.8
|
|
||||||
```
|
|
||||||
|
|
||||||
This behavior will cause problems if the proxy in front of Anubis is from a public IP, such as Cloudflare, because Anubis will use the Cloudflare IP instead of your client's real IP. You will likely see all requests from your browser being blocked and/or an infinite challenge loop.
|
|
||||||
|
|
||||||
```
|
|
||||||
Incoming: X-Forwarded-For: REAL_CLIENT_IP, CF_IP
|
|
||||||
Upstream: X-Forwarded-For: CF_IP
|
|
||||||
```
|
|
||||||
|
|
||||||
As a workaround, you should configure your web server to parse an alternative source (such as `CF-Connecting-IP`), or pre-process the incoming `X-Forwarded-For` with your web server to ensure it only contains the real client IP address, then pass it to Anubis as `X-Forwarded-For`.
|
|
||||||
|
|
||||||
If you do not control the web server upstream of Anubis, the `custom-real-ip-header` command line flag accepts a header value that Anubis will read the real client IP address from. Anubis will set the `X-Real-IP` header to the IP address found in the custom header.
|
|
||||||
|
|
||||||
The `X-Real-IP` header will be automatically inferred from `X-Forwarded-For` if not set, setting it explicitly is not necessary as long as `X-Forwarded-For` contains only the real client IP. However setting it explicitly can eliminate spoofed values if your web server doesn't set this.
|
|
||||||
|
|
||||||
See [Cloudflare](environments/cloudflare.mdx) for an example configuration.
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
Anubis supports multiple challenge methods:
|
Anubis supports multiple challenge methods:
|
||||||
|
|
||||||
- [Meta Refresh](./metarefresh.mdx)
|
- [Meta Refresh](./metarefresh.mdx)
|
||||||
- [Preact](./preact.mdx)
|
|
||||||
- [Proof of Work](./proof-of-work.mdx)
|
- [Proof of Work](./proof-of-work.mdx)
|
||||||
|
|
||||||
Read the documentation to know which method is best for you.
|
Read the documentation to know which method is best for you.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user