mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-09 18:18:49 +00:00
Compare commits
8 Commits
Xe/web-eve
...
Xe/russian
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
effcf3bb7e | ||
|
|
5aa38af128 | ||
|
|
8c1884ac46 | ||
|
|
1dc9525427 | ||
|
|
24e3746b0b | ||
|
|
31184ccd5f | ||
|
|
e69fadddf1 | ||
|
|
4aea61499d |
@@ -21,11 +21,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
Anubis now supports these new languages:
|
||||
|
||||
- [Czech](https://github.com/TecharoHQ/anubis/pull/849)
|
||||
- [Finnish](https://github.com/TecharoHQ/anubis/pull/863)
|
||||
- [Russian](https://github.com/TecharoHQ/anubis/pull/882)
|
||||
|
||||
Anubis now supports the [`missingHeader`](./admin/configuration/expressions.mdx#missingHeader) to assert the absence of headers in requests.
|
||||
|
||||
### Fixes
|
||||
|
||||
#### Fix ["error: can't get challenge"](https://github.com/TecharoHQ/anubis/issues/869) when details about a challenge can't be found in the server side state
|
||||
|
||||
v1.21.0 changed the core challenge flow to maintain information about challenges on the server side instead of only doing them via stateless idempotent generation functions and relying on details to not change. There was a subtle bug introduced in this change: if a client has an unknown challenge ID set in its test cookie, Anubis will clear that cookie and then throw an HTTP 500 error.
|
||||
|
||||
This has been fixed by making Anubis throw a new challenge page instead.
|
||||
|
||||
#### Fix event loop thrashing when solving a proof of work challenge
|
||||
|
||||
Previously the "fast" proof of work solver had a fragment of JavaScript that attempted to only post an update about proof of work progress to the main browser window every 1024 iterations. This fragment of JavaScript was subtly incorrect in a way that passed review but actually made the workers send an update back to the main thread every iteration. This caused a pileup of unhandled async calls (similar to a socket accept() backlog pileup in Unix) that caused stack space exhaustion.
|
||||
|
||||
@@ -102,6 +102,10 @@ func (s *Server) challengeFor(r *http.Request) (*challenge.Challenge, error) {
|
||||
ckie := ckies[0]
|
||||
chall, err := j.Get(r.Context(), "challenge:"+ckie.Value)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return s.issueChallenge(r.Context(), r)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package lib
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
@@ -736,3 +737,67 @@ func TestStripBasePrefixFromRequest(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestChallengeFor_ErrNotFound makes sure that users with invalid challenge IDs
|
||||
// in the test cookie don't get rejected by the database lookup failing.
|
||||
func TestChallengeFor_ErrNotFound(t *testing.T) {
|
||||
pol := loadPolicies(t, "testdata/aggressive_403.yaml", 0)
|
||||
ckieExpiration := 10 * time.Minute
|
||||
const wrongCookie = "wrong cookie"
|
||||
|
||||
srv := spawnAnubis(t, Options{
|
||||
Next: http.NewServeMux(),
|
||||
Policy: pol,
|
||||
|
||||
CookieDomain: "127.0.0.1",
|
||||
CookieExpiration: ckieExpiration,
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "http://example.com/", nil)
|
||||
req.Header.Set("X-Real-IP", "127.0.0.1")
|
||||
req.Header.Set("User-Agent", "CHALLENGE")
|
||||
req.AddCookie(&http.Cookie{Name: anubis.TestCookieName, Value: wrongCookie})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
srv.maybeReverseProxyOrPage(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
body := new(strings.Builder)
|
||||
_, err := io.Copy(body, resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("reading body should not fail: %v", err)
|
||||
}
|
||||
|
||||
t.Run("make sure challenge page is issued", func(t *testing.T) {
|
||||
if !strings.Contains(body.String(), "anubis_challenge") {
|
||||
t.Error("should get a challenge page")
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusUnauthorized {
|
||||
t.Errorf("should get a 401 Unauthorized, got: %d", resp.StatusCode)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("make sure that the body is not an error page", func(t *testing.T) {
|
||||
if strings.Contains(body.String(), "reject.webp") {
|
||||
t.Error("should not get an internal server error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("make sure new test cookie is issued", func(t *testing.T) {
|
||||
found := false
|
||||
for _, cookie := range resp.Cookies() {
|
||||
if cookie.Name == anubis.TestCookieName {
|
||||
if cookie.Value == wrongCookie {
|
||||
t.Error("a new challenge cookie should be issued")
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("a new test cookie should be set")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
64
lib/localization/locales/fi.json
Normal file
64
lib/localization/locales/fi.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"loading": "Ladataan...",
|
||||
"why_am_i_seeing": "Miksi näen tämän?",
|
||||
"protected_by": "Suojan tarjoaa",
|
||||
"protected_from": "tekijänä",
|
||||
"made_with": "❤️ tehty 🇨🇦:ssa",
|
||||
"mascot_design": "Maskotin suunnitellut",
|
||||
"ai_companies_explanation": "Sivustolla on käytössä Anubis. Anubis estää robotteja lataamasta sivustoa ylettömästi. Tämä voi aiheuttaa palvelimen ylikuormituksen, joka estää ketään pääsemästä sivustolle.",
|
||||
"anubis_compromise": "Anubis on kompromissi. Anubis käyttää roskapostin vähentämiseen ehdotettua, Hashcash-järjestelmän mukaista työnnäytettä. Yksittäiselle käyttäjälle kuormitus on mitätön, mutta kasvattaa sivuston ylettömän lataamisen kuluja huomattavasti.",
|
||||
"hack_purpose": "Tämä on \"riittävän hyvä\" väliaikainen ratkaisu, joka antaa aikaa tunnistaa robotit, ettei työnnäyte sivua tarvitsisi näyttää todellisille käyttäjille.",
|
||||
"jshelter_note": "Anubis tarvitsee toimiakseen JavaScript-ominaisuuksia, jotka liitännäiset kuten jShelter estää. Otathan tällaiset liitännäiset pois käytöstä tälle verkkotunnukselle.",
|
||||
"version_info": "Sivusto käyttää Anubis versiota",
|
||||
"try_again": "Yritä uudelleen",
|
||||
"go_home": "Poistu",
|
||||
"contact_webmaster": "tai jos uskot ettei sinua tulisi estää, ota yhteyttä ylläpitäjään",
|
||||
"connection_security": "Odota hetki. Varmistamme yhteytesi tietoturvan.",
|
||||
"javascript_required": "Valitettavasti JavaScript on oltava käytössä tämän haasteen suorittamiseksi. Vaihtoehtoinen ratkaisu on työn alla.",
|
||||
"benchmark_requires_js": "JavaScript on oltava käytössä suorituskykytestin ajamiseksi.",
|
||||
"difficulty": "Vaikeus:",
|
||||
"algorithm": "Kaava:",
|
||||
"compare": "Vertailu:",
|
||||
"time": "Aika",
|
||||
"iters": "Toisto",
|
||||
"time_a": "Aika A",
|
||||
"iters_a": "Toisto A",
|
||||
"time_b": "Aika B",
|
||||
"iters_b": "Toisto B",
|
||||
"static_check_endpoint": "Tämä päätepiste on käyttämääsi käänteistä välityspalvelinta varten.",
|
||||
"authorization_required": "Valtuutus vaadittu",
|
||||
"cookies_disabled": "Selaimesi estää evästeet. Anubis tarvitsee evästeitä varmistaakseen, että olet todellinen käyttäjä. Otathan evästeet käyttöön tälle verkkotunnukselle",
|
||||
"access_denied": "Pääsy estetty: virhekoodi",
|
||||
"dronebl_entry": "DroneBL ilmoitti merkinnän",
|
||||
"see_dronebl_lookup": "katso",
|
||||
"internal_server_error": "Palvelinvirhe: Anubis on väärin määritetty. Pyydä ylläpitäjää tarkistamaan lokit",
|
||||
"invalid_redirect": "Virheellinen pyyntö",
|
||||
"redirect_not_parseable": "Uudellenohjauksen URL ei voitu jäsentää",
|
||||
"redirect_domain_not_allowed": "Uudelleenohjauksen verkkotunnus ei ole sallittu",
|
||||
"failed_to_sign_jwt": "JWT ei voitu allekirjoittaa",
|
||||
"invalid_invocation": "Virheellinen MakeChallenge-kaava",
|
||||
"client_error_browser": "Käyttäjävirhe: Varmista ettei selaimesi ole vanhentunut ja yritä uudelleen.",
|
||||
"oh_noes": "Voi ei!",
|
||||
"benchmarking_anubis": "Testataan Anubis!",
|
||||
"you_are_not_a_bot": "Et ole robotti!",
|
||||
"making_sure_not_bot": "Varmistetaan ettet ole robotti!",
|
||||
"celphase": "CELPHASE",
|
||||
"js_web_crypto_error": "Selaimesi web.crypto elementti ei toimi. Onko yhteytesi suojattu?",
|
||||
"js_web_workers_error": "Selaimesi ei tue Web Workers ominaisuutta. Anubis käyttää tätä estääkseen selaimesi lukkiutumisen. Onko sinulla liitännäinen, kuten jShelter käytössä?",
|
||||
"js_cookies_error": "Selaimesi ei tallenna evästeitä. Anubis tallentaa allekirjoitetun merkinnän evästeeseen, tunnistaakseen haasteen läpäisseet käyttäjät. Sallithan evästeiden tallentamisen tälle verkkotunnukselle. Tallennettujen evästeiden nimet voivat vaihdella. Evästeiden nimet ja arvot eivät ole osa julkista rajapintaa.",
|
||||
"js_context_not_secure": "Yhteytesi ei ole suojattu!",
|
||||
"js_context_not_secure_msg": "Yhdistä käyttäen HTTPS tai pyydä ylläpitäjää määrittämään HTTPS. Saadaksesi lisätietoja, katso <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||
"js_calculating": "Lasketaan...",
|
||||
"js_missing_feature": "Puuttuva ominaisuus",
|
||||
"js_challenge_error": "Haastevirhe!",
|
||||
"js_challenge_error_msg": "Tarkistuskaavaa ei voitu ratkaista. Voit yrittää ladata sivua uudelleen.",
|
||||
"js_calculating_difficulty": "Lasketaan...<br/>Vaikeus:",
|
||||
"js_speed": "Nopeus:",
|
||||
"js_verification_longer": "Vahvistus kestää odotettua pitempään. Ethän lataa sivua uudelleen.",
|
||||
"js_success": "Onnistui!",
|
||||
"js_done_took": "Valmis! Kesti",
|
||||
"js_iterations": "toistot",
|
||||
"js_finished_reading": "Luettu, jatka →",
|
||||
"js_calculation_error": "Laskentavirhe!",
|
||||
"js_calculation_error_msg": "Haasteen laskenta ei onnistunut:"
|
||||
}
|
||||
@@ -5,12 +5,14 @@
|
||||
"en",
|
||||
"es",
|
||||
"et",
|
||||
"fi",
|
||||
"fil",
|
||||
"fr",
|
||||
"is",
|
||||
"it",
|
||||
"ja",
|
||||
"pt-BR",
|
||||
"ru",
|
||||
"tr",
|
||||
"zh-CN",
|
||||
"zh-TW"
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
"loading": "Carregando...",
|
||||
"why_am_i_seeing": "Por que estou vendo isso?",
|
||||
"protected_by": "Protegido por",
|
||||
"protected_from": "From",
|
||||
"made_with": "Feito com ❤️ no 🇨🇦",
|
||||
"protected_from": "de",
|
||||
"made_with": "Feito com ❤️ no Canadá",
|
||||
"mascot_design": "Design do mascote por",
|
||||
"ai_companies_explanation": "Você está vendo isso porque o administrador deste site configurou Anubis para proteger o servidor contra a praga de empresas de IA que realizam scraping agressivo em sites. Isso pode causar, e de fato causa, inoperância nos sites, o que torna seus recursos inacessíveis para todos.",
|
||||
"anubis_compromise": "O Anubis é um meio-termo. Ele utiliza um esquema de Prova de Trabalho (Proof-of-Work) semelhante ao Hashcash, um esquema de Prova de Trabalho proposto para reduzir spam de e-mail. A ideia é que, em escalas individuais, a carga adicional seja insignificante, mas em níveis em massa de scrapers, ela se acumula e torna o scraping muito mais custoso.",
|
||||
"hack_purpose": "Em última análise, este é um hack cujo propósito real é fornecer uma solução \"boa o suficiente\" para que mais tempo possa ser gasto na identificação de navegadores sem interface (por exemplo: por meio de como eles fazem a renderização de fontes), para que a página do desafio da prova de trabalho não precise ser apresentada a usuários que têm muito mais probabilidade de serem legítimos.",
|
||||
"jshelter_note": "Observe que o Anubis requer o uso de recursos JavaScript modernos que plugins como o JShelter desabilitarão. Desabilite o JShelter ou outros plugins semelhantes para este domínio.",
|
||||
"ai_companies_explanation": "Você está vendo isso porque o administrador deste site configurou Anubis para proteger o servidor contra a praga de empresas de IA que realizam captura agressiva dos dados de páginas da Web. Isso pode causar, e de fato causa, indisponibilidade nos sites, o que os torna inacessíveis para todos.",
|
||||
"anubis_compromise": "O Anubis é um meio-termo. Ele utiliza um mecanismo de prova de validação semelhante ao Hashcash, proposto para reduzir spam de e-mail. A ideia é que, para acessos individuais, a carga adicional seja insignificante, mas acessos para captura em massa, ela se acumula e torna esse processo muito mais oneroso.",
|
||||
"hack_purpose": "Por fim, essa é uma solução \"boa o suficiente\" cujo propósito real é gastar mais tempo na identificação de navegadores sem interface (por exemplo: como eles renderizam fontes), para que a página de validação não precise ser apresentada a usuários que têm muito mais probabilidade de serem legítimos.",
|
||||
"jshelter_note": "Lembrando que o Anubis requer o uso de recursos JavaScript modernos, que plugins como o JShelter desabilitarão. Desabilite o JShelter ou similares para este domínio.",
|
||||
"version_info": "Este site está usando o Anubis versão",
|
||||
"try_again": "Tente novamente",
|
||||
"go_home": "Início",
|
||||
"contact_webmaster": "ou se você acredita que não deveria estar bloqueado, contate o webmaster em",
|
||||
"contact_webmaster": "ou se você acredita que não deveria estar bloqueado, contate o administrador em",
|
||||
"connection_security": "Por favor, aguarde um momento enquanto nós garantimos a segurança de sua conexão.",
|
||||
"javascript_required": "Infelizmente, você deve habilitar JavaScript para passar por este desafio. Isso é necessário porque empresas de IA alteraram o contrato social sobre como a hospedagem de sites funciona. Uma solução que não use JavaScript ainda está sendo desenvolvida.",
|
||||
"javascript_required": "Infelizmente, você deve habilitar JavaScript para passar por esta validação. Isso é necessário porque empresas de IA alteraram o contrato social sobre como a hospedagem de sites funciona. Uma solução não dependente de JavaScript ainda está sendo desenvolvida.",
|
||||
"benchmark_requires_js": "Para executar a ferramenta de benchmark, é necessário que o JavaScript esteja habilitado.",
|
||||
"difficulty": "Dificuldade:",
|
||||
"algorithm": "Algoritmo:",
|
||||
@@ -27,7 +27,7 @@
|
||||
"iters_b": "Iteração B",
|
||||
"static_check_endpoint": "Este é apenas um ponto de verificação para seu proxy reverso usar.",
|
||||
"authorization_required": "Autorização necessária",
|
||||
"cookies_disabled": "Seu navegador está configurado para desabilitar cookies. O Anubis requer cookies para o interesse legítimo de garantir que você seja um cliente válido. Habilite os cookies para este domínio.",
|
||||
"cookies_disabled": "Seu navegador está configurado para desabilitar cookies. O Anubis requer cookies somente com o interesse de garantir que você seja um cliente válido. Por favor, habilite os cookies para este domínio.",
|
||||
"access_denied": "Acesso negado: código de erro",
|
||||
"dronebl_entry": "DroneBL relatou uma entrada",
|
||||
"see_dronebl_lookup": "consulte",
|
||||
@@ -36,21 +36,21 @@
|
||||
"redirect_not_parseable": "URL de redirecionamento não analisável",
|
||||
"redirect_domain_not_allowed": "Domínio de redirecionamento não permitido",
|
||||
"failed_to_sign_jwt": "falha ao assinar JWT",
|
||||
"invalid_invocation": "Invocação inválida de MakeChallenge",
|
||||
"client_error_browser": "Erro do cliente: verifique se seu navegador está atualizado e tente novamente mais tarde..",
|
||||
"invalid_invocation": "Invocação de MakeChallenge inválida",
|
||||
"client_error_browser": "Erro do cliente: verifique se seu navegador está atualizado e tente novamente mais tarde.",
|
||||
"oh_noes": "Ah, não!",
|
||||
"benchmarking_anubis": "Fazendo benchmark do Anubis!",
|
||||
"you_are_not_a_bot": "Você não é um bot!",
|
||||
"making_sure_not_bot": "Certificando de que você não é um bot!",
|
||||
"celphase": "CELPHASE",
|
||||
"js_web_crypto_error": "Seu navegador não possui um elemento web.crypto funcional. Você está visualizando isso em um contexto seguro?",
|
||||
"js_web_workers_error": "Seu navegador não oferece suporte a web workers (o Anubis usa isso para evitar que seu navegador trave). Você tem um plugin como o JShelter instalado?",
|
||||
"js_cookies_error": "Seu navegador não armazena cookies. O Anubis usa cookies para determinar quais clientes passaram nos desafios, armazenando um token assinado em um cookie. Habilite o armazenamento de cookies para este domínio. Os nomes dos cookies armazenados pelo Anubis podem variar sem aviso prévio. Os nomes e valores dos cookies não fazem parte da API pública.",
|
||||
"js_web_workers_error": "Seu navegador não suporta web workers (o Anubis os usa para evitar que seu navegador trave). Você tem um plugin como o JShelter instalado?",
|
||||
"js_cookies_error": "Seu navegador não armazena cookies. O Anubis usa cookies para determinar quais clientes passaram pelas validações, armazenando um token assinado nesse cookie. Habilite o armazenamento de cookies para este domínio. Os nomes dos cookies armazenados pelo Anubis podem variar sem aviso prévio. Os nomes e valores dos cookies não fazem parte da API pública.",
|
||||
"js_context_not_secure": "Seu contexto não é seguro!",
|
||||
"js_context_not_secure_msg": "Tente conectar-se via HTTPS ou avise o administrador para configurar o HTTPS. Para mais informações, consulte o <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||
"js_context_not_secure_msg": "Tente conectar-se via HTTPS ou avise o administrador para configurar a segurança de site via HTTPS. Para mais informações, consulte o <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||
"js_calculating": "Calculando...",
|
||||
"js_missing_feature": "Faltando recurso",
|
||||
"js_challenge_error": "Erro no desafio!",
|
||||
"js_missing_feature": "Recurso não disponível",
|
||||
"js_challenge_error": "Erro na validação!",
|
||||
"js_challenge_error_msg": "Falha ao resolver o algoritmo de verificação. Talvez seja necessário recarregar a página.",
|
||||
"js_calculating_difficulty": "Calculando...<br/>Dificuldade:",
|
||||
"js_speed": "Velocidade:",
|
||||
@@ -60,5 +60,5 @@
|
||||
"js_iterations": "iterações",
|
||||
"js_finished_reading": "Terminei de ler, continue →",
|
||||
"js_calculation_error": "Erro de cálculo!",
|
||||
"js_calculation_error_msg": "Falha ao calcular o desafio:"
|
||||
"js_calculation_error_msg": "Falha ao calcular a validação:"
|
||||
}
|
||||
|
||||
64
lib/localization/locales/ru.json
Normal file
64
lib/localization/locales/ru.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"loading": "Загрузка...",
|
||||
"why_am_i_seeing": "Почему я вижу это?",
|
||||
"protected_by": "Защищено",
|
||||
"protected_from": "От",
|
||||
"made_with": "Сделано с ❤️ из 🇨🇦",
|
||||
"mascot_design": "Дизайн маскота от",
|
||||
"ai_companies_explanation": "Вы это видите, потому что администратор этого сайта настроил Anubis для защиты сервера от атак, использующих ИИ, которые агрессивно копируют данные с сайтов. Это может привести к зависанию сайтов и делает их ресурсы недоступными для всех.",
|
||||
"anubis_compromise": "Anubis - это компромисс. Anubis использует Proof-of-Work, похожую на Hashcash, для борьбы со спамом в электронной почте. Идея в том, что на отдельных уровнях дополнительная нагрузка не влиятельна, но на уровне массового парсинга она накапливается и значительно удорожает сбор данных.",
|
||||
"hack_purpose": "В реальности, это хак, у которого настоящая цель - предоставить «достаточно хорошее» решение, чтобы можно было потратить больше времени на идентификацию headless-браузеров (например, по тому, как они выполняют отрисовку шрифтов), чтобы не отображать страницу с подтверждением пользователям, которые с гораздо большей вероятностью являются настоящими.",
|
||||
"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": "Время A",
|
||||
"iters_a": "Итерации A",
|
||||
"time_b": "Время B",
|
||||
"iters_b": "Итерации B",
|
||||
"static_check_endpoint": "Это всего лишь точка проверки, которую может использовать ваш обратный прокси-сервер.",
|
||||
"authorization_required": "Требуется авторизация.",
|
||||
"cookies_disabled": "В вашем браузере отключены cookie файлы. Anubis требует их для подтверждения того, что вы являетесь настоящим человеком. Пожалуйста, включите файлы cookie для этого домена",
|
||||
"access_denied": "Доступ запрещён: код ошибки",
|
||||
"dronebl_entry": "DroneBL сообщил о записи",
|
||||
"see_dronebl_lookup": "см.",
|
||||
"internal_server_error": "Внутренняя ошибка сервера: администратор неправильно настроил Anubis. Обратитесь к администратору и попросите его просмотреть логи",
|
||||
"invalid_redirect": "Неверное перенаправление",
|
||||
"redirect_not_parseable": "URL-адрес перенаправления не может быть анализирован",
|
||||
"redirect_domain_not_allowed": "Перенаправление домена запрещено",
|
||||
"failed_to_sign_jwt": "не смог подписать JWT",
|
||||
"invalid_invocation": "Неверный вызов MakeChallenge",
|
||||
"client_error_browser": "Ошибка клиента: убедитесь, что у вас браузер новейшей версии, и повторите попытку позже.",
|
||||
"oh_noes": "О нет!",
|
||||
"benchmarking_anubis": "Анализ Анубиса!",
|
||||
"you_are_not_a_bot": "Вы не бот!",
|
||||
"making_sure_not_bot": "Проверяем, что вы не бот!",
|
||||
"celphase": "CELPHASE",
|
||||
"js_web_crypto_error": "В вашем браузере отсутствует функция web.crypto. Вы просматриваете страницу через защищённый контекст?",
|
||||
"js_web_workers_error": "Ваш браузер не поддерживает web worker (Anubis использует его, чтобы избежать зависания браузера). У вас установлен плагин типа JShelter?",
|
||||
"js_cookies_error": "Ваш браузер не сохраняет cookie файлы. Anubis использует их для определения клиентов, прошедших проверку, сохраняя подписанный токен в файле cookie. Включите сохранение файлов cookie для этого домена. Имена файлов cookie, хранимых Anubis, могут изменяться без предварительного уведомления. Имена и значения cookie файлов не являются частью общедоступного API.",
|
||||
"js_context_not_secure": "Ваш контекст небезопасен!",
|
||||
"js_context_not_secure_msg": "Попробуйте подключиться по HTTPS или попросите администратора, чтобы он настроил HTTPS. Подробнее см. <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||
"js_calculating": "Расчёт...",
|
||||
"js_missing_feature": "Отсутствует функция",
|
||||
"js_challenge_error": "Ошибка проверки!",
|
||||
"js_challenge_error_msg": "Не удалось определить алгоритм проверки. Возможно, нужно перезагрузить страницу..",
|
||||
"js_calculating_difficulty": "Расчёт...<br/>Сложность:",
|
||||
"js_speed": "Скорость:",
|
||||
"js_verification_longer": "Проверка занимает больше времени, чем ожидалось. Пожалуйста, не обновляйте страницу.",
|
||||
"js_success": "Успех!",
|
||||
"js_done_took": "Получилось! Заняло",
|
||||
"js_iterations": "итераций",
|
||||
"js_finished_reading": "Я дочитал, продолжить →",
|
||||
"js_calculation_error": "Ошибка расчёта!",
|
||||
"js_calculation_error_msg": "Не удалось рассчитать задачу:"
|
||||
}
|
||||
@@ -23,6 +23,7 @@ func TestLocalizationService(t *testing.T) {
|
||||
"is": "Hleður...",
|
||||
"pt-BR": "Carregando...",
|
||||
"tr": "Yükleniyor...",
|
||||
"ru": "Загрузка...",
|
||||
"zh-CN": "加载中...",
|
||||
"zh-TW": "載入中...",
|
||||
}
|
||||
@@ -57,7 +58,7 @@ func TestLocalizationService(t *testing.T) {
|
||||
}
|
||||
|
||||
type manifest struct {
|
||||
SupportedLanguages []string `json:"supported_languages"`
|
||||
SupportedLanguages []string `json:"supportedLanguages"`
|
||||
}
|
||||
|
||||
func loadManifest(t *testing.T) manifest {
|
||||
@@ -98,6 +99,11 @@ func TestComprehensiveTranslations(t *testing.T) {
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
manifest := loadManifest(t)
|
||||
if len(manifest.SupportedLanguages) == 0 {
|
||||
t.Fatal("no languages loaded")
|
||||
}
|
||||
|
||||
for _, lang := range loadManifest(t).SupportedLanguages {
|
||||
t.Run(lang, func(t *testing.T) {
|
||||
loc := service.GetLocalizer(lang)
|
||||
|
||||
Reference in New Issue
Block a user