Compare commits

...

8 Commits

Author SHA1 Message Date
Xe Iaso
082a57a1a0 feat(logging): add option to hide log line source
This is almost certainly going to be a footgun, but it's not too
bad of a change to make. If users really do want to make getting
support more difficult, so be it.

Closes: #1537
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-03-24 15:33:23 +00:00
dependabot[bot]
e42a328843 build(deps): bump actions-hub/kubectl in the github-actions group (#1532)
Bumps the github-actions group with 1 update: [actions-hub/kubectl](https://github.com/actions-hub/kubectl).


Updates `actions-hub/kubectl` from 1.35.2 to 1.35.3
- [Release notes](https://github.com/actions-hub/kubectl/releases)
- [Commits](5ada4e2c02...934aaa4354)

---
updated-dependencies:
- dependency-name: actions-hub/kubectl
  dependency-version: 1.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 15:33:43 +00:00
Michael
c4b26e5a75 l10n(de): revise and update German translations (#1457)
* l10n(de): revise and update German translations

Improve strings for clarity and naturalness, update Wikipedia link to German version.

Signed-off-by: Michael <87752300+michi-onl@users.noreply.github.com>

* test(localization): fix tests

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

---------

Signed-off-by: Michael <87752300+michi-onl@users.noreply.github.com>
Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: Xe Iaso <me@xeiaso.net>
2026-03-21 20:02:49 +00:00
Duy
1342539a41 chore: update vi.json (#1459)
* Update vi.json

Signed-off-by: Duy <104808921+honhatduy@users.noreply.github.com>

* test(localization): fix tests

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

---------

Signed-off-by: Duy <104808921+honhatduy@users.noreply.github.com>
Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: Xe Iaso <me@xeiaso.net>
2026-03-21 20:01:21 +00:00
ramromcode
bd6f654e1f feat(i18n): add Bulgarian language translation (#1394)
* feat(localization): add bulgarian language translation

* fix(locales/bg): make tests pass

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

---------

Signed-off-by: Xe Iaso <xe.iaso@techaro.lol>
Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: Xe Iaso <xe.iaso@techaro.lol>
Co-authored-by: Xe Iaso <me@xeiaso.net>
2026-03-21 19:56:27 +00:00
Xe Iaso
d2c3a326af feat(anubis): enable pprof endpoints on the metrics server (#1530)
Closes: #1366

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-03-21 19:43:47 +00:00
dwhitemv25
c2ed62f51d fix: Address issued raised in #1193 (#1519)
* Resolve #1193

Address documentation and error message issues around REDIRECT_DOMAINS and required keywords in bot specifications.

* Add CHANGELOG entry
2026-03-21 19:32:25 +00:00
Jason Cameron
11c4adc6b4 fix: add cel iterator (#1465)
* fix: enable CEL iterators

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* test: add unit tests for CELChecker map iteration

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* fix: implement map iterators for HTTPHeaders and URLValues to resolve CEL internal errors

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

* fix: replace checker.NewMapIterator with newMapIterator for HTTPHeaders and URLValues

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>

---------

Signed-off-by: Jason Cameron <jason.cameron@stanwith.me>
2026-03-21 19:30:05 +00:00
19 changed files with 264 additions and 71 deletions

View File

@@ -53,14 +53,14 @@ jobs:
push: true
- name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@5ada4e2c02eacc03978c2437e95c8b0f979a9619 # v1.35.2
uses: actions-hub/kubectl@934aaa4354bbbc3d2176ae8d7cae92d515032dff # v1.35.3
env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with:
args: apply -k docs/manifest
- name: Apply k8s manifests to limsa lominsa
uses: actions-hub/kubectl@5ada4e2c02eacc03978c2437e95c8b0f979a9619 # v1.35.2
uses: actions-hub/kubectl@934aaa4354bbbc3d2176ae8d7cae92d515032dff # v1.35.3
env:
KUBE_CONFIG: ${{ secrets.LIMSA_LOMINSA_KUBECONFIG }}
with:

View File

@@ -17,6 +17,7 @@ import (
"net"
"net/http"
"net/http/httputil"
"net/http/pprof"
"net/url"
"os"
"os/signal"
@@ -275,7 +276,7 @@ func main() {
internal.SetHealth("anubis", healthv1.HealthCheckResponse_NOT_SERVING)
lg := internal.InitSlog(*slogLevel, os.Stderr)
lg := internal.InitSlog(*slogLevel, os.Stderr, false)
lg.Info("starting up Anubis")
if *healthcheck {
@@ -427,7 +428,7 @@ func main() {
redirectDomainsList = append(redirectDomainsList, strings.TrimSpace(domain))
}
} 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")
lg.Warn("REDIRECT_DOMAINS is not set, Anubis will redirect to any domain, see https://anubis.techaro.lol/docs/admin/configuration/redirect-domains")
}
anubis.CookieName = *cookiePrefix + "-auth"
@@ -522,6 +523,11 @@ func metricsServer(ctx context.Context, lg slog.Logger, done func()) {
defer done()
mux := http.NewServeMux()
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
st, ok := internal.GetHealth("anubis")

View File

@@ -28,7 +28,7 @@ func main() {
flagenv.Parse()
flag.Parse()
slog.SetDefault(internal.InitSlog(*slogLevel, os.Stderr))
slog.SetDefault(internal.InitSlog(*slogLevel, os.Stderr, false))
koDockerRepo := strings.TrimSuffix(*dockerRepo, "/"+filepath.Base(*dockerRepo))
@@ -159,8 +159,8 @@ func run(command string) (string, error) {
}
func setOutput(key, val string) {
github_output := os.Getenv("GITHUB_OUTPUT")
f, _ := os.OpenFile(github_output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
fmt.Fprintf(f, "%s=%s\n", key, val)
f.Close()
github_output := os.Getenv("GITHUB_OUTPUT")
f, _ := os.OpenFile(github_output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
fmt.Fprintf(f, "%s=%s\n", key, val)
f.Close()
}

View File

@@ -11,12 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Expose [pprof endpoints](https://pkg.go.dev/net/http/pprof) on the metrics listener to enable profiling Anubis in production.
- fix: prevent nil pointer panic in challenge validation when threshold rules match during PassChallenge (#1463)
- Instruct reverse proxies to not cache error pages.
- Fixed mixed tab/space indentation in Caddy documentation code block
- Improve error messages and fix broken REDIRECT_DOMAINS link in docs ([#1193](https://github.com/TecharoHQ/anubis/issues/1193))
- Add Bulgarian locale ([#1394](https://github.com/TecharoHQ/anubis/pull/1394))
- Add option to hide source code origin of log lines in [logging configuration](./admin/policies.mdx#logging-management)
<!-- This changes the project to: -->
- Fix CEL internal errors when iterating `headers`/`query` map wrappers by implementing map iterators for `HTTPHeaders` and `URLValues` ([#1465](https://github.com/TecharoHQ/anubis/pull/1465)).
## v1.25.0: Necron
Hey all,

View File

@@ -95,7 +95,7 @@ Anubis uses these environment variables for configuration:
| `OVERLAY_FOLDER` | unset | <EO /> If set, treat the given path as an [overlay folder](./botstopper.mdx#custom-images-and-css), allowing you to customize CSS, fonts, images, and add other assets to BotStopper deployments. |
| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.mdx). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. |
| `PUBLIC_URL` | unset | The externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for Traefik forwardAuth). Leave it unset when Anubis terminates traffic directly (sidecar/standalone deployments) or redirect building will fail with `redir=null`. |
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains) for more details. |
| `REDIRECT_DOMAINS` | unset | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains.mdx) for more details. |
| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. |
| `SLOG_LEVEL` | `INFO` | The log level for structured logging. Valid values are `DEBUG`, `INFO`, `WARN`, and `ERROR`. Set to `DEBUG` to see all requests, evaluations, and detailed diagnostic information. |
| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. |

View File

@@ -339,6 +339,7 @@ Anubis exposes the following logging settings in the policy file:
| `level` | [log level](#log-levels) | `info` | The logging level threshold. Any logs that are at or above this threshold will be drained to the sink. Any other logs will be discarded. |
| `sink` | string | `stdio`, `file` | The sink where the logs drain to as they are being recorded in Anubis. |
| `parameters` | object | | Parameters for the given logging sink. This will vary based on the logging sink of choice. See below for more information. |
| `hideSource` | boolean | `false` | If set, hide the details of which line of code triggered a log line. Setting this to `true` may make getting support more difficult. |
Anubis supports the following logging sinks:

View File

@@ -10,7 +10,7 @@ import (
"strings"
)
func InitSlog(level string, sink io.Writer) *slog.Logger {
func InitSlog(level string, sink io.Writer, hideSource bool) *slog.Logger {
var programLevel slog.Level
if err := (&programLevel).UnmarshalText([]byte(level)); err != nil {
fmt.Fprintf(os.Stderr, "invalid log level %s: %v, using info\n", level, err)
@@ -20,10 +20,16 @@ func InitSlog(level string, sink io.Writer) *slog.Logger {
leveler := &slog.LevelVar{}
leveler.Set(programLevel)
h := slog.NewJSONHandler(sink, &slog.HandlerOptions{
opts := &slog.HandlerOptions{
AddSource: true,
Level: leveler,
})
}
if hideSource {
opts.AddSource = false
}
h := slog.NewJSONHandler(sink, opts)
result := slog.New(h)
return result
}

View File

@@ -19,7 +19,7 @@ import (
var (
ErrNoBotRulesDefined = errors.New("config: must define at least one (1) bot rule")
ErrBotMustHaveName = errors.New("config.Bot: must set name")
ErrBotMustHaveUserAgentOrPath = errors.New("config.Bot: must set either user_agent_regex, path_regex, headers_regex, or remote_addresses")
ErrBotMustHaveUserAgentOrPath = errors.New("config.Bot: must set one of user_agent_regex, path_regex, headers_regex, remote_addresses, expression, or Thoth keyword")
ErrBotMustHaveUserAgentOrPathNotBoth = errors.New("config.Bot: must set either user_agent_regex, path_regex, and not both")
ErrUnknownAction = errors.New("config.Bot: unknown action")
ErrInvalidUserAgentRegex = errors.New("config.Bot: invalid user agent regex")

View File

@@ -17,6 +17,7 @@ type Logging struct {
Sink string `json:"sink"` // Logging sink, either "stdio" or "file"
Level *slog.Level `json:"level"` // Log level, if set supersedes the level in flags
Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future
HideSource bool `json:"hideSource"` // If true, hide the `source` field in log lines
}
const (

View File

@@ -0,0 +1,66 @@
{
"loading": "Зареждане...",
"why_am_i_seeing": "Защо виждам това?",
"protected_by": "Защитено от",
"protected_from": "От",
"made_with": "Направено с ❤️ в 🇨🇦",
"mascot_design": "Дизайн на талисмана от",
"ai_companies_explanation": "Виждате това, защото администраторът на този уебсайт е kонфигурирал Anubis, за да защити сървъра от агресивното събиране на данни от компании, занимаващи се с изкуствен интелект. Това може и причинява прекъсвания на уебсайтовете, което прави техните ресурси недостъпни за всички.",
"anubis_compromise": "Anubis е компромис. Anubis използва схема за ддоказателство-за-работа по подобие на Hashcash, предложена схема за доказателство-за-работа за намаляване на спама в имейлите. Идеята е, че при индивидуални мащаби допълнителното натоварване е пренебрежимо, но при масов ниво на събиране на данни то се натрупва и прави събирането на данни много по-скъпо.",
"hack_purpose": "В крайна сметка, това е временно решение, за да се отдели повече време за идентифициране и разпознаване на безглави браузъри (например чрез това как те рендират шрифтовете), така че страницата за доказателство-за-работа да не се налага да се показва на потребители, които е по-вероятно да са легитимни.",
"simplified_explanation": "Това е мярка срещу ботове и злонамерени заявки, подобна на CAPTCHA. Вместо да трябва да правите нещо сами, браузърът ви получава задача за изчисление, която трябва да реши, за да се увери, че е валиден клиент. Тази концепция се нарича схема доказателство-за-работа. Задачата се изчислява за няколко секунди и ви се дава достъп до уебсайта. Благодаря ви за разбирането и търпението.",
"jshelter_note": "Моля, имайте предвид, че Anubis изисква използването на модерни функции на JavaScript, сред които и като JShelter ще деактивират. Моля, деактивирайте JShelter или други подобни добавки за този домейн.",
"version_info": "Този уебсайт използва версия на Anubis",
"try_again": "Опитайте отново",
"go_home": "Отидете на началната страница",
"contact_webmaster": "или ако смятате, че не трябва да бъдете блокирани, моля свържете се с уебмастъра на",
"connection_security": "Моля, изчакайте, докато се уверим в сигурността на връзката ви",
"javascript_required": "За съжаление, трябва да включите JavaScript, за да минете през това предизвикателство. Това е необходимо, защото компаниите за изкуствен интелект промениха социалния договор около начина на хостинг на уебсайтове. Решение без JavaScript е в процес на разработка.",
"benchmark_requires_js": "За да използвате инструмента за тестване, е необходимо да включите JavaScript.",
"difficulty": "Трудност:",
"algorithm": "Алгоритъм:",
"compare": "Сравни:",
"time": "Време",
"iters": "Итерации",
"time_a": "Време А",
"iters_a": "Итерации А",
"time_b": "Време Б",
"iters_b": "Итерации Б",
"static_check_endpoint": "Това е просто краен пункт за проверка, който да използва обратният ви прокси.",
"authorization_required": "Изисква се авторизация",
"cookies_disabled": "Браузърът ви е настроен да деактивира бисквитките. Anubis изисква бисквитки за законния интерес да се увери, че сте валиден клиент. Моля, включете бисквитките за този домейн",
"access_denied": "Достъпът е отказан: код на грешка",
"dronebl_entry": "DroneBL докладва запис",
"see_dronebl_lookup": "вижте",
"internal_server_error": "Вътрешна сървърна грешка: администраторът е грешно конфигурирал Anubis. Моля, свържете се с администратора и ги помолете да проверят логовете около",
"invalid_redirect": "Невалидно пренасочване",
"redirect_not_parseable": "URL адресът за пренасочване не може да бъде разпознат",
"redirect_domain_not_allowed": "Домейнът за пренасочване не е позволен",
"missing_required_forwarded_headers": "Липсват необходимите X-Forwarded-* заглавни части",
"failed_to_sign_jwt": "неуспешно подписване на JWT",
"invalid_invocation": "Невалидно извикване на MakeChallenge",
"client_error_browser": "Крешка в клиента: Моля, уверете се, че браузърът ви е актуализиран и опитайте отново по-късно.",
"oh_noes": "О, не!",
"benchmarking_anubis": "Тестване на Anubis!",
"you_are_not_a_bot": "Ти не си бот!",
"making_sure_not_bot": "Уверяваме се, че не си бот!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Браузърът ви няма функциониращ web.crypto елемент. Гледате ли това през сигурен контекст?",
"js_web_workers_error": "Браузърът ви не поддържа уеб работници (Anubis използва това, за да избегне замръзване на браузъра ви). Имате ли инсталирана добавка като JShelter?",
"js_cookies_error": "Браузърът ви не съхранява бисквитки. Anubis използва бисквитки, за да определи които клиенти са преминали задачите, като съхранява подписан токен в бисквитка. Моля, включете съхраняването на бисквитки за този домейн. Имената на бисквитките, съхранени от Anubis, могат да се променят без предварително уведомление. Имената и стойностите на бисквитките не са част от публичния API.",
"js_context_not_secure": "Вашият контекст не е сигурен!",
"js_context_not_secure_msg": "Опитайте да се свържете чрез HTTPS или уведомете администратора да kонфигурира HTTPS. За повече информация вижте MDN.",
"js_calculating": "Изчисляване...",
"js_missing_feature": "Липсваща функция",
"js_challenge_error": "Грешка при задачата!",
"js_challenge_error_msg": "Неуспешно разрешаване на алгоритъма за проверка. Може би искате да презаредите страницата.",
"js_calculating_difficulty": "Изчисляване... Трудност:",
"js_speed": "Скорост:",
"js_verification_longer": "Проверката отнема повече време от очакваното. Моля, не презареждайте страницата.",
"js_success": "Успех!",
"js_done_took": "Готово! Отне",
"js_iterations": "итерации",
"js_finished_reading": "Приключих с четенето, продължете →",
"js_calculation_error": "Грешка при изчислението!",
"js_calculation_error_msg": "Неуспешно изчисление на задачата:"
}

View File

@@ -1,38 +1,38 @@
{
"loading": "Ladevorgang...",
"loading": "Wird geladen …",
"why_am_i_seeing": "Warum sehe ich diese Seite?",
"protected_by": "Geschützt durch",
"protected_from": "Von",
"made_with": "Mit ❤️ entwickelt in 🇨🇦",
"mascot_design": "Maskottchen erstellt von",
"ai_companies_explanation": "Diese Seite wird angezeigt, da der Betreiber der Website Anubis eingerichtet hat, um sie vor aggressiven Webcrawlern von KI-Unternehmen zu schützen. Diese können Ausfälle verursachen, wodurch die Website für niemanden erreichbar ist.",
"anubis_compromise": "Anubis stellt einen Kompromiss dar. Es verwendet eine Proof-of-Work-Methode nach dem Hashcash-Prinzip, das ursprünglich zur Bekämpfung von E-Mail-Spam entwickelt wurde. Die Idee dahinter: Für einen einzelnen Besucher ist die Verzögerung vernachlässigbar, aber massenhaftes Scraping wird dadurch aufwändig und teuer.",
"hack_purpose": "Letztendlich ist dies eine Übergangslösung, um mehr Zeit für Browser-Fingerprinting und die Identifizierung von Headless-Browsern (z. B. anhand ihrer Schriftwiedergabe) zu gewinnen. So muss die Proof-of-Work-Seite nicht Nutzern angezeigt werden, die sehr wahrscheinlich legitim sind.",
"simplified_explanation": "Dies ist eine Maßnahme gegen Bots und bösartige Anfragen, ähnlich einem CAPTCHA. Anstatt jedoch selbst arbeiten zu müssen, erhält dein Browser eine Rechenaufgabe, um sicherzustellen, dass es sich um einen gültigen Client handelt. Dieses Konzept nennt sich <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Proof of Work</a>. Die Aufgabe wird in wenigen Sekunden berechnet und du erhältst Zugriff auf die Website. Danke für deine Geduld.",
"jshelter_note": "Anubis benötigt moderne JavaScript-Features, die von Plugins wie JShelter deaktiviert werden. Bitte deaktiviere JShelter oder ähnliche Plugins für diese Domain.",
"version_info": "Diese Website läuft mit Anubis-Version",
"mascot_design": "Maskottchen entworfen von",
"ai_companies_explanation": "Diese Seite wird angezeigt, weil der Betreiber dieser Website Anubis eingerichtet hat, um den Server vor aggressivem Scraping durch KI-Unternehmen zu schützen. Dieses Scraping kann Ausfälle verursachen, wodurch die Website für niemanden erreichbar ist.",
"anubis_compromise": "Anubis ist ein Kompromiss. Es verwendet ein Proof-of-Work-Verfahren nach dem Vorbild von Hashcash, das ursprünglich zur Reduzierung von E-Mail-Spam entwickelt wurde. Die Idee dahinter ist, dass die zusätzliche Last für einzelne Nutzer vernachlässigbar ist, sich aber auf der Ebene von Massen-Scrapern summiert und das Scraping deutlich teurer macht.",
"hack_purpose": "Letztlich ist dies eine Übergangslösung, damit mehr Zeit in das Fingerprinting und die Erkennung von Headless-Browsern investiert werden kann (z. B. anhand ihrer Schriftart-Darstellung), sodass die Proof-of-Work-Seite Nutzern, die mit hoher Wahrscheinlichkeit legitim sind, nicht mehr angezeigt werden muss.",
"simplified_explanation": "Dies ist eine Schutzmaßnahme gegen Bots und schädliche Anfragen, ähnlich einem CAPTCHA. Anstatt selbst eine Aufgabe lösen zu müssen, bekommt dein Browser eine Rechenaufgabe, die er lösen muss, um sicherzustellen, dass es sich um einen gültigen Client handelt. Dieses Konzept nennt sich <a href=\"https://de.wikipedia.org/wiki/Proof_of_Work\">Proof of Work</a>. Die Aufgabe wird innerhalb weniger Sekunden berechnet und du erhältst Zugang zur Website. Danke für dein Verständnis und deine Geduld.",
"jshelter_note": "Anubis benötigt moderne JavaScript-Funktionen, die von Plugins wie JShelter deaktiviert werden. Bitte deaktiviere JShelter oder ähnliche Plugins für diese Domain.",
"version_info": "Diese Website nutzt Anubis Version",
"try_again": "Erneut versuchen",
"go_home": "Zur Startseite",
"contact_webmaster": "Falls du glaubst, dass es sich um einen Fehler handelt, kontaktiere bitte den Administrator unter",
"connection_security": "Bitte warte einen Moment, während wir die Sicherheit deiner Verbindung prüfen.",
"javascript_required": "Du musst JavaScript aktivieren, um diese Prüfung durchführen zu können. Dies ist notwendig, da KI-Unternehmen die bisherigen Regeln für das Hosting von Websites nicht mehr respektieren. Eine Lösung ohne JavaScript ist in Entwicklung.",
"benchmark_requires_js": "Für die Nutzung des Benchmark-Tools muss JavaScript aktiviert sein.",
"contact_webmaster": "oder kontaktiere den Webmaster unter, falls du glaubst, dass du nicht blockiert werden solltest:",
"connection_security": "Bitte warte einen Moment, während wir die Sicherheit deiner Verbindung überprüfen.",
"javascript_required": "Du musst JavaScript aktivieren, um diese Prüfung zu bestehen. Dies ist notwendig, da KI-Unternehmen den Gesellschaftsvertrag rund um Webhosting verändert haben. Eine Lösung ohne JavaScript ist in Arbeit.",
"benchmark_requires_js": "Für das Benchmark-Tool muss JavaScript aktiviert sein.",
"difficulty": "Schwierigkeit:",
"algorithm": "Algorithmus:",
"compare": "Vergleich:",
"compare": "Vergleichen:",
"time": "Zeit",
"iters": "Iterationen",
"time_a": "Zeit A",
"iters_a": "Iterationen A",
"time_b": "Zeit B",
"iters_b": "Iterationen B",
"static_check_endpoint": "Dies ist ein Endpunkt zur Prüfung durch einen Reverse-Proxy.",
"static_check_endpoint": "Dies ist nur ein Prüf-Endpunkt für deinen Reverse-Proxy.",
"authorization_required": "Autorisierung erforderlich",
"cookies_disabled": "Cookies sind in deinem Browser deaktiviert. Anubis benötigt Cookies, um sicherzustellen, dass es sich um einen legitimen Zugriff handelt. Bitte aktiviere Cookies für diese Domain.",
"access_denied": "Zugriff verweigert Fehlercode",
"dronebl_entry": "Eintrag in DroneBL",
"cookies_disabled": "Cookies sind in deinem Browser deaktiviert. Anubis benötigt Cookies im berechtigten Interesse, sicherzustellen, dass es sich um einen gültigen Client handelt. Bitte aktiviere Cookies für diese Domain.",
"access_denied": "Zugriff verweigert: Fehlercode",
"dronebl_entry": "DroneBL hat einen Eintrag gemeldet",
"see_dronebl_lookup": "anzeigen",
"internal_server_error": "Interner Serverfehler: Der Administrator hat Anubis fehlerhaft konfiguriert. Bitte kontaktiere den Administrator und bitte ihn, die Logs zu prüfen.",
"internal_server_error": "Interner Serverfehler: Der Administrator hat Anubis fehlerhaft konfiguriert. Bitte kontaktiere den Administrator und bitte ihn, die Logs im Zeitraum um folgenden Zeitpunkt zu prüfen:",
"invalid_redirect": "Ungültige Weiterleitung",
"redirect_not_parseable": "Weiterleitungs-URL kann nicht verarbeitet werden",
"redirect_domain_not_allowed": "Weiterleitungs-Domain nicht erlaubt",
@@ -41,26 +41,26 @@
"invalid_invocation": "Ungültiger Aufruf von MakeChallenge",
"client_error_browser": "Client-Fehler: Bitte stelle sicher, dass dein Browser aktuell ist, und versuche es später erneut.",
"oh_noes": "Oh nein!",
"benchmarking_anubis": "Benchmark wird durchgeführt!",
"benchmarking_anubis": "Anubis-Benchmark wird durchgeführt!",
"you_are_not_a_bot": "Du bist kein Bot!",
"making_sure_not_bot": "Dein Browser wird geprüft!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Dein Browser verfügt nicht über ein funktionierendes web.crypto-Element. Wird eine sichere Verbindung verwendet?",
"js_web_workers_error": "Dein Browser unterstützt keine Web-Worker (Anubis verwendet diese, damit der Browser nicht einfriert). Ist ein Plugin wie JShelter installiert?",
"js_cookies_error": "Dein Browser speichert keine Cookies. Anubis verwendet Cookies, um nach bestandener Prüfung ein signiertes Token abzulegen. Bitte aktiviere Cookies für diese Domain. Die Cookie-Namen von Anubis können sich jederzeit ändern. Cookie-Namen und gespeicherte Werte sind nicht Teil der öffentlichen API.",
"js_web_crypto_error": "Dein Browser verfügt nicht über ein funktionierendes web.crypto-Element. Wird diese Seite in einem sicheren Kontext angezeigt?",
"js_web_workers_error": "Dein Browser unterstützt keine Web Workers (Anubis verwendet diese, damit dein Browser nicht einfriert). Hast du ein Plugin wie JShelter installiert?",
"js_cookies_error": "Dein Browser speichert keine Cookies. Anubis verwendet Cookies, um nach bestandener Prüfung ein signiertes Token abzulegen. Bitte aktiviere Cookies für diese Domain. Die Cookie-Namen von Anubis können sich jederzeit ohne Vorankündigung ändern. Cookie-Namen und -Werte sind nicht Teil der öffentlichen API.",
"js_context_not_secure": "Diese Verbindung ist nicht sicher!",
"js_context_not_secure_msg": "Bitte versuche, dich über HTTPS zu verbinden, oder weise den Administrator darauf hin, HTTPS einzurichten. Mehr Informationen: <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
"js_calculating": "Berechnung läuft...",
"js_context_not_secure_msg": "Versuche, dich über HTTPS zu verbinden, oder informiere den Administrator, HTTPS einzurichten. Weitere Informationen unter <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
"js_calculating": "Berechnung läuft",
"js_missing_feature": "Fehlendes Feature",
"js_challenge_error": "Prüfung fehlgeschlagen!",
"js_challenge_error_msg": "Der Prüf-Algorithmus konnte nicht geladen werden. Bitte lade die Seite neu.",
"js_calculating_difficulty": "Berechnung läuft...<br/>Schwierigkeit:",
"js_challenge_error_msg": "Der Prüfalgorithmus konnte nicht aufgelöst werden. Bitte lade die Seite neu.",
"js_calculating_difficulty": "Berechnung läuft<br/>Schwierigkeit:",
"js_speed": "Geschwindigkeit:",
"js_verification_longer": "Die Prüfung dauert länger als erwartet. Bitte warte und lade die Seite nicht neu.",
"js_success": "Erfolgreich!",
"js_verification_longer": "Die Verifizierung dauert länger als erwartet. Bitte bleibe auf der Seite und lade sie nicht neu.",
"js_success": "Geschafft!",
"js_done_took": "Fertig! Dauer:",
"js_iterations": "Iterationen",
"js_finished_reading": "Fertig gelesen weiter zur Seite →",
"js_finished_reading": "Fertig gelesen, weiter zur Seite →",
"js_calculation_error": "Berechnungsfehler!",
"js_calculation_error_msg": "Fehler bei der Berechnung der Prüfung:"
}

View File

@@ -23,6 +23,7 @@
"vi",
"zh-CN",
"zh-TW",
"sv"
"sv",
"bg"
]
}
}

View File

@@ -1,20 +1,20 @@
{
"loading": "Đang nạp...",
"why_am_i_seeing": "Tại sao tôi đang thấy trang này?",
"loading": "Đang tải...",
"why_am_i_seeing": "Tại sao tôi thấy trang này?",
"protected_by": "Bảo vệ bởi",
"protected_from": "từ",
"made_with": "Tạo ra bằng ❤️ tại 🇨🇦",
"mascot_design": "Thiết kế mascot bởi",
"ai_companies_explanation": "Bạn đang thấy trang này do quản trị viên của trang web này đã thiết lập Anubis để bảo vệ máy chủ của họ khỏi quấy rầy từ những công ty AI hung hãn cóp nhặt nội dung khắp Internet. Điều này có thể và đã dẫn tới tình trạng gián đoạn hoạt động trên nhiều trang web, khiến tài nguyên tại đó nằm ngoài tầm với của mọi người.",
"made_with": "Lập trình bằng ❤️ 🇨🇦",
"mascot_design": "Mascot thiết kế bởi",
"ai_companies_explanation": "Bạn thấy trang này do quản trị viên của trang web này đã thiết lập Anubis để bảo vệ máy chủ của họ khỏi quấy rầy từ những công ty AI hung hãn cóp nhặt nội dung khắp Internet. Điều này dẫn tới tình trạng gián đoạn hoạt động trên nhiều trang web, khiến tài nguyên đó nằm ngoài tầm với của mọi người.",
"anubis_compromise": "Anubis là giải pháp thỏa hiệp. Anubis sử dụng cơ chế Proof-of-Work dựa trên Hashcash, được thiết kế ban đầu để giảm bớt email spam. Ý tưởng đằng sau đó là với người dùng cá nhân phần nạp thêm sẽ không đáng kể, nhưng ở tầm mức quy mô lớn sẽ cộng dồn và dẫn tới chi phí tiêu hao hơn rất nhiều.",
"hack_purpose": "Chốt lại, đây cũng chỉ là giải pháp \"tạm ổn\" với mục đích thực sự là để giành thêm thời gian nhận diện và fingerprint những trình duyệt headless (VD: cách dựng font ra sao), sao cho hạn chế tối đa các yêu cầu tính toán trang thử thách Proof-of-Work tới nhóm người dùng có khả năng cao là con người hơn.",
"hack_purpose": "Chốt lại, đây cũng chỉ là giải pháp \"tạm ổn\" với mục đích thực sự là để giành thêm thời gian nhận diện và truy vết những trình duyệt headless (VD: cách dựng font ra sao), sao cho hạn chế tối đa các yêu cầu tính toán trang thử thách Proof-of-Work tới nhóm người dùng có khả năng cao là con người hơn.",
"simplified_explanation": "Đây là một biện pháp chống lại bot và các yêu cầu độc hại tương tự như CAPTCHA. Tuy nhiên, thay vì bạn phải tự mình thực hiện, trình duyệt của bạn sẽ được giao một nhiệm vụ tính toán mà nó phải giải quyết để đảm bảo rằng nó là một máy khách hợp lệ. Khái niệm này được gọi là <a href=\"https://en.wikipedia.org/wiki/Proof_of_work\">Bằng chứng Công việc</a>. Nhiệm vụ được tính toán trong vài giây và bạn được cấp quyền truy cập vào trang web. Cảm ơn sự thông cảm và kiên nhẫn của bạn.",
"jshelter_note": "Vui lòng lưu ý Anubis cần sử dụng những tính năng JavaScript hiện đại mà một số phần mở rộng như JShelter sẽ tắt. Vui lòng vô hiệu hóa JShelter hoặc những phần mở rộng tương tự cho tên miền này.",
"version_info": "Trang web này đang chạy Anubis phiên bản",
"version_info": "Trang web này ng Anubis bản",
"try_again": "Thử lại",
"go_home": "Về trang chủ",
"contact_webmaster": "hoặc nếu bạn tin rằng mình không nên bị chặn, vui lòng liên hệ chủ trang web tại",
"connection_security": "Vui lòng chờ một chút trong khi chúng tôi kiểm tra an ninh kết nối của bạn.",
"connection_security": "Vui lòng chờ một chút trong lúc chúng tôi kiểm tra kết nối của bạn.",
"javascript_required": "Rất tiếc, bạn phải bật JavaScript để vượt qua thử thách này. Điều này bắt buộc do những công ty AI đã thay đổi luật ngầm quanh việc hoạt động máy chủ web ra sao. Giải pháp không có JavaScript đang được phát triển.",
"benchmark_requires_js": "Bắt buộc phải bật JavaScript để chạy công cụ benchmark.",
"difficulty": "Độ khó:",
@@ -28,14 +28,14 @@
"iters_b": "Lặp lại kiểu B",
"static_check_endpoint": "Đây là điểm cuối cho reverse proxy của bạn sử dụng.",
"authorization_required": "Bắt buộc xác thực",
"cookies_disabled": "Trình duyệt của bạn được thiết lập để vô hiệu hóa cookie. Anubis cần cookie cho mục đích chính đáng để kiểm tra chắc chắn bạn là người dùng hợp lệ. Vui lòng bật cookie cho tên miền này",
"cookies_disabled": "Trình duyệt của bạn đã vô hiệu hóa cookie. Anubis cần cookie cho mục đích chính đáng để kiểm tra chắc chắn bạn là người dùng hợp lệ. Vui lòng bật cookie cho tên miền này",
"access_denied": "Truy cập bị từ chối: mã lỗi",
"dronebl_entry": "DroneBL báo cáo truy cập",
"see_dronebl_lookup": "xem",
"internal_server_error": "Lỗi máy chủ nội bộ: quản trị viên đã thiết lập sai Anubis. Vui lòng liên hệ quản trị viên và yêu cầu họ kiểm tra log",
"internal_server_error": "Lỗi nội bộ máy chủ: quản trị viên đã thiết lập sai Anubis. Vui lòng liên hệ quản trị viên và yêu cầu họ kiểm tra log",
"invalid_redirect": "Điều hướng không hợp lệ",
"redirect_not_parseable": "Liên kết điều hướng không thể xử lý",
"redirect_domain_not_allowed": "Tên miền điều hướng không được phép",
"redirect_not_parseable": "Không thể xử lý liên kết điều hướng",
"redirect_domain_not_allowed": "Không được phép điều hướng tên miền",
"missing_required_forwarded_headers": "Thiếu các tiêu đề X-Forwarded-* bắt buộc",
"failed_to_sign_jwt": "không thể ký JWT",
"invalid_invocation": "Gọi hàm MakeChallenge không hợp lệ",
@@ -43,7 +43,7 @@
"oh_noes": "Ôi không!",
"benchmarking_anubis": "Đang benchmark Anubis!",
"you_are_not_a_bot": "Bạn không phải là bot!",
"making_sure_not_bot": ang kiểm tra bạn không phải là bot!",
"making_sure_not_bot": ảm bảo bạn không phải là bot!",
"celphase": "CELPHASE",
"js_web_crypto_error": "Trình duyệt của bạn không có web.crypto hoạt động. Liệu bạn có đang xem trang này với kết nối bảo mật không?",
"js_web_workers_error": "Trình duyệt của bạn không hỗ trợ tính năng web worker (Anubis sử dụng để trình duyệt của bạn bị đơ). Bạn có cài đặt và sử dụng phần mở rộng như JShelter hay không?",
@@ -53,12 +53,12 @@
"js_calculating": "Đang tính toán...",
"js_missing_feature": "Thiếu tính năng",
"js_challenge_error": "Lỗi thử thách!",
"js_challenge_error_msg": "Không thể xử lý thuật toán kiểm tra. Bạn nên nạp lại trang này.",
"js_calculating_difficulty": "Đang tính...<br/>Độ khó:",
"js_challenge_error_msg": "Không thể xử lý thuật toán kiểm tra. Bạn nên tải lại trang này.",
"js_calculating_difficulty": "Đang tính toán...<br/>Độ khó:",
"js_speed": "Tốc độ:",
"js_verification_longer": "Quá trình kiểm tra đang kéo dài lâu hơn dự kiến. Vui lòng không nạp lại trang này.",
"js_verification_longer": "Quá trình kiểm tra i lâu hơn dự kiến. Vui lòng không tải lại trang này.",
"js_success": "Thành công!",
"js_done_took": "Hoàn tất! Mất",
"js_done_took": "Xong rồi! Vào",
"js_iterations": "lần lặp lại",
"js_finished_reading": "Tôi đã đọc xong, tiếp tục →",
"js_calculation_error": "Lỗi tính toán!",

View File

@@ -14,7 +14,7 @@ func TestLocalizationService(t *testing.T) {
service := NewLocalizationService()
loadingStrMap := map[string]string{
"de": "Ladevorgang...",
"de": "Wird geladen …",
"en": "Loading...",
"es": "Cargando...",
"et": "Laadin...",
@@ -30,10 +30,11 @@ func TestLocalizationService(t *testing.T) {
"tr": "Yükleniyor...",
"ru": "Загрузка...",
"uk": "Завантаження...",
"vi": "Đang nạp...",
"vi": "Đang tải...",
"zh-CN": "加载中...",
"zh-TW": "載入中...",
"sv": "Laddar...",
"bg": "Зареждане...",
}
var keys []string

View File

@@ -0,0 +1,44 @@
package policy
import (
"net/http"
"testing"
"github.com/TecharoHQ/anubis/internal/dns"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/store/memory"
)
func newTestDNS(t *testing.T) *dns.Dns {
t.Helper()
ctx := t.Context()
memStore := memory.New(ctx)
cache := dns.NewDNSCache(300, 300, memStore)
return dns.New(ctx, cache)
}
func TestCELChecker_MapIterationWrappers(t *testing.T) {
cfg := &config.ExpressionOrList{
Expression: `headers.exists(k, k == "Accept") && query.exists(k, k == "format")`,
}
checker, err := NewCELChecker(cfg, newTestDNS(t))
if err != nil {
t.Fatalf("creating CEL checker failed: %v", err)
}
req, err := http.NewRequest(http.MethodGet, "https://example.com/?format=json", nil)
if err != nil {
t.Fatalf("making request failed: %v", err)
}
req.Header.Set("Accept", "application/json")
got, err := checker.Check(req)
if err != nil {
t.Fatalf("checking expression failed: %v", err)
}
if !got {
t.Fatal("expected expression to evaluate true")
}
}

View File

@@ -66,7 +66,9 @@ func (h HTTPHeaders) Get(key ref.Val) ref.Val {
return result
}
func (h HTTPHeaders) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (h HTTPHeaders) Iterator() traits.Iterator {
return newMapIterator(h.Header)
}
func (h HTTPHeaders) IsZeroValue() bool {
return len(h.Header) == 0

View File

@@ -0,0 +1,60 @@
package expressions
import (
"errors"
"maps"
"reflect"
"slices"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
type stringSliceIterator struct {
keys []string
idx int
}
func (s *stringSliceIterator) Value() any {
return s
}
func (s *stringSliceIterator) ConvertToNative(typeDesc reflect.Type) (any, error) {
return nil, ErrNotImplemented
}
func (s *stringSliceIterator) ConvertToType(typeValue ref.Type) ref.Val {
return types.NewErr("can't convert from %q to %q", types.IteratorType, typeValue)
}
func (s *stringSliceIterator) Equal(other ref.Val) ref.Val {
return types.NewErr("can't compare %q to %q", types.IteratorType, other.Type())
}
func (s *stringSliceIterator) Type() ref.Type {
return types.IteratorType
}
func (s *stringSliceIterator) HasNext() ref.Val {
return types.Bool(s.idx < len(s.keys))
}
func (s *stringSliceIterator) Next() ref.Val {
if s.HasNext() != types.True {
return nil
}
val := s.keys[s.idx]
s.idx++
return types.String(val)
}
func newMapIterator(m map[string][]string) traits.Iterator {
return &stringSliceIterator{
keys: slices.Collect(maps.Keys(m)),
idx: 0,
}
}

View File

@@ -1,7 +1,6 @@
package expressions
import (
"errors"
"net/url"
"reflect"
"strings"
@@ -11,8 +10,6 @@ import (
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
// URLValues is a type wrapper to expose url.Values into CEL programs.
type URLValues struct {
url.Values
@@ -69,7 +66,9 @@ func (u URLValues) Get(key ref.Val) ref.Val {
return result
}
func (u URLValues) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (u URLValues) Iterator() traits.Iterator {
return newMapIterator(u.Values)
}
func (u URLValues) IsZeroValue() bool {
return len(u.Values) == 0

View File

@@ -75,7 +75,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
switch c.Logging.Sink {
case config.LogSinkStdio:
result.Logger = internal.InitSlog(logLevel, os.Stderr)
result.Logger = internal.InitSlog(logLevel, os.Stderr, c.Logging.HideSource)
case config.LogSinkFile:
out := &logrotate.Logger{
Filename: c.Logging.Parameters.Filename,
@@ -87,7 +87,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic
Compress: c.Logging.Parameters.Compress,
}
result.Logger = internal.InitSlog(logLevel, out)
result.Logger = internal.InitSlog(logLevel, out, c.Logging.HideSource)
}
lg := result.Logger.With("at", "config-validate")