mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 09:48:08 -04:00
feat: implement localization system (#716)
* lib/localization: implement localization system Locale files are placed in lib/localization/locales/. If you add a locale, update manifest.json with available locales. * Exclude locales from check spelling * tests(lib/localization): add comprehensive translations test Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(challenge/metarefresh): enable localization Signed-off-by: Xe Iaso <me@xeiaso.net> * fix: use simple syntax for localization in templ Also localize CELPHASE into French according to the wishes of the artist. Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * chore:(js): fix forbidden patterns Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: add goi18n to tools Signed-off-by: Xe Iaso <me@xeiaso.net> * test(lib/localization): dynamically determine the list of supported languages Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Co-authored-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
parent
c2423d0688
commit
ad5430612f
2
.github/actions/spelling/excludes.txt
vendored
2
.github/actions/spelling/excludes.txt
vendored
@ -89,3 +89,5 @@
|
|||||||
^lib/policy/config/testdata/bad/unparseable\.json$
|
^lib/policy/config/testdata/bad/unparseable\.json$
|
||||||
ignore$
|
ignore$
|
||||||
robots.txt
|
robots.txt
|
||||||
|
^lib/localization/locales/.*\.json$
|
||||||
|
^lib/localization/.*_test.go$
|
||||||
|
4
.github/actions/spelling/expect.txt
vendored
4
.github/actions/spelling/expect.txt
vendored
@ -33,7 +33,7 @@ Caddyfile
|
|||||||
caninetools
|
caninetools
|
||||||
Cardyb
|
Cardyb
|
||||||
celchecker
|
celchecker
|
||||||
CELPHASE
|
celphase
|
||||||
cerr
|
cerr
|
||||||
certresolver
|
certresolver
|
||||||
cespare
|
cespare
|
||||||
@ -42,6 +42,7 @@ cgr
|
|||||||
chainguard
|
chainguard
|
||||||
chall
|
chall
|
||||||
challengemozilla
|
challengemozilla
|
||||||
|
Chargement
|
||||||
checkpath
|
checkpath
|
||||||
checkresult
|
checkresult
|
||||||
chibi
|
chibi
|
||||||
@ -183,6 +184,7 @@ mozilla
|
|||||||
nbf
|
nbf
|
||||||
netsurf
|
netsurf
|
||||||
nginx
|
nginx
|
||||||
|
nicksnyder
|
||||||
nobots
|
nobots
|
||||||
NONINFRINGEMENT
|
NONINFRINGEMENT
|
||||||
nosleep
|
nosleep
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,3 +20,5 @@ node_modules
|
|||||||
|
|
||||||
# how does this get here
|
# how does this get here
|
||||||
doc/VERSION
|
doc/VERSION
|
||||||
|
|
||||||
|
web/static/locales/*.json
|
@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Implement localization system. Find locale files in lib/localization/locales/.
|
||||||
|
|
||||||
## v1.20.0: Thancred Waters
|
## v1.20.0: Thancred Waters
|
||||||
|
|
||||||
The big ticket items are as follows:
|
The big ticket items are as follows:
|
||||||
|
4
go.mod
4
go.mod
@ -29,7 +29,7 @@ require (
|
|||||||
cel.dev/expr v0.23.1 // indirect
|
cel.dev/expr v0.23.1 // indirect
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
github.com/AlekSi/pointer v1.2.0 // indirect
|
github.com/AlekSi/pointer v1.2.0 // indirect
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||||
@ -87,6 +87,7 @@ require (
|
|||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/natefinch/atomic v1.0.1 // indirect
|
github.com/natefinch/atomic v1.0.1 // indirect
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
@ -133,6 +134,7 @@ require (
|
|||||||
tool (
|
tool (
|
||||||
github.com/TecharoHQ/yeet/cmd/yeet
|
github.com/TecharoHQ/yeet/cmd/yeet
|
||||||
github.com/a-h/templ/cmd/templ
|
github.com/a-h/templ/cmd/templ
|
||||||
|
github.com/nicksnyder/go-i18n/v2/goi18n
|
||||||
github.com/suzuki-shunsuke/pinact/cmd/pinact
|
github.com/suzuki-shunsuke/pinact/cmd/pinact
|
||||||
golang.org/x/tools/cmd/deadcode
|
golang.org/x/tools/cmd/deadcode
|
||||||
golang.org/x/tools/cmd/goimports
|
golang.org/x/tools/cmd/goimports
|
||||||
|
4
go.sum
4
go.sum
@ -10,6 +10,8 @@ github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
|
|||||||
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||||
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
@ -237,6 +239,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
|||||||
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
|
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
|
||||||
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
|
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
|
||||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
||||||
"github.com/TecharoHQ/anubis/internal/ogtags"
|
"github.com/TecharoHQ/anubis/internal/ogtags"
|
||||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy"
|
"github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/checker"
|
"github.com/TecharoHQ/anubis/lib/policy/checker"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
@ -87,6 +88,8 @@ func (s *Server) getTokenKeyfunc() jwt.Keyfunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (s *Server) challengeFor(r *http.Request, difficulty int) string {
|
func (s *Server) challengeFor(r *http.Request, difficulty int) string {
|
||||||
var fp [32]byte
|
var fp [32]byte
|
||||||
if len(s.hs512Secret) == 0 {
|
if len(s.hs512Secret) == 0 {
|
||||||
@ -126,7 +129,8 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS
|
|||||||
cr, rule, err := s.check(r)
|
cr, rule, err := s.check(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
s.respondWithError(w, r, "Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to look for the logs around \"maybeReverseProxy\"")
|
localizer := localization.GetLocalizer(r)
|
||||||
|
s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy\"", localizer.T("internal_server_error")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +214,8 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch
|
|||||||
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
|
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
switch cr.Rule {
|
switch cr.Rule {
|
||||||
case config.RuleAllow:
|
case config.RuleAllow:
|
||||||
lg.Debug("allowing traffic to origin (explicit)")
|
lg.Debug("allowing traffic to origin (explicit)")
|
||||||
@ -220,13 +226,13 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch
|
|||||||
lg.Info("explicit deny")
|
lg.Info("explicit deny")
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
lg.Error("rule is nil, cannot calculate checksum")
|
lg.Error("rule is nil, cannot calculate checksum")
|
||||||
s.respondWithError(w, r, "Internal Server Error: Please contact the administrator and ask them to look for the logs around \"maybeReverseProxy.RuleDeny\"")
|
s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.RuleDeny\"", localizer.T("internal_server_error")))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
hash := rule.Hash()
|
hash := rule.Hash()
|
||||||
|
|
||||||
lg.Debug("rule hash", "hash", hash)
|
lg.Debug("rule hash", "hash", hash)
|
||||||
s.respondWithStatus(w, r, fmt.Sprintf("Access Denied: error code %s", hash), s.policy.StatusCodes.Deny)
|
s.respondWithStatus(w, r, fmt.Sprintf("%s %s", localizer.T("access_denied"), hash), s.policy.StatusCodes.Deny)
|
||||||
return true
|
return true
|
||||||
case config.RuleChallenge:
|
case config.RuleChallenge:
|
||||||
lg.Debug("challenge requested")
|
lg.Debug("challenge requested")
|
||||||
@ -237,7 +243,7 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch
|
|||||||
default:
|
default:
|
||||||
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
||||||
slog.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule)
|
slog.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule)
|
||||||
s.respondWithError(w, r, "Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to look for the logs around \"maybeReverseProxy.Rules\"")
|
s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.Rules\"", localizer.T("internal_server_error")))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -258,7 +264,12 @@ func (s *Server) handleDNSBL(w http.ResponseWriter, r *http.Request, ip string,
|
|||||||
|
|
||||||
if resp != dnsbl.AllGood {
|
if resp != dnsbl.AllGood {
|
||||||
lg.Info("DNSBL hit", "status", resp.String())
|
lg.Info("DNSBL hit", "status", resp.String())
|
||||||
s.respondWithStatus(w, r, fmt.Sprintf("DroneBL reported an entry: %s, see https://dronebl.org/lookup?ip=%s", resp.String(), ip), s.policy.StatusCodes.Deny)
|
localizer := localization.GetLocalizer(r)
|
||||||
|
s.respondWithStatus(w, r, fmt.Sprintf("%s: %s, %s https://dronebl.org/lookup?ip=%s",
|
||||||
|
localizer.T("dronebl_entry"),
|
||||||
|
resp.String(),
|
||||||
|
localizer.T("see_dronebl_lookup"),
|
||||||
|
ip), s.policy.StatusCodes.Deny)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +278,7 @@ func (s *Server) handleDNSBL(w http.ResponseWriter, r *http.Request, ip string,
|
|||||||
|
|
||||||
func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
||||||
lg := internal.GetRequestLogger(r)
|
lg := internal.GetRequestLogger(r)
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
redir := r.FormValue("redir")
|
redir := r.FormValue("redir")
|
||||||
if redir == "" {
|
if redir == "" {
|
||||||
@ -276,7 +288,7 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
encoder.Encode(struct {
|
encoder.Encode(struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
}{
|
}{
|
||||||
Error: "Invalid invocation of MakeChallenge",
|
Error: localizer.T("invalid_invocation"),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -291,7 +303,7 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
err := encoder.Encode(struct {
|
err := encoder.Encode(struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
}{
|
}{
|
||||||
Error: "Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to look for the logs around \"makeChallenge\"",
|
Error: fmt.Sprintf("%s \"makeChallenge\"", localizer.T("internal_server_error")),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("failed to encode error response", "err", err)
|
lg.Error("failed to encode error response", "err", err)
|
||||||
@ -322,6 +334,7 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
||||||
lg := internal.GetRequestLogger(r)
|
lg := internal.GetRequestLogger(r)
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
// Adjust cookie path if base prefix is not empty
|
// Adjust cookie path if base prefix is not empty
|
||||||
cookiePath := "/"
|
cookiePath := "/"
|
||||||
@ -333,7 +346,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
||||||
s.ClearCookie(w, anubis.TestCookieName, "/", r.Host)
|
s.ClearCookie(w, anubis.TestCookieName, "/", r.Host)
|
||||||
lg.Warn("user has cookies disabled, this is not an anubis bug")
|
lg.Warn("user has cookies disabled, this is not an anubis bug")
|
||||||
s.respondWithError(w, r, "Your browser is configured to disable cookies. Anubis requires cookies for the legitimate interest of making sure you are a valid client. Please enable cookies for this domain")
|
s.respondWithError(w, r, localizer.T("cookies_disabled"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +356,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
redirURL, err := url.ParseRequestURI(redir)
|
redirURL, err := url.ParseRequestURI(redir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("invalid redirect", "err", err)
|
lg.Error("invalid redirect", "err", err)
|
||||||
s.respondWithError(w, r, "Invalid redirect")
|
s.respondWithError(w, r, localizer.T("invalid_redirect"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// used by the path checker rule
|
// used by the path checker rule
|
||||||
@ -351,18 +364,18 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
urlParsed, err := r.URL.Parse(redir)
|
urlParsed, err := r.URL.Parse(redir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.respondWithError(w, r, "Redirect URL not parseable")
|
s.respondWithError(w, r, localizer.T("redirect_not_parseable"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (len(urlParsed.Host) > 0 && len(s.opts.RedirectDomains) != 0 && !slices.Contains(s.opts.RedirectDomains, urlParsed.Host)) || urlParsed.Host != r.URL.Host {
|
if (len(urlParsed.Host) > 0 && len(s.opts.RedirectDomains) != 0 && !slices.Contains(s.opts.RedirectDomains, urlParsed.Host)) || urlParsed.Host != r.URL.Host {
|
||||||
s.respondWithError(w, r, "Redirect domain not allowed")
|
s.respondWithError(w, r, localizer.T("redirect_domain_not_allowed"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cr, rule, err := s.check(r)
|
cr, rule, err := s.check(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
s.respondWithError(w, r, "Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to look for the logs around \"passChallenge\"")
|
s.respondWithError(w, r, fmt.Sprintf("%s \"passChallenge\"", localizer.T("internal_server_error")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lg = lg.With("check_result", cr)
|
lg = lg.With("check_result", cr)
|
||||||
@ -370,7 +383,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
impl, ok := challenge.Get(rule.Challenge.Algorithm)
|
impl, ok := challenge.Get(rule.Challenge.Algorithm)
|
||||||
if !ok {
|
if !ok {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
s.respondWithError(w, r, fmt.Sprintf("Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to file a bug as Anubis is trying to use challenge method %s but it does not exist in the challenge registry", rule.Challenge.Algorithm))
|
s.respondWithError(w, r, fmt.Sprintf("%s: %s", localizer.T("internal_server_error"), rule.Challenge.Algorithm))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +416,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("failed to sign JWT", "err", err)
|
lg.Error("failed to sign JWT", "err", err)
|
||||||
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
s.ClearCookie(w, s.cookieName, cookiePath, r.Host)
|
||||||
s.respondWithError(w, r, "failed to sign JWT")
|
s.respondWithError(w, r, localizer.T("failed_to_sign_jwt"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy"
|
"github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
@ -34,7 +35,9 @@ func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput)
|
|||||||
q.Set("challenge", in.Challenge)
|
q.Set("challenge", in.Challenge)
|
||||||
u.RawQuery = q.Encode()
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
component, err := web.BaseWithChallengeAndOGTags("Making sure you're not a bot!", page(in.Challenge, u.String(), in.Rule.Challenge.Difficulty), in.Impressum, in.Challenge, in.Rule.Challenge, in.OGTags)
|
loc := localization.GetLocalizer(r)
|
||||||
|
component, err := web.BaseWithChallengeAndOGTags(loc.T("making_sure_not_bot"), page(in.Challenge, u.String(), in.Rule.Challenge.Difficulty, loc), in.Impressum, in.Challenge, in.Rule.Challenge, in.OGTags, loc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't render page: %w", err)
|
return nil, fmt.Errorf("can't render page: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
)
|
)
|
||||||
|
|
||||||
templ page(challenge, redir string, difficulty int) {
|
templ page(challenge, redir string, difficulty int, loc *localization.SimpleLocalizer) {
|
||||||
<div class="centered-div">
|
<div class="centered-div">
|
||||||
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<img style="display:none;" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version }/>
|
<img style="display:none;" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<p id="status">Loading...</p>
|
<p id="status">{ loc.T("loading") }</p>
|
||||||
<p>Please wait a moment while we ensure the security of your connection.</p>
|
<p>{ loc.T("connection_security") }</p>
|
||||||
<meta http-equiv="refresh" content={ fmt.Sprintf("%d; url=%s", difficulty, redir) }/>
|
<meta http-equiv="refresh" content={ fmt.Sprintf("%d; url=%s", difficulty, redir) }/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
41
lib/challenge/metarefresh/metarefresh_templ.go
generated
41
lib/challenge/metarefresh/metarefresh_templ.go
generated
@ -12,9 +12,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
)
|
)
|
||||||
|
|
||||||
func page(challenge, redir string, difficulty int) templ.Component {
|
func page(challenge, redir string, difficulty int, loc *localization.SimpleLocalizer) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -42,7 +43,7 @@ func page(challenge, redir string, difficulty int) templ.Component {
|
|||||||
var templ_7745c5c3_Var2 string
|
var templ_7745c5c3_Var2 string
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 11, Col: 165}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 12, Col: 165}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -55,26 +56,52 @@ func page(challenge, redir string, difficulty int) templ.Component {
|
|||||||
var templ_7745c5c3_Var3 string
|
var templ_7745c5c3_Var3 string
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 12, Col: 174}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 13, Col: 174}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><p id=\"status\">Loading...</p><p>Please wait a moment while we ensure the security of your connection.</p><meta http-equiv=\"refresh\" content=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><p id=\"status\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 string
|
var templ_7745c5c3_Var4 string
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d; url=%s", difficulty, redir))
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(loc.T("loading"))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 15, Col: 83}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 14, Col: 35}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</p><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(loc.T("connection_security"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 15, Col: 35}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</p><meta http-equiv=\"refresh\" content=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var6 string
|
||||||
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d; url=%s", difficulty, redir))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 16, Col: 83}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\"></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
chall "github.com/TecharoHQ/anubis/lib/challenge"
|
chall "github.com/TecharoHQ/anubis/lib/challenge"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy"
|
"github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
@ -29,7 +30,8 @@ func (i *Impl) Setup(mux *http.ServeMux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *chall.IssueInput) (templ.Component, error) {
|
func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *chall.IssueInput) (templ.Component, error) {
|
||||||
component, err := web.BaseWithChallengeAndOGTags("Making sure you're not a bot!", web.Index(), in.Impressum, in.Challenge, in.Rule.Challenge, in.OGTags)
|
loc := localization.GetLocalizer(r)
|
||||||
|
component, err := web.BaseWithChallengeAndOGTags(loc.T("making_sure_not_bot"), web.Index(loc), in.Impressum, in.Challenge, in.Rule.Challenge, in.OGTags, loc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't render page: %w", err)
|
return nil, fmt.Errorf("can't render page: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
||||||
"github.com/TecharoHQ/anubis/internal/ogtags"
|
"github.com/TecharoHQ/anubis/internal/ogtags"
|
||||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy"
|
"github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
@ -155,7 +156,7 @@ func New(opts Options) (*Server, error) {
|
|||||||
if opts.Policy.Impressum != nil {
|
if opts.Policy.Impressum != nil {
|
||||||
registerWithPrefix(anubis.APIPrefix+"imprint", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
registerWithPrefix(anubis.APIPrefix+"imprint", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
templ.Handler(
|
templ.Handler(
|
||||||
web.Base(opts.Policy.Impressum.Page.Title, opts.Policy.Impressum.Page, opts.Policy.Impressum),
|
web.Base(opts.Policy.Impressum.Page.Title, opts.Policy.Impressum.Page, opts.Policy.Impressum, localization.GetLocalizer(r)),
|
||||||
).ServeHTTP(w, r)
|
).ServeHTTP(w, r)
|
||||||
}), "GET")
|
}), "GET")
|
||||||
}
|
}
|
||||||
|
27
lib/http.go
27
lib/http.go
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
"github.com/TecharoHQ/anubis/internal"
|
"github.com/TecharoHQ/anubis/internal"
|
||||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy"
|
"github.com/TecharoHQ/anubis/lib/policy"
|
||||||
"github.com/TecharoHQ/anubis/web"
|
"github.com/TecharoHQ/anubis/web"
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
@ -83,9 +84,11 @@ func randomChance(n int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *policy.Bot, returnHTTPStatusOnly bool) {
|
func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *policy.Bot, returnHTTPStatusOnly bool) {
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
if returnHTTPStatusOnly {
|
if returnHTTPStatusOnly {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
w.Write([]byte("Authorization required"))
|
w.Write([]byte(localizer.T("authorization_required")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +96,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *polic
|
|||||||
|
|
||||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") && randomChance(64) {
|
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") && randomChance(64) {
|
||||||
lg.Error("client was given a challenge but does not in fact support gzip compression")
|
lg.Error("client was given a challenge but does not in fact support gzip compression")
|
||||||
s.respondWithError(w, r, "Client Error: Please ensure your browser is up to date and try again later.")
|
s.respondWithError(w, r, localizer.T("client_error_browser"))
|
||||||
}
|
}
|
||||||
|
|
||||||
challengesIssued.WithLabelValues("embedded").Add(1)
|
challengesIssued.WithLabelValues("embedded").Add(1)
|
||||||
@ -118,7 +121,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *polic
|
|||||||
impl, ok := challenge.Get(rule.Challenge.Algorithm)
|
impl, ok := challenge.Get(rule.Challenge.Algorithm)
|
||||||
if !ok {
|
if !ok {
|
||||||
lg.Error("check failed", "err", "can't get algorithm", "algorithm", rule.Challenge.Algorithm)
|
lg.Error("check failed", "err", "can't get algorithm", "algorithm", rule.Challenge.Algorithm)
|
||||||
s.respondWithError(w, r, fmt.Sprintf("Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to file a bug as Anubis is trying to use challenge method %s but it does not exist in the challenge registry", rule.Challenge.Algorithm))
|
s.respondWithError(w, r, fmt.Sprintf("%s: %s", localizer.T("internal_server_error"), rule.Challenge.Algorithm))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +135,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *polic
|
|||||||
component, err := impl.Issue(r, lg, in)
|
component, err := impl.Issue(r, lg, in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("[unexpected] render failed, please open an issue", "err", err) // This is likely a bug in the template. Should never be triggered as CI tests for this.
|
lg.Error("[unexpected] render failed, please open an issue", "err", err) // This is likely a bug in the template. Should never be triggered as CI tests for this.
|
||||||
s.respondWithError(w, r, "Internal Server Error: please contact the administrator and ask them to look for the logs around \"RenderIndex\"")
|
s.respondWithError(w, r, fmt.Sprintf("%s \"RenderIndex\"", localizer.T("internal_server_error")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,8 +147,10 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *polic
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RenderBench(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) RenderBench(w http.ResponseWriter, r *http.Request) {
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
templ.Handler(
|
templ.Handler(
|
||||||
web.Base("Benchmarking Anubis!", web.Bench(), s.policy.Impressum),
|
web.Base(localizer.T("benchmarking_anubis"), web.Bench(localizer), s.policy.Impressum, localizer),
|
||||||
).ServeHTTP(w, r)
|
).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +159,9 @@ func (s *Server) respondWithError(w http.ResponseWriter, r *http.Request, messag
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) respondWithStatus(w http.ResponseWriter, r *http.Request, msg string, status int) {
|
func (s *Server) respondWithStatus(w http.ResponseWriter, r *http.Request, msg string, status int) {
|
||||||
templ.Handler(web.Base("Oh noes!", web.ErrorPage(msg, s.opts.WebmasterEmail), s.policy.Impressum), templ.WithStatus(status)).ServeHTTP(w, r)
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
|
templ.Handler(web.Base(localizer.T("oh_noes"), web.ErrorPage(msg, s.opts.WebmasterEmail, localizer), s.policy.Impressum, localizer), templ.WithStatus(status)).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -189,15 +196,17 @@ func (s *Server) stripBasePrefixFromRequest(r *http.Request) *http.Request {
|
|||||||
|
|
||||||
func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
|
||||||
if s.next == nil {
|
if s.next == nil {
|
||||||
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
redir := r.FormValue("redir")
|
redir := r.FormValue("redir")
|
||||||
urlParsed, err := r.URL.Parse(redir)
|
urlParsed, err := r.URL.Parse(redir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.respondWithStatus(w, r, "Redirect URL not parseable", http.StatusBadRequest)
|
s.respondWithStatus(w, r, localizer.T("redirect_not_parseable"), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(urlParsed.Host) > 0 && len(s.opts.RedirectDomains) != 0 && !slices.Contains(s.opts.RedirectDomains, urlParsed.Host)) || urlParsed.Host != r.URL.Host {
|
if (len(urlParsed.Host) > 0 && len(s.opts.RedirectDomains) != 0 && !slices.Contains(s.opts.RedirectDomains, urlParsed.Host)) || urlParsed.Host != r.URL.Host {
|
||||||
s.respondWithStatus(w, r, "Redirect domain not allowed", http.StatusBadRequest)
|
s.respondWithStatus(w, r, localizer.T("redirect_domain_not_allowed"), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +216,7 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
templ.Handler(
|
templ.Handler(
|
||||||
web.Base("You are not a bot!", web.StaticHappy(), s.policy.Impressum),
|
web.Base(localizer.T("you_are_not_a_bot"), web.StaticHappy(localizer), s.policy.Impressum, localizer),
|
||||||
).ServeHTTP(w, r)
|
).ServeHTTP(w, r)
|
||||||
} else {
|
} else {
|
||||||
requestsProxied.WithLabelValues(r.Host).Inc()
|
requestsProxied.WithLabelValues(r.Host).Inc()
|
||||||
|
63
lib/localization/locales/en.json
Normal file
63
lib/localization/locales/en.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"loading": "Loading...",
|
||||||
|
"why_am_i_seeing": "Why am I seeing this?",
|
||||||
|
"protected_by": "Protected by",
|
||||||
|
"made_with": "Made with ❤️ in 🇨🇦",
|
||||||
|
"mascot_design": "Mascot design by",
|
||||||
|
"ai_companies_explanation": "You are seeing this because the administrator of this website has set up Anubis to protect the server against the scourge of AI companies aggressively scraping websites. This can and does cause downtime for the websites, which makes their resources inaccessible for everyone.",
|
||||||
|
"anubis_compromise": "Anubis is a compromise. Anubis uses a Proof-of-Work scheme in the vein of Hashcash, a proposed proof-of-work scheme for reducing email spam. The idea is that at individual scales the additional load is ignorable, but at mass scraper levels it adds up and makes scraping much more expensive.",
|
||||||
|
"hack_purpose": "Ultimately, this is a hack whose real purpose is to give a \"good enough\" placeholder solution so that more time can be spent on fingerprinting and identifying headless browsers (EG: via how they do font rendering) so that the challenge proof of work page doesn't need to be presented to users that are much more likely to be legitimate.",
|
||||||
|
"jshelter_note": "Please note that Anubis requires the use of modern JavaScript features that plugins like JShelter will disable. Please disable JShelter or other such plugins for this domain.",
|
||||||
|
"version_info": "This website is running Anubis version",
|
||||||
|
"try_again": "Try again",
|
||||||
|
"go_home": "Go home",
|
||||||
|
"contact_webmaster": "or if you believe you should not be blocked, please contact the webmaster at",
|
||||||
|
"connection_security": "Please wait a moment while we ensure the security of your connection.",
|
||||||
|
"javascript_required": "Sadly, you must enable JavaScript to get past this challenge. This is required because AI companies have changed the social contract around how website hosting works. A no-JS solution is a work-in-progress.",
|
||||||
|
"benchmark_requires_js": "Running the benchmark tool requires JavaScript to be enabled.",
|
||||||
|
"difficulty": "Difficulty:",
|
||||||
|
"algorithm": "Algorithm:",
|
||||||
|
"compare": "Compare:",
|
||||||
|
"time": "Time",
|
||||||
|
"iters": "Iters",
|
||||||
|
"time_a": "Time A",
|
||||||
|
"iters_a": "Iters A",
|
||||||
|
"time_b": "Time B",
|
||||||
|
"iters_b": "Iters B",
|
||||||
|
"static_check_endpoint": "This is just a check endpoint for your reverse proxy to use.",
|
||||||
|
"authorization_required": "Authorization required",
|
||||||
|
"cookies_disabled": "Your browser is configured to disable cookies. Anubis requires cookies for the legitimate interest of making sure you are a valid client. Please enable cookies for this domain",
|
||||||
|
"access_denied": "Access Denied: error code",
|
||||||
|
"dronebl_entry": "DroneBL reported an entry",
|
||||||
|
"see_dronebl_lookup": "see",
|
||||||
|
"internal_server_error": "Internal Server Error: administrator has misconfigured Anubis. Please contact the administrator and ask them to look for the logs around",
|
||||||
|
"invalid_redirect": "Invalid redirect",
|
||||||
|
"redirect_not_parseable": "Redirect URL not parseable",
|
||||||
|
"redirect_domain_not_allowed": "Redirect domain not allowed",
|
||||||
|
"failed_to_sign_jwt": "failed to sign JWT",
|
||||||
|
"invalid_invocation": "Invalid invocation of MakeChallenge",
|
||||||
|
"client_error_browser": "Client Error: Please ensure your browser is up to date and try again later.",
|
||||||
|
"oh_noes": "Oh noes!",
|
||||||
|
"benchmarking_anubis": "Benchmarking Anubis!",
|
||||||
|
"you_are_not_a_bot": "You are not a bot!",
|
||||||
|
"making_sure_not_bot": "Making sure you're not a bot!",
|
||||||
|
"celphase": "CELPHASE",
|
||||||
|
"js_web_crypto_error": "Your browser doesn't have a functioning web.crypto element. Are you viewing this over a secure context?",
|
||||||
|
"js_web_workers_error": "Your browser doesn't support web workers (Anubis uses this to avoid freezing your browser). Do you have a plugin like JShelter installed?",
|
||||||
|
"js_cookies_error": "Your browser doesn't store cookies. Anubis uses cookies to determine which clients have passed challenges by storing a signed token in a cookie. Please enable storing cookies for this domain. The names of the cookies Anubis stores may vary without notice. Cookie names and values are not part of the public API.",
|
||||||
|
"js_context_not_secure": "Your context is not secure!",
|
||||||
|
"js_context_not_secure_msg": "Try connecting over HTTPS or let the admin know to set up HTTPS. For more information, see <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||||
|
"js_calculating": "Calculating...",
|
||||||
|
"js_missing_feature": "Missing feature",
|
||||||
|
"js_challenge_error": "Challenge error!",
|
||||||
|
"js_challenge_error_msg": "Failed to resolve check algorithm. You may want to reload the page.",
|
||||||
|
"js_calculating_difficulty": "Calculating...<br/>Difficulty:",
|
||||||
|
"js_speed": "Speed:",
|
||||||
|
"js_verification_longer": "Verification is taking longer than expected. Please do not refresh the page.",
|
||||||
|
"js_success": "Success!",
|
||||||
|
"js_done_took": "Done! Took",
|
||||||
|
"js_iterations": "iterations",
|
||||||
|
"js_finished_reading": "I've finished reading, continue →",
|
||||||
|
"js_calculation_error": "Calculation error!",
|
||||||
|
"js_calculation_error_msg": "Failed to calculate challenge:"
|
||||||
|
}
|
63
lib/localization/locales/es.json
Normal file
63
lib/localization/locales/es.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"loading": "Cargando...",
|
||||||
|
"why_am_i_seeing": "¿Por qué veo esto?",
|
||||||
|
"protected_by": "Protegido por",
|
||||||
|
"made_with": "Hecho con ❤️ en 🇨🇦",
|
||||||
|
"mascot_design": "Diseño de la mascota por",
|
||||||
|
"ai_companies_explanation": "Ves esto porque el administrador de este sitio web ha configurado Anubis para proteger el servidor contra la plaga de empresas de IA que rastrean agresivamente los sitios web. Esto puede y causa tiempo de inactividad para los sitios web, haciendo que sus recursos sean inaccesibles para todos.",
|
||||||
|
"anubis_compromise": "Anubis es un compromiso. Anubis utiliza un esquema de Prueba de Trabajo en la línea de Hashcash, un esquema de prueba de trabajo propuesto para reducir el spam por correo electrónico. La idea es que a escala individual, la carga adicional es insignificante, pero a escala de raspadores masivos, se acumula y hace que el raspado sea mucho más costoso.",
|
||||||
|
"hack_purpose": "En última instancia, esto es un hack cuyo verdadero propósito es dar una solución alternativa \"suficientemente buena\" para que se pueda dedicar más tiempo a la huella digital e identificación de navegadores sin cabeza (por ejemplo: a través de cómo renderizan las fuentes) para que la página de desafío de prueba de trabajo no necesite ser presentada a usuarios que son mucho más propensos a ser legítimos.",
|
||||||
|
"jshelter_note": "Ten en cuenta que Anubis requiere el uso de características modernas de JavaScript que plugins como JShelter deshabilitarán. Por favor, deshabilita JShelter u otros plugins similares para este dominio.",
|
||||||
|
"version_info": "Este sitio web utiliza Anubis versión",
|
||||||
|
"try_again": "Intentar de nuevo",
|
||||||
|
"go_home": "Inicio",
|
||||||
|
"contact_webmaster": "o si crees que no deberías estar bloqueado, por favor contacta al webmaster en",
|
||||||
|
"connection_security": "Espere un momento mientras garantizamos la seguridad de su conexión.",
|
||||||
|
"javascript_required": "Desafortunadamente, necesitas habilitar JavaScript para pasar este desafío. Esto es requerido porque las empresas de IA han cambiado el contrato social sobre cómo funciona el alojamiento de sitios web. Una solución sin JS está en desarrollo.",
|
||||||
|
"benchmark_requires_js": "Ejecutar la herramienta de benchmark requiere que JavaScript esté habilitado.",
|
||||||
|
"difficulty": "Dificultad:",
|
||||||
|
"algorithm": "Algoritmo:",
|
||||||
|
"compare": "Comparar:",
|
||||||
|
"time": "Tiempo",
|
||||||
|
"iters": "Iteraciones",
|
||||||
|
"time_a": "Tiempo A",
|
||||||
|
"iters_a": "Iter. A",
|
||||||
|
"time_b": "Tiempo B",
|
||||||
|
"iters_b": "Iter. B",
|
||||||
|
"static_check_endpoint": "Este es solo un endpoint de verificación para que tu proxy inverso lo use.",
|
||||||
|
"authorization_required": "Autorización requerida",
|
||||||
|
"cookies_disabled": "Tu navegador está configurado para deshabilitar las cookies. Anubis requiere cookies para el interés legítimo de asegurar que eres un cliente válido. Por favor habilita las cookies para este dominio",
|
||||||
|
"access_denied": "Acceso denegado: código de error",
|
||||||
|
"dronebl_entry": "DroneBL reportó una entrada",
|
||||||
|
"see_dronebl_lookup": "ver",
|
||||||
|
"internal_server_error": "Error interno del servidor: el administrador ha configurado mal Anubis. Por favor contacta al administrador y pídele que revise los logs alrededor de",
|
||||||
|
"invalid_redirect": "Redirección inválida",
|
||||||
|
"redirect_not_parseable": "URL de redirección no analizable",
|
||||||
|
"redirect_domain_not_allowed": "Dominio de redirección no permitido",
|
||||||
|
"failed_to_sign_jwt": "falló al firmar JWT",
|
||||||
|
"invalid_invocation": "Invocación inválida de MakeChallenge",
|
||||||
|
"client_error_browser": "Error del cliente: Por favor asegúrate de que tu navegador esté actualizado e inténtalo de nuevo más tarde.",
|
||||||
|
"oh_noes": "¡Oh no!",
|
||||||
|
"benchmarking_anubis": "¡Benchmarking de Anubis!",
|
||||||
|
"you_are_not_a_bot": "¡No eres un robot!",
|
||||||
|
"making_sure_not_bot": "¡Asegurándonos de que no eres un robot!",
|
||||||
|
"celphase": "CELPHASE",
|
||||||
|
"js_web_crypto_error": "Tu navegador no tiene un elemento web.crypto funcional. ¿Estás viendo esta página en un contexto seguro?",
|
||||||
|
"js_web_workers_error": "Tu navegador no soporta web workers (Anubis los usa para evitar bloquear tu navegador). ¿Tienes un plugin como JShelter instalado?",
|
||||||
|
"js_cookies_error": "Tu navegador no almacena cookies. Anubis usa cookies para determinar qué clientes han pasado los desafíos almacenando un token firmado en una cookie. Por favor habilita el almacenamiento de cookies para este dominio. Los nombres de las cookies que Anubis almacena pueden variar sin previo aviso. Los nombres y valores de las cookies no son parte de la API pública.",
|
||||||
|
"js_context_not_secure": "¡Tu contexto no es seguro!",
|
||||||
|
"js_context_not_secure_msg": "Intenta conectarte a través de HTTPS o informa al administrador para configurar HTTPS. Para más información, consulta <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": "Característica faltante",
|
||||||
|
"js_challenge_error": "¡Error de desafío!",
|
||||||
|
"js_challenge_error_msg": "Falló al resolver el algoritmo de verificación. Puedes intentar recargar la página.",
|
||||||
|
"js_calculating_difficulty": "Calculando...<br/>Dificultad:",
|
||||||
|
"js_speed": "Velocidad:",
|
||||||
|
"js_verification_longer": "La verificación está tomando más tiempo del esperado. Por favor no actualices la página.",
|
||||||
|
"js_success": "¡Éxito!",
|
||||||
|
"js_done_took": "¡Terminado! Tomó",
|
||||||
|
"js_iterations": "iteraciones",
|
||||||
|
"js_finished_reading": "He terminado de leer, continuar →",
|
||||||
|
"js_calculation_error": "¡Error de cálculo!",
|
||||||
|
"js_calculation_error_msg": "Falló al calcular el desafío:"
|
||||||
|
}
|
63
lib/localization/locales/fr.json
Normal file
63
lib/localization/locales/fr.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"loading": "Chargement...",
|
||||||
|
"why_am_i_seeing": "Pourquoi je vois ceci ?",
|
||||||
|
"protected_by": "Protégé par",
|
||||||
|
"made_with": "Fait avec ❤️ au 🇨🇦",
|
||||||
|
"mascot_design": "Design de la mascotte par",
|
||||||
|
"ai_companies_explanation": "Vous voyez ceci car l'administrateur de ce site web a configuré Anubis pour protéger le serveur contre le fléau des entreprises d'IA qui scrapent agressivement les sites web. Cela peut et cause des temps d'arrêt pour les sites web, ce qui rend leurs ressources inaccessibles pour tout le monde.",
|
||||||
|
"anubis_compromise": "Anubis est un compromis. Anubis utilise un schéma de Preuve de Travail dans la veine de Hashcash, un schéma de preuve de travail proposé pour réduire le spam par email. L'idée est qu'à l'échelle individuelle, la charge supplémentaire est négligeable, mais à l'échelle des scrapers de masse, cela s'accumule et rend le scraping beaucoup plus coûteux.",
|
||||||
|
"hack_purpose": "En fin de compte, c'est un hack dont le véritable objectif est de donner une solution de substitution \"assez bonne\" pour que plus de temps puisse être consacré à l'empreinte digitale et à l'identification des navigateurs sans tête (par exemple : via la façon dont ils font le rendu des polices) afin que la page de défi de preuve de travail n'ait pas besoin d'être présentée aux utilisateurs qui sont beaucoup plus susceptibles d'être légitimes.",
|
||||||
|
"jshelter_note": "Veuillez noter qu'Anubis nécessite l'utilisation de fonctionnalités JavaScript modernes que des plugins comme JShelter désactiveront. Veuillez désactiver JShelter ou d'autres plugins similaires pour ce domaine.",
|
||||||
|
"version_info": "Ce site web utilise Anubis version",
|
||||||
|
"try_again": "Réessayer",
|
||||||
|
"go_home": "Accueil",
|
||||||
|
"contact_webmaster": "ou si vous pensez que vous ne devriez pas être bloqué, veuillez contacter le webmaster à",
|
||||||
|
"connection_security": "Veuillez patienter un instant pendant que nous assurons la sécurité de votre connexion.",
|
||||||
|
"javascript_required": "Malheureusement, vous devez activer JavaScript pour passer ce défi. Ceci est requis car les entreprises d'IA ont changé le contrat social autour du fonctionnement de l'hébergement de sites web. Une solution sans JS est en cours de développement.",
|
||||||
|
"benchmark_requires_js": "L'exécution de l'outil de benchmark nécessite l'activation de JavaScript.",
|
||||||
|
"difficulty": "Difficulté :",
|
||||||
|
"algorithm": "Algorithme :",
|
||||||
|
"compare": "Comparer :",
|
||||||
|
"time": "Temps",
|
||||||
|
"iters": "Itérations",
|
||||||
|
"time_a": "Temps A",
|
||||||
|
"iters_a": "Itér. A",
|
||||||
|
"time_b": "Temps B",
|
||||||
|
"iters_b": "Itér. B",
|
||||||
|
"static_check_endpoint": "Ceci est juste un point de terminaison de vérification pour votre proxy inverse à utiliser.",
|
||||||
|
"authorization_required": "Autorisation requise",
|
||||||
|
"cookies_disabled": "Votre navigateur est configuré pour désactiver les cookies. Anubis nécessite des cookies pour l'intérêt légitime de s'assurer que vous êtes un client valide. Veuillez activer les cookies pour ce domaine",
|
||||||
|
"access_denied": "Accès refusé : code d'erreur",
|
||||||
|
"dronebl_entry": "DroneBL a signalé une entrée",
|
||||||
|
"see_dronebl_lookup": "voir",
|
||||||
|
"internal_server_error": "Erreur interne du serveur : l'administrateur a mal configuré Anubis. Veuillez contacter l'administrateur et lui demander de consulter les logs autour de",
|
||||||
|
"invalid_redirect": "Redirection invalide",
|
||||||
|
"redirect_not_parseable": "URL de redirection non analysable",
|
||||||
|
"redirect_domain_not_allowed": "Domaine de redirection non autorisé",
|
||||||
|
"failed_to_sign_jwt": "échec de la signature JWT",
|
||||||
|
"invalid_invocation": "Invocation invalide de MakeChallenge",
|
||||||
|
"client_error_browser": "Erreur client : Veuillez vous assurer que votre navigateur est à jour et réessayez plus tard.",
|
||||||
|
"oh_noes": "Oh non !",
|
||||||
|
"benchmarking_anubis": "Test de performance d'Anubis !",
|
||||||
|
"you_are_not_a_bot": "Vous n'êtes pas un robot !",
|
||||||
|
"making_sure_not_bot": "Vérification que vous n'êtes pas un robot !",
|
||||||
|
"celphase": "PHASE de CEL",
|
||||||
|
"js_web_crypto_error": "Votre navigateur n'a pas d'élément web.crypto fonctionnel. Consultez-vous cette page dans un contexte sécurisé ?",
|
||||||
|
"js_web_workers_error": "Votre navigateur ne prend pas en charge les web workers (Anubis les utilise pour éviter de bloquer votre navigateur). Avez-vous un plugin comme JShelter installé ?",
|
||||||
|
"js_cookies_error": "Votre navigateur ne stocke pas les cookies. Anubis utilise des cookies pour déterminer quels clients ont réussi les défis en stockant un jeton signé dans un cookie. Veuillez activer le stockage des cookies pour ce domaine. Les noms des cookies qu'Anubis stocke peuvent varier sans préavis. Les noms et valeurs des cookies ne font pas partie de l'API publique.",
|
||||||
|
"js_context_not_secure": "Votre contexte n'est pas sécurisé !",
|
||||||
|
"js_context_not_secure_msg": "Essayez de vous connecter via HTTPS ou informez l'administrateur de configurer HTTPS. Pour plus d'informations, voir <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a>.",
|
||||||
|
"js_calculating": "Calcul en cours...",
|
||||||
|
"js_missing_feature": "Fonctionnalité manquante",
|
||||||
|
"js_challenge_error": "Erreur de défi !",
|
||||||
|
"js_challenge_error_msg": "Échec de la résolution de l'algorithme de vérification. Vous pouvez essayer de recharger la page.",
|
||||||
|
"js_calculating_difficulty": "Calcul en cours...<br/>Difficulté :",
|
||||||
|
"js_speed": "Vitesse :",
|
||||||
|
"js_verification_longer": "La vérification prend plus de temps que prévu. Veuillez ne pas actualiser la page.",
|
||||||
|
"js_success": "Succès !",
|
||||||
|
"js_done_took": "Terminé ! A pris",
|
||||||
|
"js_iterations": "itérations",
|
||||||
|
"js_finished_reading": "J'ai fini de lire, continuer →",
|
||||||
|
"js_calculation_error": "Erreur de calcul !",
|
||||||
|
"js_calculation_error_msg": "Échec du calcul du défi :"
|
||||||
|
}
|
3
lib/localization/locales/manifest.json
Normal file
3
lib/localization/locales/manifest.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"supportedLanguages": ["en", "fr", "es"]
|
||||||
|
}
|
100
lib/localization/localization.go
Normal file
100
lib/localization/localization.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package localization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed locales/*.json
|
||||||
|
var localeFS embed.FS
|
||||||
|
|
||||||
|
type LocalizationService struct {
|
||||||
|
bundle *i18n.Bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalService *LocalizationService
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLocalizationService() *LocalizationService {
|
||||||
|
once.Do(func() {
|
||||||
|
bundle := i18n.NewBundle(language.English)
|
||||||
|
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
|
||||||
|
|
||||||
|
// Read all JSON files from the locales directory
|
||||||
|
entries, err := localeFS.ReadDir("locales")
|
||||||
|
if err != nil {
|
||||||
|
// Try fallback - create a minimal service with default messages
|
||||||
|
globalService = &LocalizationService{bundle: bundle}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedAny := false
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".json") {
|
||||||
|
filePath := "locales/" + entry.Name()
|
||||||
|
_, err := bundle.LoadMessageFileFS(localeFS, filePath)
|
||||||
|
if err != nil {
|
||||||
|
// Log error but continue with other files
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
loadedAny = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !loadedAny {
|
||||||
|
// If no files were loaded successfully, create minimal service
|
||||||
|
globalService = &LocalizationService{bundle: bundle}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
globalService = &LocalizationService{bundle: bundle}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Safety check - if globalService is still nil, create a minimal one
|
||||||
|
if globalService == nil {
|
||||||
|
bundle := i18n.NewBundle(language.English)
|
||||||
|
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
|
||||||
|
globalService = &LocalizationService{bundle: bundle}
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LocalizationService) GetLocalizer(lang string) *i18n.Localizer {
|
||||||
|
return i18n.NewLocalizer(ls.bundle, lang)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LocalizationService) GetLocalizerFromRequest(r *http.Request) *i18n.Localizer {
|
||||||
|
if ls == nil || ls.bundle == nil {
|
||||||
|
// Fallback to a basic bundle if service is not properly initialized
|
||||||
|
bundle := i18n.NewBundle(language.English)
|
||||||
|
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
|
||||||
|
return i18n.NewLocalizer(bundle, "en")
|
||||||
|
}
|
||||||
|
acceptLanguage := r.Header.Get("Accept-Language")
|
||||||
|
return i18n.NewLocalizer(ls.bundle, acceptLanguage, "en")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleLocalizer wraps i18n.Localizer with a more convenient API
|
||||||
|
type SimpleLocalizer struct {
|
||||||
|
Localizer *i18n.Localizer
|
||||||
|
}
|
||||||
|
|
||||||
|
// T provides a concise way to localize messages
|
||||||
|
func (sl *SimpleLocalizer) T(messageID string) string {
|
||||||
|
return sl.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLocalizer creates a localizer based on the request's Accept-Language header
|
||||||
|
func GetLocalizer(r *http.Request) *SimpleLocalizer {
|
||||||
|
localizer := NewLocalizationService().GetLocalizerFromRequest(r)
|
||||||
|
return &SimpleLocalizer{Localizer: localizer}
|
||||||
|
}
|
116
lib/localization/localization_test.go
Normal file
116
lib/localization/localization_test.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package localization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocalizationService(t *testing.T) {
|
||||||
|
service := NewLocalizationService()
|
||||||
|
|
||||||
|
t.Run("English localization", func(t *testing.T) {
|
||||||
|
localizer := service.GetLocalizer("en")
|
||||||
|
result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "loading"})
|
||||||
|
if result != "Loading..." {
|
||||||
|
t.Errorf("Expected 'Loading...', got '%s'", result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("French localization", func(t *testing.T) {
|
||||||
|
localizer := service.GetLocalizer("fr")
|
||||||
|
result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "loading"})
|
||||||
|
if result != "Chargement..." {
|
||||||
|
t.Errorf("Expected 'Chargement...', got '%s'", result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("All required keys exist in English", func(t *testing.T) {
|
||||||
|
localizer := service.GetLocalizer("en")
|
||||||
|
requiredKeys := []string{
|
||||||
|
"loading", "why_am_i_seeing", "protected_by", "made_with",
|
||||||
|
"mascot_design", "try_again", "go_home", "javascript_required",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range requiredKeys {
|
||||||
|
result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: key})
|
||||||
|
if result == "" {
|
||||||
|
t.Errorf("Key '%s' returned empty string", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("All required keys exist in French", func(t *testing.T) {
|
||||||
|
localizer := service.GetLocalizer("fr")
|
||||||
|
requiredKeys := []string{
|
||||||
|
"loading", "why_am_i_seeing", "protected_by", "made_with",
|
||||||
|
"mascot_design", "try_again", "go_home", "javascript_required",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range requiredKeys {
|
||||||
|
result := localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: key})
|
||||||
|
if result == "" {
|
||||||
|
t.Errorf("Key '%s' returned empty string", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type manifest struct {
|
||||||
|
SupportedLanguages []string `json:"supported_languages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadManifest(t *testing.T) manifest {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
fin, err := localeFS.Open("locales/manifest.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer fin.Close()
|
||||||
|
|
||||||
|
var result manifest
|
||||||
|
if err := json.NewDecoder(fin).Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComprehensiveTranslations(t *testing.T) {
|
||||||
|
service := NewLocalizationService()
|
||||||
|
|
||||||
|
var translations = map[string]any{}
|
||||||
|
fin, err := localeFS.Open("locales/en.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer fin.Close()
|
||||||
|
|
||||||
|
if err := json.NewDecoder(fin).Decode(&translations); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range translations {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, lang := range loadManifest(t).SupportedLanguages {
|
||||||
|
t.Run(lang, func(t *testing.T) {
|
||||||
|
loc := service.GetLocalizer(lang)
|
||||||
|
sl := SimpleLocalizer{Localizer: loc}
|
||||||
|
for _, key := range keys {
|
||||||
|
t.Run(key, func(t *testing.T) {
|
||||||
|
if result := sl.T(key); result == "" {
|
||||||
|
t.Error("key not defined")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -32,9 +32,13 @@ THE SOFTWARE.
|
|||||||
for the JavaScript code in this page.
|
for the JavaScript code in this page.
|
||||||
*/'
|
*/'
|
||||||
|
|
||||||
|
# Copy localization files to static directory
|
||||||
|
mkdir -p static/locales
|
||||||
|
cp ../lib/localization/locales/*.json static/locales/
|
||||||
|
|
||||||
esbuild js/main.mjs --sourcemap --bundle --minify --outfile=static/js/main.mjs "--banner:js=${LICENSE}"
|
esbuild js/main.mjs --sourcemap --bundle --minify --outfile=static/js/main.mjs "--banner:js=${LICENSE}"
|
||||||
gzip -f -k -n static/js/main.mjs
|
gzip -f -k -n static/js/main.mjs
|
||||||
zstd -f -k --ultra -22 static/js/main.mjs
|
zstd -f -k --ultra -22 static/js/main.mjs
|
||||||
brotli -fZk static/js/main.mjs
|
brotli -fZk static/js/main.mjs
|
||||||
|
|
||||||
esbuild js/bench.mjs --sourcemap --bundle --minify --outfile=static/js/bench.mjs
|
esbuild js/bench.mjs --sourcemap --bundle --minify --outfile=static/js/bench.mjs
|
||||||
|
21
web/index.go
21
web/index.go
@ -3,31 +3,32 @@ package web
|
|||||||
import (
|
import (
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
|
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Base(title string, body templ.Component, impressum *config.Impressum) templ.Component {
|
func Base(title string, body templ.Component, impressum *config.Impressum, localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return base(title, body, impressum, nil, nil)
|
return base(title, body, impressum, nil, nil, localizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BaseWithChallengeAndOGTags(title string, body templ.Component, impressum *config.Impressum, challenge string, rules *config.ChallengeRules, ogTags map[string]string) (templ.Component, error) {
|
func BaseWithChallengeAndOGTags(title string, body templ.Component, impressum *config.Impressum, challenge string, rules *config.ChallengeRules, ogTags map[string]string, localizer *localization.SimpleLocalizer) (templ.Component, error) {
|
||||||
return base(title, body, impressum, struct {
|
return base(title, body, impressum, struct {
|
||||||
Rules *config.ChallengeRules `json:"rules"`
|
Rules *config.ChallengeRules `json:"rules"`
|
||||||
Challenge string `json:"challenge"`
|
Challenge string `json:"challenge"`
|
||||||
}{
|
}{
|
||||||
Challenge: challenge,
|
Challenge: challenge,
|
||||||
Rules: rules,
|
Rules: rules,
|
||||||
}, ogTags), nil
|
}, ogTags, localizer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Index() templ.Component {
|
func Index(localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return index()
|
return index(localizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorPage(msg string, mail string) templ.Component {
|
func ErrorPage(msg string, mail string, localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return errorPage(msg, mail)
|
return errorPage(msg, mail, localizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Bench() templ.Component {
|
func Bench(localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return bench()
|
return bench(localizer)
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@ package web
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
"github.com/TecharoHQ/anubis/xess"
|
"github.com/TecharoHQ/anubis/xess"
|
||||||
)
|
)
|
||||||
|
|
||||||
templ base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string) {
|
templ base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) {
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@ -71,14 +72,16 @@ templ base(title string, body templ.Component, impressum *config.Impressum, chal
|
|||||||
<footer>
|
<footer>
|
||||||
<center>
|
<center>
|
||||||
<p>
|
<p>
|
||||||
Protected by <a href="https://github.com/TecharoHQ/anubis">Anubis</a> from <a
|
{ localizer.T("protected_by") } <a href="https://github.com/TecharoHQ/anubis">Anubis</a> from <a
|
||||||
href="https://techaro.lol"
|
href="https://techaro.lol"
|
||||||
>Techaro</a>. Made with ❤️ in 🇨🇦.
|
>Techaro</a>. { localizer.T("made_with") }.
|
||||||
</p>
|
</p>
|
||||||
<p>Mascot design by <a href="https://bsky.app/profile/celphase.bsky.social">CELPHASE</a>.</p>
|
<p>{ localizer.T("mascot_design") } <a href="https://bsky.app/profile/celphase.bsky.social">{ localizer.T("celphase") }</a>.</p>
|
||||||
if impressum != nil {
|
if impressum != nil {
|
||||||
<p>@templ.Raw(impressum.Footer)
|
<p>
|
||||||
-- <a href={ templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a></p>
|
@templ.Raw(impressum.Footer)
|
||||||
|
-- <a href={ templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a>
|
||||||
|
</p>
|
||||||
}
|
}
|
||||||
</center>
|
</center>
|
||||||
</footer>
|
</footer>
|
||||||
@ -87,79 +90,59 @@ templ base(title string, body templ.Component, impressum *config.Impressum, chal
|
|||||||
</html>
|
</html>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ index() {
|
templ index(localizer *localization.SimpleLocalizer) {
|
||||||
<div class="centered-div">
|
<div class="centered-div">
|
||||||
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<img style="display:none;" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version }/>
|
<img style="display:none;" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<p id="status">Loading...</p>
|
<p id="status">{ localizer.T("loading") }</p>
|
||||||
<script async type="module" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version }></script>
|
<script async type="module" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version }></script>
|
||||||
<div id="progress" role="progressbar" aria-labelledby="status">
|
<div id="progress" role="progressbar" aria-labelledby="status">
|
||||||
<div class="bar-inner"></div>
|
<div class="bar-inner"></div>
|
||||||
</div>
|
</div>
|
||||||
<details>
|
<details>
|
||||||
<summary>Why am I seeing this?</summary>
|
<summary>{ localizer.T("why_am_i_seeing") }</summary>
|
||||||
<p>
|
<p>
|
||||||
You are seeing this because the administrator of this website has set up <a
|
{ localizer.T("ai_companies_explanation") }
|
||||||
href="https://github.com/TecharoHQ/anubis"
|
|
||||||
>Anubis</a> to protect the server against the scourge of
|
|
||||||
<a href="https://thelibre.news/foss-infrastructure-is-under-attack-by-ai-companies/">
|
|
||||||
AI companies
|
|
||||||
aggressively scraping websites
|
|
||||||
</a>. This can and does cause downtime for the websites, which makes their
|
|
||||||
resources inaccessible for everyone.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Anubis is a compromise. Anubis uses a <a
|
{ localizer.T("anubis_compromise") }
|
||||||
href="https://anubis.techaro.lol/docs/design/why-proof-of-work"
|
|
||||||
>Proof-of-Work</a>
|
|
||||||
scheme in the vein of <a href="https://en.wikipedia.org/wiki/Hashcash">Hashcash</a>, a proposed
|
|
||||||
proof-of-work scheme for reducing email spam. The idea is that at individual scales the additional load is
|
|
||||||
ignorable, but at mass scraper levels it adds up and makes scraping much more expensive.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Ultimately, this is a hack whose real purpose is to give a "good enough" placeholder solution so that more
|
{ localizer.T("hack_purpose") }
|
||||||
time can be spent on fingerprinting and identifying headless browsers (EG: via how they do font rendering)
|
|
||||||
so that the challenge proof of work page doesn't need to be presented to users that are much more likely to
|
|
||||||
be legitimate.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Please note that Anubis requires the use of modern JavaScript features that plugins like <a
|
{ localizer.T("jshelter_note") }
|
||||||
href="https://jshelter.org/"
|
|
||||||
>JShelter</a> will disable. Please disable JShelter or other such
|
|
||||||
plugins for this domain.
|
|
||||||
</p>
|
</p>
|
||||||
<p>This website is running Anubis version <code>{ anubis.Version }</code>.</p>
|
<p>{ localizer.T("version_info") } <code>{ anubis.Version }</code>.</p>
|
||||||
</details>
|
</details>
|
||||||
<noscript>
|
<noscript>
|
||||||
<p>
|
<p>
|
||||||
Sadly, you must enable JavaScript to get past this challenge. This is required because AI companies have
|
{ localizer.T("javascript_required") }
|
||||||
changed
|
|
||||||
the social contract around how website hosting works. A no-JS solution is a work-in-progress.
|
|
||||||
</p>
|
</p>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="testarea"></div>
|
<div id="testarea"></div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ errorPage(message string, mail string) {
|
templ errorPage(message string, mail string, localizer *localization.SimpleLocalizer) {
|
||||||
<div class="centered-div">
|
<div class="centered-div">
|
||||||
<img id="image" alt="Sad Anubis" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version }/>
|
<img id="image" alt="Sad Anubis" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<p>{ message }.</p>
|
<p>{ message }.</p>
|
||||||
<button onClick="window.location.reload();">Try again</button>
|
<button onClick="window.location.reload();">{ localizer.T("try_again") }</button>
|
||||||
if mail != "" {
|
if mail != "" {
|
||||||
<p>
|
<p>
|
||||||
<a href="/">Go home</a> or if you believe you should not be blocked, please contact the webmaster at
|
<a href="/">{ localizer.T("go_home") }</a> { localizer.T("contact_webmaster") }
|
||||||
<a href={ "mailto:" + templ.SafeURL(mail) }>
|
<a href={ "mailto:" + templ.SafeURL(mail) }>
|
||||||
{ mail }
|
{ mail }
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
} else {
|
} else {
|
||||||
<p><a href="/">Go home</a></p>
|
<p><a href="/">{ localizer.T("go_home") }</a></p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ StaticHappy() {
|
templ StaticHappy(localizer *localization.SimpleLocalizer) {
|
||||||
<div class="centered-div">
|
<div class="centered-div">
|
||||||
<img
|
<img
|
||||||
style="display:none;"
|
style="display:none;"
|
||||||
@ -167,25 +150,25 @@ templ StaticHappy() {
|
|||||||
src={ "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
|
src={ "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
|
||||||
anubis.Version }
|
anubis.Version }
|
||||||
/>
|
/>
|
||||||
<p>This is just a check endpoint for your reverse proxy to use.</p>
|
<p>{ localizer.T("static_check_endpoint") }</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ bench() {
|
templ bench(localizer *localization.SimpleLocalizer) {
|
||||||
<div style="height:20rem;display:flex">
|
<div style="height:20rem;display:flex">
|
||||||
<table style="margin-top:1rem;display:grid;grid-template:auto 1fr/auto auto;gap:0 0.5rem">
|
<table style="margin-top:1rem;display:grid;grid-template:auto 1fr/auto auto;gap:0 0.5rem">
|
||||||
<thead
|
<thead
|
||||||
style="border-bottom:1px solid black;padding:0.25rem 0;display:grid;grid-template:1fr/subgrid;grid-column:1/-1"
|
style="border-bottom:1px solid black;padding:0.25rem 0;display:grid;grid-template:1fr/subgrid;grid-column:1/-1"
|
||||||
>
|
>
|
||||||
<tr id="table-header" style="display:contents">
|
<tr id="table-header" style="display:contents">
|
||||||
<th style="width:4.5rem">Time</th>
|
<th style="width:4.5rem">{ localizer.T("time") }</th>
|
||||||
<th style="width:4rem">Iters</th>
|
<th style="width:4rem">{ localizer.T("iters") }</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="table-header-compare" style="display:none">
|
<tr id="table-header-compare" style="display:none">
|
||||||
<th style="width:4.5rem">Time A</th>
|
<th style="width:4.5rem">{ localizer.T("time_a") }</th>
|
||||||
<th style="width:4rem">Iters A</th>
|
<th style="width:4rem">{ localizer.T("iters_a") }</th>
|
||||||
<th style="width:4.5rem">Time B</th>
|
<th style="width:4.5rem">{ localizer.T("time_b") }</th>
|
||||||
<th style="width:4rem">Iters B</th>
|
<th style="width:4rem">{ localizer.T("iters_b") }</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody
|
<tbody
|
||||||
@ -195,25 +178,25 @@ templ bench() {
|
|||||||
</table>
|
</table>
|
||||||
<div class="centered-div">
|
<div class="centered-div">
|
||||||
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
<img id="image" style="width:100%;max-width:256px;" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
|
||||||
<p id="status" style="max-width:256px">Loading...</p>
|
<p id="status" style="max-width:256px">{ localizer.T("loading") }</p>
|
||||||
<script async type="module" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/bench.mjs?cacheBuster=" + anubis.Version }></script>
|
<script async type="module" src={ anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/bench.mjs?cacheBuster=" + anubis.Version }></script>
|
||||||
<div id="sparkline"></div>
|
<div id="sparkline"></div>
|
||||||
<noscript>
|
<noscript>
|
||||||
<p>Running the benchmark tool requires JavaScript to be enabled.</p>
|
<p>{ localizer.T("benchmark_requires_js") }</p>
|
||||||
</noscript>
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="controls" style="position:fixed;top:0.5rem;right:0.5rem">
|
<form id="controls" style="position:fixed;top:0.5rem;right:0.5rem">
|
||||||
<div style="display:flex;justify-content:end">
|
<div style="display:flex;justify-content:end">
|
||||||
<label for="difficulty-input" style="margin-right:0.5rem">Difficulty:</label>
|
<label for="difficulty-input" style="margin-right:0.5rem">{ localizer.T("difficulty") }</label>
|
||||||
<input id="difficulty-input" type="number" name="difficulty" style="width:3rem"/>
|
<input id="difficulty-input" type="number" name="difficulty" style="width:3rem"/>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:0.25rem;display:flex;justify-content:end">
|
<div style="margin-top:0.25rem;display:flex;justify-content:end">
|
||||||
<label for="algorithm-select" style="margin-right:0.5rem">Algorithm:</label>
|
<label for="algorithm-select" style="margin-right:0.5rem">{ localizer.T("algorithm") }</label>
|
||||||
<select id="algorithm-select" name="algorithm"></select>
|
<select id="algorithm-select" name="algorithm"></select>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:0.25rem;display:flex;justify-content:end">
|
<div style="margin-top:0.25rem;display:flex;justify-content:end">
|
||||||
<label for="compare-select" style="margin-right:0.5rem">Compare:</label>
|
<label for="compare-select" style="margin-right:0.5rem">{ localizer.T("compare") }</label>
|
||||||
<select id="compare-select" name="compare">
|
<select id="compare-select" name="compare">
|
||||||
<option value="NONE">-</option>
|
<option value="NONE">-</option>
|
||||||
</select>
|
</select>
|
||||||
|
721
web/index_templ.go
generated
721
web/index_templ.go
generated
@ -11,11 +11,12 @@ import templruntime "github.com/a-h/templ/runtime"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TecharoHQ/anubis"
|
"github.com/TecharoHQ/anubis"
|
||||||
|
"github.com/TecharoHQ/anubis/lib/localization"
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||||
"github.com/TecharoHQ/anubis/xess"
|
"github.com/TecharoHQ/anubis/xess"
|
||||||
)
|
)
|
||||||
|
|
||||||
func base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string) templ.Component {
|
func base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -43,7 +44,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
var templ_7745c5c3_Var2 string
|
var templ_7745c5c3_Var2 string
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 14, Col: 17}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 15, Col: 17}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -56,7 +57,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
var templ_7745c5c3_Var3 string
|
var templ_7745c5c3_Var3 string
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + xess.URL)
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + xess.URL)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 15, Col: 61}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 16, Col: 61}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -74,7 +75,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
var templ_7745c5c3_Var4 string
|
var templ_7745c5c3_Var4 string
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(key)
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(key)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 19, Col: 24}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 20, Col: 24}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -87,7 +88,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
var templ_7745c5c3_Var5 string
|
var templ_7745c5c3_Var5 string
|
||||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(value)
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(value)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 19, Col: 42}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 20, Col: 42}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -123,7 +124,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
var templ_7745c5c3_Var6 string
|
var templ_7745c5c3_Var6 string
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 68, Col: 49}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 69, Col: 49}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@ -137,12 +138,64 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<footer><center><p>Protected by <a href=\"https://github.com/TecharoHQ/anubis\">Anubis</a> from <a href=\"https://techaro.lol\">Techaro</a>. Made with ❤️ in 🇨🇦.</p><p>Mascot design by <a href=\"https://bsky.app/profile/celphase.bsky.social\">CELPHASE</a>.</p>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<footer><center><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("protected_by"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 75, Col: 36}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " <a href=\"https://github.com/TecharoHQ/anubis\">Anubis</a> from <a href=\"https://techaro.lol\">Techaro</a>. ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("made_with"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 77, Col: 40}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, ".</p><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("mascot_design"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 39}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " <a href=\"https://bsky.app/profile/celphase.bsky.social\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var10 string
|
||||||
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("celphase"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 123}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a>.</p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if impressum != nil {
|
if impressum != nil {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<p>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -150,25 +203,25 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "-- <a href=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "-- <a href=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var7 templ.SafeURL
|
var templ_7745c5c3_Var11 templ.SafeURL
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix)))
|
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("%simprint", anubis.APIPrefix)))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 81, Col: 70}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 78}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">Imprint</a></p>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">Imprint</a></p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</center></footer></main></body></html>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</center></footer></main></body></html>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -176,7 +229,7 @@ func base(title string, body templ.Component, impressum *config.Impressum, chall
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func index() templ.Component {
|
func index(localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -192,203 +245,168 @@ func index() templ.Component {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
|
templ_7745c5c3_Var12 := templ.GetChildren(ctx)
|
||||||
if templ_7745c5c3_Var8 == nil {
|
if templ_7745c5c3_Var12 == nil {
|
||||||
templ_7745c5c3_Var8 = templ.NopComponent
|
templ_7745c5c3_Var12 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<div class=\"centered-div\"><img id=\"image\" style=\"width:100%;max-width:256px;\" src=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div class=\"centered-div\"><img id=\"image\" style=\"width:100%;max-width:256px;\" src=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var9 string
|
var templ_7745c5c3_Var13 string
|
||||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 92, Col: 165}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 95, Col: 165}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\"> <img style=\"display:none;\" style=\"width:100%;max-width:256px;\" src=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\"> <img style=\"display:none;\" style=\"width:100%;max-width:256px;\" src=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var10 string
|
|
||||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 93, Col: 174}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\"><p id=\"status\">Loading...</p><script async type=\"module\" src=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var11 string
|
|
||||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 95, Col: 136}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\"></script><div id=\"progress\" role=\"progressbar\" aria-labelledby=\"status\"><div class=\"bar-inner\"></div></div><details><summary>Why am I seeing this?</summary><p>You are seeing this because the administrator of this website has set up <a href=\"https://github.com/TecharoHQ/anubis\">Anubis</a> to protect the server against the scourge of <a href=\"https://thelibre.news/foss-infrastructure-is-under-attack-by-ai-companies/\">AI companies aggressively scraping websites</a>. This can and does cause downtime for the websites, which makes their resources inaccessible for everyone.</p><p>Anubis is a compromise. Anubis uses a <a href=\"https://anubis.techaro.lol/docs/design/why-proof-of-work\">Proof-of-Work</a> scheme in the vein of <a href=\"https://en.wikipedia.org/wiki/Hashcash\">Hashcash</a>, a proposed proof-of-work scheme for reducing email spam. The idea is that at individual scales the additional load is ignorable, but at mass scraper levels it adds up and makes scraping much more expensive.</p><p>Ultimately, this is a hack whose real purpose is to give a \"good enough\" placeholder solution so that more time can be spent on fingerprinting and identifying headless browsers (EG: via how they do font rendering) so that the challenge proof of work page doesn't need to be presented to users that are much more likely to be legitimate.</p><p>Please note that Anubis requires the use of modern JavaScript features that plugins like <a href=\"https://jshelter.org/\">JShelter</a> will disable. Please disable JShelter or other such plugins for this domain.</p><p>This website is running Anubis version <code>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var12 string
|
|
||||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.Version)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 131, Col: 67}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</code>.</p></details><noscript><p>Sadly, you must enable JavaScript to get past this challenge. This is required because AI companies have changed the social contract around how website hosting works. A no-JS solution is a work-in-progress.</p></noscript><div id=\"testarea\"></div></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorPage(message string, mail string) templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
||||||
if !templ_7745c5c3_IsBuffer {
|
|
||||||
defer func() {
|
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
ctx = templ.InitializeContext(ctx)
|
|
||||||
templ_7745c5c3_Var13 := templ.GetChildren(ctx)
|
|
||||||
if templ_7745c5c3_Var13 == nil {
|
|
||||||
templ_7745c5c3_Var13 = templ.NopComponent
|
|
||||||
}
|
|
||||||
ctx = templ.ClearChildren(ctx)
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div class=\"centered-div\"><img id=\"image\" alt=\"Sad Anubis\" style=\"width:100%;max-width:256px;\" src=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var14 string
|
var templ_7745c5c3_Var14 string
|
||||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 146, Col: 181}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 96, Col: 174}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\"><p>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\"><p id=\"status\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var15 string
|
var templ_7745c5c3_Var15 string
|
||||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(message)
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("loading"))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 147, Col: 14}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 97, Col: 41}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, ".</p><button onClick=\"window.location.reload();\">Try again</button> ")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</p><script async type=\"module\" src=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if mail != "" {
|
var templ_7745c5c3_Var16 string
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<p><a href=\"/\">Go home</a> or if you believe you should not be blocked, please contact the webmaster at <a href=\"")
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 98, Col: 136}
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var16 templ.SafeURL
|
|
||||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs("mailto:" + templ.SafeURL(mail))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 152, Col: 45}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\">")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var17 string
|
|
||||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(mail)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 153, Col: 11}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</a></p>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<p><a href=\"/\">Go home</a></p>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</div>")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
return nil
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\"></script><div id=\"progress\" role=\"progressbar\" aria-labelledby=\"status\"><div class=\"bar-inner\"></div></div><details><summary>")
|
||||||
})
|
if templ_7745c5c3_Err != nil {
|
||||||
}
|
return templ_7745c5c3_Err
|
||||||
|
|
||||||
func StaticHappy() templ.Component {
|
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
||||||
return templ_7745c5c3_CtxErr
|
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
var templ_7745c5c3_Var17 string
|
||||||
if !templ_7745c5c3_IsBuffer {
|
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("why_am_i_seeing"))
|
||||||
defer func() {
|
if templ_7745c5c3_Err != nil {
|
||||||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 103, Col: 44}
|
||||||
if templ_7745c5c3_Err == nil {
|
|
||||||
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||||
templ_7745c5c3_Var18 := templ.GetChildren(ctx)
|
if templ_7745c5c3_Err != nil {
|
||||||
if templ_7745c5c3_Var18 == nil {
|
return templ_7745c5c3_Err
|
||||||
templ_7745c5c3_Var18 = templ.NopComponent
|
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</summary><p>")
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<div class=\"centered-div\"><img style=\"display:none;\" style=\"width:100%;max-width:256px;\" src=\"")
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("ai_companies_explanation"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 105, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</p><p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var19 string
|
var templ_7745c5c3_Var19 string
|
||||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("anubis_compromise"))
|
||||||
anubis.Version)
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 168, Col: 18}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 108, Col: 38}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\"><p>This is just a check endpoint for your reverse proxy to use.</p></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</p><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var20 string
|
||||||
|
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("hack_purpose"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 111, Col: 33}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</p><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var21 string
|
||||||
|
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("jshelter_note"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 114, Col: 34}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</p><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var22 string
|
||||||
|
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("version_info"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 116, Col: 35}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " <code>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var23 string
|
||||||
|
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.Version)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 116, Col: 60}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</code>.</p></details><noscript><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var24 string
|
||||||
|
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("javascript_required"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 120, Col: 40}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</p></noscript><div id=\"testarea\"></div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -396,7 +414,7 @@ func StaticHappy() templ.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func bench() templ.Component {
|
func errorPage(message string, mail string, localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -412,38 +430,385 @@ func bench() templ.Component {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
templ_7745c5c3_Var20 := templ.GetChildren(ctx)
|
templ_7745c5c3_Var25 := templ.GetChildren(ctx)
|
||||||
if templ_7745c5c3_Var20 == nil {
|
if templ_7745c5c3_Var25 == nil {
|
||||||
templ_7745c5c3_Var20 = templ.NopComponent
|
templ_7745c5c3_Var25 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<div style=\"height:20rem;display:flex\"><table style=\"margin-top:1rem;display:grid;grid-template:auto 1fr/auto auto;gap:0 0.5rem\"><thead style=\"border-bottom:1px solid black;padding:0.25rem 0;display:grid;grid-template:1fr/subgrid;grid-column:1/-1\"><tr id=\"table-header\" style=\"display:contents\"><th style=\"width:4.5rem\">Time</th><th style=\"width:4rem\">Iters</th></tr><tr id=\"table-header-compare\" style=\"display:none\"><th style=\"width:4.5rem\">Time A</th><th style=\"width:4rem\">Iters A</th><th style=\"width:4.5rem\">Time B</th><th style=\"width:4rem\">Iters B</th></tr></thead> <tbody id=\"results\" style=\"padding-top:0.25rem;display:grid;grid-template-columns:subgrid;grid-auto-rows:min-content;grid-column:1/-1;row-gap:0.25rem;overflow-y:auto;font-variant-numeric:tabular-nums\"></tbody></table><div class=\"centered-div\"><img id=\"image\" style=\"width:100%;max-width:256px;\" src=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<div class=\"centered-div\"><img id=\"image\" alt=\"Sad Anubis\" style=\"width:100%;max-width:256px;\" src=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var21 string
|
var templ_7745c5c3_Var26 string
|
||||||
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 197, Col: 166}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 129, Col: 181}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\"><p id=\"status\" style=\"max-width:256px\">Loading...</p><script async type=\"module\" src=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "\"><p>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var22 string
|
var templ_7745c5c3_Var27 string
|
||||||
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/bench.mjs?cacheBuster=" + anubis.Version)
|
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(message)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 199, Col: 138}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 130, Col: 14}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\"></script><div id=\"sparkline\"></div><noscript><p>Running the benchmark tool requires JavaScript to be enabled.</p></noscript></div></div><form id=\"controls\" style=\"position:fixed;top:0.5rem;right:0.5rem\"><div style=\"display:flex;justify-content:end\"><label for=\"difficulty-input\" style=\"margin-right:0.5rem\">Difficulty:</label> <input id=\"difficulty-input\" type=\"number\" name=\"difficulty\" style=\"width:3rem\"></div><div style=\"margin-top:0.25rem;display:flex;justify-content:end\"><label for=\"algorithm-select\" style=\"margin-right:0.5rem\">Algorithm:</label> <select id=\"algorithm-select\" name=\"algorithm\"></select></div><div style=\"margin-top:0.25rem;display:flex;justify-content:end\"><label for=\"compare-select\" style=\"margin-right:0.5rem\">Compare:</label> <select id=\"compare-select\" name=\"compare\"><option value=\"NONE\">-</option></select></div></form>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, ".</p><button onClick=\"window.location.reload();\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var28 string
|
||||||
|
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("try_again"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 131, Col: 72}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</button> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if mail != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "<p><a href=\"/\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var29 string
|
||||||
|
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("go_home"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 134, Col: 40}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</a> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var30 string
|
||||||
|
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("contact_webmaster"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 134, Col: 81}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, " <a href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var31 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinURLErrs("mailto:" + templ.SafeURL(mail))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 135, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var32 string
|
||||||
|
templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(mail)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 136, Col: 11}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</a></p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<p><a href=\"/\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var33 string
|
||||||
|
templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("go_home"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 140, Col: 42}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "</a></p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func StaticHappy(localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var34 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var34 == nil {
|
||||||
|
templ_7745c5c3_Var34 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "<div class=\"centered-div\"><img style=\"display:none;\" style=\"width:100%;max-width:256px;\" src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var35 string
|
||||||
|
templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs("/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
|
||||||
|
anubis.Version)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 151, Col: 18}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\"><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var36 string
|
||||||
|
templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("static_check_endpoint"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 153, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "</p></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func bench(localizer *localization.SimpleLocalizer) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var37 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var37 == nil {
|
||||||
|
templ_7745c5c3_Var37 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "<div style=\"height:20rem;display:flex\"><table style=\"margin-top:1rem;display:grid;grid-template:auto 1fr/auto auto;gap:0 0.5rem\"><thead style=\"border-bottom:1px solid black;padding:0.25rem 0;display:grid;grid-template:1fr/subgrid;grid-column:1/-1\"><tr id=\"table-header\" style=\"display:contents\"><th style=\"width:4.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var38 string
|
||||||
|
templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 164, Col: 51}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "</th><th style=\"width:4rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var39 string
|
||||||
|
templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 165, Col: 50}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</th></tr><tr id=\"table-header-compare\" style=\"display:none\"><th style=\"width:4.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var40 string
|
||||||
|
templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time_a"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 168, Col: 53}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</th><th style=\"width:4rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var41 string
|
||||||
|
templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters_a"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 169, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</th><th style=\"width:4.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var42 string
|
||||||
|
templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("time_b"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 170, Col: 53}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</th><th style=\"width:4rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var43 string
|
||||||
|
templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("iters_b"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 171, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</th></tr></thead> <tbody id=\"results\" style=\"padding-top:0.25rem;display:grid;grid-template-columns:subgrid;grid-auto-rows:min-content;grid-column:1/-1;row-gap:0.25rem;overflow-y:auto;font-variant-numeric:tabular-nums\"></tbody></table><div class=\"centered-div\"><img id=\"image\" style=\"width:100%;max-width:256px;\" src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var44 string
|
||||||
|
templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 180, Col: 166}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\"><p id=\"status\" style=\"max-width:256px\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var45 string
|
||||||
|
templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("loading"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 181, Col: 66}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "</p><script async type=\"module\" src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var46 string
|
||||||
|
templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/js/bench.mjs?cacheBuster=" + anubis.Version)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 182, Col: 138}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\"></script><div id=\"sparkline\"></div><noscript><p>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var47 string
|
||||||
|
templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("benchmark_requires_js"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 185, Col: 45}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "</p></noscript></div></div><form id=\"controls\" style=\"position:fixed;top:0.5rem;right:0.5rem\"><div style=\"display:flex;justify-content:end\"><label for=\"difficulty-input\" style=\"margin-right:0.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var48 string
|
||||||
|
templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("difficulty"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 191, Col: 88}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "</label> <input id=\"difficulty-input\" type=\"number\" name=\"difficulty\" style=\"width:3rem\"></div><div style=\"margin-top:0.25rem;display:flex;justify-content:end\"><label for=\"algorithm-select\" style=\"margin-right:0.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var49 string
|
||||||
|
templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("algorithm"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 195, Col: 87}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</label> <select id=\"algorithm-select\" name=\"algorithm\"></select></div><div style=\"margin-top:0.25rem;display:flex;justify-content:end\"><label for=\"compare-select\" style=\"margin-right:0.5rem\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var50 string
|
||||||
|
templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(localizer.T("compare"))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 199, Col: 83}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "</label> <select id=\"compare-select\" name=\"compare\"><option value=\"NONE\">-</option></select></div></form>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
128
web/js/main.mjs
128
web/js/main.mjs
@ -18,25 +18,87 @@ const imageURL = (mood, cacheBuster, basePrefix) =>
|
|||||||
cacheBuster,
|
cacheBuster,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dependencies = [
|
// Detect available languages by loading the manifest
|
||||||
{
|
const getAvailableLanguages = async () => {
|
||||||
name: "WebCrypto",
|
const basePrefix = JSON.parse(
|
||||||
msg: "Your browser doesn't have a functioning web.crypto element. Are you viewing this over a secure context?",
|
document.getElementById("anubis_base_prefix").textContent,
|
||||||
value: window.crypto,
|
);
|
||||||
},
|
|
||||||
{
|
try {
|
||||||
name: "Web Workers",
|
const response = await fetch(`${basePrefix}/.within.website/x/cmd/anubis/static/locales/manifest.json`);
|
||||||
msg: "Your browser doesn't support web workers (Anubis uses this to avoid freezing your browser). Do you have a plugin like JShelter installed?",
|
if (response.ok) {
|
||||||
value: window.Worker,
|
const manifest = await response.json();
|
||||||
},
|
return manifest.supportedLanguages || ['en'];
|
||||||
{
|
}
|
||||||
name: "Cookies",
|
} catch (error) {
|
||||||
msg: "Your browser doesn't store cookies. Anubis uses cookies to determine which clients have passed challenges by storing a signed token in a cookie. Please enable storing cookies for this domain. The names of the cookies Anubis stores may vary without notice. Cookie names and values are not part of the public API.",
|
console.warn('Failed to load language manifest, falling back to default languages');
|
||||||
value: navigator.cookieEnabled,
|
}
|
||||||
},
|
|
||||||
];
|
// Fallback to default languages if manifest loading fails
|
||||||
|
return ['en'];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Detect browser language
|
||||||
|
const getBrowserLanguage = async () => {
|
||||||
|
const lang = navigator.language || navigator.userLanguage;
|
||||||
|
const availableLanguages = await getAvailableLanguages();
|
||||||
|
|
||||||
|
// Extract the language code (first 2 characters)
|
||||||
|
const langCode = lang.substring(0, 2).toLowerCase();
|
||||||
|
|
||||||
|
// Return the language if supported, or use English
|
||||||
|
return availableLanguages.includes(langCode) ? langCode : 'en';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load translations from JSON files
|
||||||
|
const loadTranslations = async (lang) => {
|
||||||
|
const basePrefix = JSON.parse(
|
||||||
|
document.getElementById("anubis_base_prefix").textContent,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${basePrefix}/.within.website/x/cmd/anubis/static/locales/${lang}.json`);
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to load translations for ${lang}, falling back to English`);
|
||||||
|
if (lang !== 'en') {
|
||||||
|
return await loadTranslations('en');
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let translations = {};
|
||||||
|
let currentLang;
|
||||||
|
|
||||||
|
// Initialize translations
|
||||||
|
const initTranslations = async () => {
|
||||||
|
currentLang = await getBrowserLanguage();
|
||||||
|
translations = await loadTranslations(currentLang);
|
||||||
|
};
|
||||||
|
|
||||||
|
const t = (key) => translations[`js_${key}`] || translations[key] || key;
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
// Initialize translations first
|
||||||
|
await initTranslations();
|
||||||
|
|
||||||
|
const dependencies = [
|
||||||
|
{
|
||||||
|
name: "WebCrypto",
|
||||||
|
msg: t('web_crypto_error'),
|
||||||
|
value: window.crypto,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Web Workers",
|
||||||
|
msg: t('web_workers_error'),
|
||||||
|
value: window.Worker,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cookies",
|
||||||
|
msg: t('cookies_error'),
|
||||||
|
value: navigator.cookieEnabled,
|
||||||
|
},
|
||||||
|
];
|
||||||
const status = document.getElementById("status");
|
const status = document.getElementById("status");
|
||||||
const image = document.getElementById("image");
|
const image = document.getElementById("image");
|
||||||
const title = document.getElementById("title");
|
const title = document.getElementById("title");
|
||||||
@ -67,19 +129,19 @@ const dependencies = [
|
|||||||
|
|
||||||
if (!window.isSecureContext) {
|
if (!window.isSecureContext) {
|
||||||
ohNoes({
|
ohNoes({
|
||||||
titleMsg: "Your context is not secure!",
|
titleMsg: t('context_not_secure'),
|
||||||
statusMsg: `Try connecting over HTTPS or let the admin know to set up HTTPS. For more information, see <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure">MDN</a>.`,
|
statusMsg: t('context_not_secure_msg'),
|
||||||
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.innerHTML = "Calculating...";
|
status.innerHTML = t('calculating');
|
||||||
|
|
||||||
for (const { value, name, msg } of dependencies) {
|
for (const { value, name, msg } of dependencies) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
ohNoes({
|
ohNoes({
|
||||||
titleMsg: `Missing feature ${name}`,
|
titleMsg: `${t('missing_feature')} ${name}`,
|
||||||
statusMsg: msg,
|
statusMsg: msg,
|
||||||
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
||||||
});
|
});
|
||||||
@ -94,20 +156,20 @@ const dependencies = [
|
|||||||
const process = algorithms[rules.algorithm];
|
const process = algorithms[rules.algorithm];
|
||||||
if (!process) {
|
if (!process) {
|
||||||
ohNoes({
|
ohNoes({
|
||||||
titleMsg: "Challenge error!",
|
titleMsg: t('challenge_error'),
|
||||||
statusMsg: `Failed to resolve check algorithm. You may want to reload the page.`,
|
statusMsg: t('challenge_error_msg'),
|
||||||
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.innerHTML = `Calculating...<br/>Difficulty: ${rules.report_as}, `;
|
status.innerHTML = `${t('calculating_difficulty')} ${rules.report_as}, `;
|
||||||
progress.style.display = "inline-block";
|
progress.style.display = "inline-block";
|
||||||
|
|
||||||
// the whole text, including "Speed:", as a single node, because some browsers
|
// the whole text, including "Speed:", as a single node, because some browsers
|
||||||
// (Firefox mobile) present screen readers with each node as a separate piece
|
// (Firefox mobile) present screen readers with each node as a separate piece
|
||||||
// of text.
|
// of text.
|
||||||
const rateText = document.createTextNode("Speed: 0kH/s");
|
const rateText = document.createTextNode(`${t('speed')} 0kH/s`);
|
||||||
status.appendChild(rateText);
|
status.appendChild(rateText);
|
||||||
|
|
||||||
let lastSpeedUpdate = 0;
|
let lastSpeedUpdate = 0;
|
||||||
@ -125,7 +187,7 @@ const dependencies = [
|
|||||||
// only update the speed every second so it's less visually distracting
|
// only update the speed every second so it's less visually distracting
|
||||||
if (delta - lastSpeedUpdate > 1000) {
|
if (delta - lastSpeedUpdate > 1000) {
|
||||||
lastSpeedUpdate = delta;
|
lastSpeedUpdate = delta;
|
||||||
rateText.data = `Speed: ${(iters / delta).toFixed(3)}kH/s`;
|
rateText.data = `${t('speed')} ${(iters / delta).toFixed(3)}kH/s`;
|
||||||
}
|
}
|
||||||
// the probability of still being on the page is (1 - likelihood) ^ iters.
|
// the probability of still being on the page is (1 - likelihood) ^ iters.
|
||||||
// by definition, half of the time the progress bar only gets to half, so
|
// by definition, half of the time the progress bar only gets to half, so
|
||||||
@ -141,9 +203,7 @@ const dependencies = [
|
|||||||
if (probability < 0.1 && !showingApology) {
|
if (probability < 0.1 && !showingApology) {
|
||||||
status.append(
|
status.append(
|
||||||
document.createElement("br"),
|
document.createElement("br"),
|
||||||
document.createTextNode(
|
document.createTextNode(t('verification_longer')),
|
||||||
"Verification is taking longer than expected. Please do not refresh the page.",
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
showingApology = true;
|
showingApology = true;
|
||||||
}
|
}
|
||||||
@ -152,8 +212,8 @@ const dependencies = [
|
|||||||
const t1 = Date.now();
|
const t1 = Date.now();
|
||||||
console.log({ hash, nonce });
|
console.log({ hash, nonce });
|
||||||
|
|
||||||
title.innerHTML = "Success!";
|
title.innerHTML = t('success');
|
||||||
status.innerHTML = `Done! Took ${t1 - t0}ms, ${nonce} iterations`;
|
status.innerHTML = `${t('done_took')} ${t1 - t0}ms, ${nonce} ${t('iterations')}`;
|
||||||
image.src = imageURL("happy", anubisVersion, basePrefix);
|
image.src = imageURL("happy", anubisVersion, basePrefix);
|
||||||
progress.style.display = "none";
|
progress.style.display = "none";
|
||||||
|
|
||||||
@ -174,7 +234,7 @@ const dependencies = [
|
|||||||
container.style.outlineOffset = "2px";
|
container.style.outlineOffset = "2px";
|
||||||
container.style.width = "min(20rem, 90%)";
|
container.style.width = "min(20rem, 90%)";
|
||||||
container.style.margin = "1rem auto 2rem";
|
container.style.margin = "1rem auto 2rem";
|
||||||
container.innerHTML = "I've finished reading, continue →";
|
container.innerHTML = t('finished_reading');
|
||||||
|
|
||||||
function onDetailsExpand() {
|
function onDetailsExpand() {
|
||||||
const redir = window.location.href;
|
const redir = window.location.href;
|
||||||
@ -205,8 +265,8 @@ const dependencies = [
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ohNoes({
|
ohNoes({
|
||||||
titleMsg: "Calculation error!",
|
titleMsg: t('calculation_error'),
|
||||||
statusMsg: `Failed to calculate challenge: ${err.message}`,
|
statusMsg: `${t('calculation_error_msg')} ${err.message}`,
|
||||||
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
imageSrc: imageURL("reject", anubisVersion, basePrefix),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user