Compare commits

..

2 Commits

Author SHA1 Message Date
Xe Iaso f2c93d1105 chore: spelling
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-05-08 18:42:37 -04:00
Xe Iaso b74bc6268c fix: patch GHSA-6wcg-mqvh-fcvg
PR https://github.com/TecharoHQ/anubis/pull/1015 added the ability for
reverse proxies using Anubis in subrequest auth mode to look at the path
of a request as there are many rules in the wild that rely on checking
the path. This is how access to things like robots.txt or anything in the
.well-known directory is unaffected by Anubis.

However this logic was also enabled for non-subrequest deployments of Anubis,
meaning that a specially crafted request could include a /.well-known/
path in it and then get around Anubis with little effort.

This fix gates the logic behind a new plumbed variable named subrequestMode
that only fires when Anubis is running in subrequest auth mode. This
properly contains that workaround so that the logic does not fire in
most deployments.

Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-05-08 18:39:22 -04:00
21 changed files with 493 additions and 629 deletions
-1
View File
@@ -28,7 +28,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix a bug in the dataset poisoning maze that could allow denial of service [#1580](https://github.com/TecharoHQ/anubis/issues/1580).
- Add config option to add ASN to logs/metrics.
- Log weight when issuing challenge
- Keep Anubis server URL state local to each `lib.Server` instance to make embedded use safer.
## v1.25.0: Necron
+15 -42
View File
@@ -33,7 +33,6 @@ import (
"github.com/TecharoHQ/anubis/lib/policy"
"github.com/TecharoHQ/anubis/lib/policy/checker"
"github.com/TecharoHQ/anubis/lib/store"
"github.com/TecharoHQ/anubis/web"
iptoasnv1 "github.com/TecharoHQ/thoth-proto/gen/techaro/thoth/iptoasn/v1"
// challenge implementations
@@ -98,8 +97,6 @@ type Server struct {
OGTags *ogtags.OGTagCache
logger *slog.Logger
opts Options
basePrefix string
publicURL string
ed25519Priv ed25519.PrivateKey
hs512Secret []byte
}
@@ -126,42 +123,6 @@ func (s *Server) getRequestLogger(r *http.Request) (*slog.Logger, *http.Request)
return lg, r
}
func (s *Server) configuredBasePrefix() string {
if s.basePrefix != "" {
return s.basePrefix
}
return strings.TrimRight(s.opts.BasePrefix, "/")
}
func (s *Server) configuredPublicURL() string {
if s.publicURL != "" {
return s.publicURL
}
return s.opts.PublicUrl
}
func (s *Server) prefixedPath(path string) string {
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
return s.configuredBasePrefix() + path
}
func (s *Server) cookiePath() string {
basePrefix := s.configuredBasePrefix()
if basePrefix == "" {
return "/"
}
return basePrefix + "/"
}
func (s *Server) renderOptions() web.Options {
return web.Options{
BasePrefix: s.configuredBasePrefix(),
PublicURL: s.configuredPublicURL(),
}
}
func (s *Server) getTokenKeyfunc() jwt.Keyfunc {
// return ED25519 key if HS512 is not set
if len(s.hs512Secret) == 0 {
@@ -285,7 +246,11 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS
return
}
cookiePath := s.cookiePath()
// Adjust cookie path if base prefix is not empty
cookiePath := "/"
if anubis.BasePrefix != "" {
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
}
cr, rule, err := s.check(r, lg)
if err != nil {
@@ -379,7 +344,11 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS
}
func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.CheckResult, lg *slog.Logger, rule *policy.Bot) bool {
cookiePath := s.cookiePath()
// Adjust cookie path if base prefix is not empty
cookiePath := "/"
if anubis.BasePrefix != "" {
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
}
localizer := localization.GetLocalizer(r)
@@ -542,7 +511,11 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
return
}
cookiePath := s.cookiePath()
// Adjust cookie path if base prefix is not empty
cookiePath := "/"
if anubis.BasePrefix != "" {
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
}
if _, err := r.Cookie(anubis.TestCookieName); errors.Is(err, http.ErrNoCookie) {
s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host})
+2 -92
View File
@@ -2,7 +2,6 @@ package lib
import (
"bytes"
"compress/gzip"
"context"
"encoding/json"
"fmt"
@@ -502,11 +501,8 @@ func TestBasePrefix(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
originalBasePrefix := anubis.BasePrefix
anubis.BasePrefix = "/not-this-server"
t.Cleanup(func() {
anubis.BasePrefix = originalBasePrefix
})
// Reset the global BasePrefix before each test
anubis.BasePrefix = ""
pol := loadPolicies(t, "", 4)
@@ -635,96 +631,10 @@ func TestBasePrefix(t *testing.T) {
if ckie.Path != expectedPath {
t.Errorf("cookie path is wrong, wanted %s, got: %s", expectedPath, ckie.Path)
}
if anubis.BasePrefix != "/not-this-server" {
t.Errorf("New should not overwrite anubis.BasePrefix, got %q", anubis.BasePrefix)
}
})
}
}
func TestBasePrefixUsesServerConfigNotPackageGlobal(t *testing.T) {
originalBasePrefix := anubis.BasePrefix
anubis.BasePrefix = "/global"
t.Cleanup(func() {
anubis.BasePrefix = originalBasePrefix
})
pol := loadPolicies(t, "", 4)
srv := spawnAnubis(t, Options{
Next: http.NewServeMux(),
Policy: pol,
BasePrefix: "/local/",
})
if anubis.BasePrefix != "/global" {
t.Fatalf("New should leave anubis.BasePrefix alone, got %q", anubis.BasePrefix)
}
req := httptest.NewRequest(http.MethodPost, "/local/.within.website/x/cmd/anubis/api/make-challenge?redir=/", nil)
req.Header.Set("X-Real-Ip", "127.0.0.1")
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected local server prefix route to work, got status %d body %q", rr.Code, rr.Body.String())
}
}
func TestRenderIndexUsesServerBasePrefixNotPackageGlobal(t *testing.T) {
originalBasePrefix := anubis.BasePrefix
anubis.BasePrefix = "/global"
t.Cleanup(func() {
anubis.BasePrefix = originalBasePrefix
})
pol := loadPolicies(t, "", 4)
srv := spawnAnubis(t, Options{
Next: http.NewServeMux(),
Policy: pol,
BasePrefix: "/local/",
})
req := httptest.NewRequest(http.MethodGet, "/local/protected", nil)
req.Header.Set("X-Real-Ip", "127.0.0.1")
req.Header.Set("User-Agent", "Mozilla/5.0")
req.Header.Set("Accept-Encoding", "gzip")
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
resp := rr.Result()
defer resp.Body.Close()
var body strings.Builder
reader := io.Reader(resp.Body)
if resp.Header.Get("Content-Encoding") == "gzip" {
gzipReader, err := gzip.NewReader(resp.Body)
if err != nil {
t.Fatalf("opening gzip response should not fail: %v", err)
}
defer gzipReader.Close()
reader = gzipReader
}
if _, err := io.Copy(&body, reader); err != nil {
t.Fatalf("reading challenge response should not fail: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected challenge status %d, got %d body %q", http.StatusOK, resp.StatusCode, body.String())
}
if !strings.Contains(body.String(), "/local/.within.website/x/cmd/anubis/static/js/main.mjs") {
t.Fatalf("expected challenge assets to use server base prefix, body %q", body.String())
}
if strings.Contains(body.String(), "/global/.within.website") {
t.Fatalf("challenge body used package global base prefix: %q", body.String())
}
if anubis.BasePrefix != "/global" {
t.Fatalf("rendering should leave anubis.BasePrefix alone, got %q", anubis.BasePrefix)
}
}
func TestCustomStatusCodes(t *testing.T) {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Log(r.UserAgent())
+5 -6
View File
@@ -44,12 +44,11 @@ func Methods() []string {
}
type IssueInput struct {
BasePrefix string
Impressum *config.Impressum
Rule *policy.Bot
Challenge *Challenge
OGTags map[string]string
Store store.Interface
Impressum *config.Impressum
Rule *policy.Bot
Challenge *Challenge
OGTags map[string]string
Store store.Interface
}
func (in *IssueInput) Valid() error {
+3 -2
View File
@@ -7,6 +7,7 @@ import (
"net/http"
"time"
"github.com/TecharoHQ/anubis"
"github.com/TecharoHQ/anubis/lib/challenge"
"github.com/TecharoHQ/anubis/lib/localization"
"github.com/a-h/templ"
@@ -27,7 +28,7 @@ func (i *Impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in
return nil, err
}
u, err := r.URL.Parse(in.BasePrefix + "/.within.website/x/cmd/anubis/api/pass-challenge")
u, err := r.URL.Parse(anubis.BasePrefix + "/.within.website/x/cmd/anubis/api/pass-challenge")
if err != nil {
return nil, fmt.Errorf("can't render page: %w", err)
}
@@ -46,7 +47,7 @@ func (i *Impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in
loc := localization.GetLocalizer(r)
result := page(in.BasePrefix, u.String(), in.Rule.Challenge.Difficulty, showMeta, loc)
result := page(u.String(), in.Rule.Challenge.Difficulty, showMeta, loc)
return result, nil
}
+3 -3
View File
@@ -7,10 +7,10 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
templ page(basePrefix, redir string, difficulty int, showMeta bool, loc *localization.SimpleLocalizer) {
templ page(redir string, difficulty int, showMeta bool, loc *localization.SimpleLocalizer) {
<div class="centered-div">
<img id="image" style="width:100%;max-width:256px;" src={ basePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
<img style="display:none;" style="width:100%;max-width:256px;" src={ basePrefix + "/.within.website/x/cmd/anubis/static/img/happy.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 }/>
<p id="status">{ loc.T("loading") }</p>
<p>{ loc.T("connection_security") }</p>
if showMeta {
+5 -5
View File
@@ -15,7 +15,7 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
func page(basePrefix, redir string, difficulty int, showMeta bool, loc *localization.SimpleLocalizer) templ.Component {
func page(redir string, difficulty int, showMeta bool, loc *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 {
@@ -41,9 +41,9 @@ func page(basePrefix, redir string, difficulty int, showMeta bool, loc *localiza
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(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 {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 12, Col: 158}
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))
if templ_7745c5c3_Err != nil {
@@ -54,9 +54,9 @@ func page(basePrefix, redir string, difficulty int, showMeta bool, loc *localiza
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(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 {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 13, Col: 167}
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))
if templ_7745c5c3_Err != nil {
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"net/http"
"time"
"github.com/TecharoHQ/anubis"
"github.com/TecharoHQ/anubis/internal"
"github.com/TecharoHQ/anubis/lib/challenge"
"github.com/TecharoHQ/anubis/lib/localization"
@@ -42,7 +43,7 @@ func (i *impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in
return nil, err
}
u, err := r.URL.Parse(in.BasePrefix + "/.within.website/x/cmd/anubis/api/pass-challenge")
u, err := r.URL.Parse(anubis.BasePrefix + "/.within.website/x/cmd/anubis/api/pass-challenge")
if err != nil {
return nil, fmt.Errorf("can't render page: %w", err)
}
@@ -54,7 +55,7 @@ func (i *impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in
loc := localization.GetLocalizer(r)
result := page(in.BasePrefix, u.String(), in.Challenge.RandomData, in.Rule.Challenge.Difficulty, loc)
result := page(u.String(), in.Challenge.RandomData, in.Rule.Challenge.Difficulty, loc)
return result, nil
}
+3 -3
View File
@@ -5,10 +5,10 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
templ page(basePrefix, redir, challenge string, difficulty int, loc *localization.SimpleLocalizer) {
templ page(redir, challenge string, difficulty int, loc *localization.SimpleLocalizer) {
<div class="centered-div">
<div id="app">
<img id="image" style="width:100%;max-width:256px;" src={ 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">{ loc.T("loading") }</p>
<p>{ loc.T("connection_security") }</p>
</div>
@@ -18,7 +18,7 @@ templ page(basePrefix, redir, challenge string, difficulty int, loc *localizatio
"difficulty": difficulty,
"connection_security_message": loc.T("connection_security"),
"loading_message": loc.T("loading"),
"pensive_url": basePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version,
"pensive_url": anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version,
})
@templ.ComponentFunc(renderAppJS)
<noscript>
+4 -4
View File
@@ -13,7 +13,7 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
func page(basePrefix, redir, challenge string, difficulty int, loc *localization.SimpleLocalizer) templ.Component {
func page(redir, challenge string, difficulty int, loc *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 {
@@ -39,9 +39,9 @@ func page(basePrefix, redir, challenge string, difficulty int, loc *localization
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(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 {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `preact.templ`, Line: 11, Col: 159}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `preact.templ`, Line: 11, Col: 166}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -83,7 +83,7 @@ func page(basePrefix, redir, challenge string, difficulty int, loc *localization
"difficulty": difficulty,
"connection_security_message": loc.T("connection_security"),
"loading_message": loc.T("loading"),
"pensive_url": basePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version,
"pensive_url": anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
+1 -1
View File
@@ -29,7 +29,7 @@ func (i *Impl) Setup(mux *http.ServeMux) {}
func (i *Impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in *chall.IssueInput) (templ.Component, error) {
loc := localization.GetLocalizer(r)
return page(in.BasePrefix, loc), nil
return page(loc), nil
}
func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *chall.ValidateInput) error {
+4 -4
View File
@@ -5,12 +5,12 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
templ page(basePrefix string, localizer *localization.SimpleLocalizer) {
templ page(localizer *localization.SimpleLocalizer) {
<div class="centered-div">
<img id="image" style="width:100%;max-width:256px;" src={ basePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version }/>
<img style="display:none;" style="width:100%;max-width:256px;" src={ basePrefix + "/.within.website/x/cmd/anubis/static/img/happy.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 }/>
<p id="status">{ localizer.T("loading") }</p>
<script async type="module" src={ 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 class="bar-inner"></div>
</div>
+7 -7
View File
@@ -13,7 +13,7 @@ import (
"github.com/TecharoHQ/anubis/lib/localization"
)
func page(basePrefix string, localizer *localization.SimpleLocalizer) templ.Component {
func page(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 {
@@ -39,9 +39,9 @@ func page(basePrefix string, localizer *localization.SimpleLocalizer) templ.Comp
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(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 {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `proofofwork.templ`, Line: 10, Col: 158}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `proofofwork.templ`, Line: 10, Col: 165}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -52,9 +52,9 @@ func page(basePrefix string, localizer *localization.SimpleLocalizer) templ.Comp
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(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 {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `proofofwork.templ`, Line: 11, Col: 167}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `proofofwork.templ`, Line: 11, Col: 174}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -78,9 +78,9 @@ func page(basePrefix string, localizer *localization.SimpleLocalizer) templ.Comp
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(basePrefix + "/.within.website/x/cmd/anubis/static/js/main.mjs?cacheBuster=" + anubis.Version)
templ_7745c5c3_Var5, 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: `proofofwork.templ`, Line: 13, Col: 129}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `proofofwork.templ`, Line: 13, Col: 136}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
+18 -12
View File
@@ -112,7 +112,8 @@ func New(opts Options) (*Server, error) {
opts.ED25519PrivateKey = priv
}
opts.BasePrefix = strings.TrimRight(opts.BasePrefix, "/")
anubis.BasePrefix = strings.TrimRight(opts.BasePrefix, "/")
anubis.PublicUrl = opts.PublicUrl
result := &Server{
next: opts.Next,
@@ -120,8 +121,6 @@ func New(opts Options) (*Server, error) {
hs512Secret: opts.HS512Secret,
policy: opts.Policy,
opts: opts,
basePrefix: opts.BasePrefix,
publicURL: opts.PublicUrl,
OGTags: ogtags.NewOGTagCache(opts.Target, opts.Policy.OpenGraph, opts.Policy.Store, ogtags.TargetOptions{
Host: opts.TargetHost,
SNI: opts.TargetSNI,
@@ -132,20 +131,28 @@ func New(opts Options) (*Server, error) {
}
mux := http.NewServeMux()
xessPrefix := result.prefixedPath(xess.BasePrefix)
mux.Handle(xessPrefix, internal.UnchangingCache(http.StripPrefix(xessPrefix, http.FileServerFS(xess.Static))))
xess.Mount(mux)
// Helper to add the server-local base prefix.
// Helper to add global prefix
registerWithPrefix := func(pattern string, handler http.Handler, method string) {
if method != "" {
method = method + " " // methods must end with a space to register with them
}
mux.Handle(method+result.prefixedPath(pattern), handler)
// Ensure there's no double slash when concatenating BasePrefix and pattern
basePrefix := strings.TrimSuffix(anubis.BasePrefix, "/")
prefix := method + basePrefix
// If pattern doesn't start with a slash, add one
if !strings.HasPrefix(pattern, "/") {
pattern = "/" + pattern
}
mux.Handle(prefix+pattern, handler)
}
// Ensure there's no double slash when concatenating BasePrefix and StaticPath
stripPrefix := result.prefixedPath(anubis.StaticPath)
stripPrefix := strings.TrimSuffix(anubis.BasePrefix, "/") + anubis.StaticPath
registerWithPrefix(anubis.StaticPath, internal.UnchangingCache(internal.NoBrowsing(http.StripPrefix(stripPrefix, http.FileServerFS(web.Static)))), "")
if opts.ServeRobotsTXT {
@@ -159,10 +166,9 @@ func New(opts Options) (*Server, error) {
if opts.Policy.Impressum != nil {
registerWithPrefix(anubis.APIPrefix+"imprint", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler := templ.Handler(
web.BaseWithOptions(result.renderOptions(), opts.Policy.Impressum.Page.Title, opts.Policy.Impressum.Page, opts.Policy.Impressum, localization.GetLocalizer(r)),
)
handler.ServeHTTP(w, r)
templ.Handler(
web.Base(opts.Policy.Impressum.Page.Title, opts.Policy.Impressum.Page, opts.Policy.Impressum, localization.GetLocalizer(r)),
).ServeHTTP(w, r)
}), "GET")
}
+21 -37
View File
@@ -193,7 +193,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
localizer := localization.GetLocalizer(r)
if returnHTTPStatusOnly {
if s.configuredPublicURL() == "" {
if s.opts.PublicUrl == "" {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(localizer.T("authorization_required")))
} else {
@@ -263,12 +263,11 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
}
in := &challenge.IssueInput{
BasePrefix: s.configuredBasePrefix(),
Impressum: s.policy.Impressum,
Rule: rule,
Challenge: chall,
OGTags: ogTags,
Store: s.store,
Impressum: s.policy.Impressum,
Rule: rule,
Challenge: chall,
OGTags: ogTags,
Store: s.store,
}
component, err := impl.Issue(w, r, lg, in)
@@ -278,8 +277,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
return
}
page := web.BaseWithChallengeAndOGTagsWithOptions(
s.renderOptions(),
page := web.BaseWithChallengeAndOGTags(
localizer.T("making_sure_not_bot"),
component,
s.policy.Impressum,
@@ -325,17 +323,15 @@ func (s *Server) constructRedirectURL(r *http.Request) (string, error) {
redir := proto + "://" + host + uri
escapedURL := url.QueryEscape(redir)
return fmt.Sprintf("%s/.within.website/?redir=%s", s.configuredPublicURL(), escapedURL), nil
return fmt.Sprintf("%s/.within.website/?redir=%s", s.opts.PublicUrl, escapedURL), nil
}
func (s *Server) RenderBench(w http.ResponseWriter, r *http.Request) {
localizer := localization.GetLocalizer(r)
opts := s.renderOptions()
handler := templ.Handler(
web.BaseWithOptions(opts, localizer.T("benchmarking_anubis"), web.BenchWithOptions(opts, localizer), s.policy.Impressum, localizer),
)
handler.ServeHTTP(w, r)
templ.Handler(
web.Base(localizer.T("benchmarking_anubis"), web.Bench(localizer), s.policy.Impressum, localizer),
).ServeHTTP(w, r)
}
func (s *Server) respondWithError(w http.ResponseWriter, r *http.Request, message, code string) {
@@ -344,12 +340,10 @@ func (s *Server) respondWithError(w http.ResponseWriter, r *http.Request, messag
func (s *Server) respondWithStatus(w http.ResponseWriter, r *http.Request, msg, code string, status int) {
localizer := localization.GetLocalizer(r)
opts := s.renderOptions()
component := web.BaseWithOptions(
opts,
component := web.Base(
localizer.T("oh_noes"),
web.ErrorPageWithOptions(opts, msg, s.opts.WebmasterEmail, code, localizer),
web.ErrorPage(msg, s.opts.WebmasterEmail, code, localizer),
s.policy.Impressum,
localizer,
)
@@ -358,25 +352,17 @@ func (s *Server) respondWithStatus(w http.ResponseWriter, r *http.Request, msg,
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, s.prefixedPath(anubis.StaticPath)) {
if strings.HasPrefix(r.URL.Path, anubis.BasePrefix+anubis.StaticPath) {
s.mux.ServeHTTP(w, r)
return
} else if strings.HasPrefix(r.URL.Path, s.prefixedPath(xess.BasePrefix)) {
} else if strings.HasPrefix(r.URL.Path, anubis.BasePrefix+xess.BasePrefix) {
s.mux.ServeHTTP(w, r)
return
}
// Forward robots.txt requests to mux when ServeRobotsTXT is enabled
if s.opts.ServeRobotsTXT {
path := r.URL.Path
basePrefix := s.configuredBasePrefix()
if basePrefix != "" {
if !strings.HasPrefix(path, basePrefix) {
s.maybeReverseProxyOrPage(w, r)
return
}
path = strings.TrimPrefix(path, basePrefix)
}
path := strings.TrimPrefix(r.URL.Path, anubis.BasePrefix)
if path == "/robots.txt" || path == "/.well-known/robots.txt" {
s.mux.ServeHTTP(w, r)
return
@@ -387,11 +373,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) stripBasePrefixFromRequest(r *http.Request) *http.Request {
basePrefix := s.configuredBasePrefix()
if !s.opts.StripBasePrefix || basePrefix == "" {
if !s.opts.StripBasePrefix || s.opts.BasePrefix == "" {
return r
}
basePrefix := strings.TrimSuffix(s.opts.BasePrefix, "/")
path := r.URL.Path
if !strings.HasPrefix(path, basePrefix) {
@@ -455,11 +441,9 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
return
}
opts := s.renderOptions()
handler := templ.Handler(
web.BaseWithOptions(opts, localizer.T("you_are_not_a_bot"), web.StaticHappyWithOptions(opts, localizer), s.policy.Impressum, localizer),
)
handler.ServeHTTP(w, r)
templ.Handler(
web.Base(localizer.T("you_are_not_a_bot"), web.StaticHappy(localizer), s.policy.Impressum, localizer),
).ServeHTTP(w, r)
} else {
asn, asnDesc := asnFromContext(r.Context())
requestsProxied.WithLabelValues(r.Host, asn, asnDesc).Inc()
+357 -324
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -20,11 +20,11 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@commitlint/cli": "^20.5.3",
"@commitlint/config-conventional": "^20.5.3",
"baseline-browser-mapping": "^2.10.27",
"cssnano": "^7.1.8",
"cssnano-preset-advanced": "^7.0.16",
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"baseline-browser-mapping": "^2.10.15",
"cssnano": "^7.1.4",
"cssnano-preset-advanced": "^7.0.12",
"esbuild": "^0.28.0",
"husky": "^9.1.7",
"playwright": "^1.52.0",
@@ -32,7 +32,7 @@
"postcss-import": "^16.1.1",
"postcss-import-url": "^7.2.0",
"postcss-url": "^10.1.3",
"prettier": "^3.8.3"
"prettier": "^3.8.1"
},
"dependencies": {
"@aws-crypto/sha256-js": "^5.2.0",
+4 -46
View File
@@ -7,43 +7,17 @@ import (
"github.com/a-h/templ"
"github.com/TecharoHQ/anubis"
"github.com/TecharoHQ/anubis/lib/challenge"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/localization"
)
// Options carries per-server render state for Anubis pages. Embedders can
// render multiple Server instances in one process without mutating package
// globals.
type Options struct {
BasePrefix string
PublicURL string
}
// DefaultOptions preserves the legacy package-global behavior for callers that
// render web components directly.
func DefaultOptions() Options {
return Options{
BasePrefix: anubis.BasePrefix,
PublicURL: anubis.PublicUrl,
}
}
func Base(title string, body templ.Component, impressum *config.Impressum, localizer *localization.SimpleLocalizer) templ.Component {
return BaseWithOptions(DefaultOptions(), title, body, impressum, localizer)
}
func BaseWithOptions(opts Options, title string, body templ.Component, impressum *config.Impressum, localizer *localization.SimpleLocalizer) templ.Component {
return base(opts, title, body, impressum, nil, nil, localizer)
return base(title, body, impressum, nil, nil, localizer)
}
func BaseWithChallengeAndOGTags(title string, body templ.Component, impressum *config.Impressum, challenge *challenge.Challenge, rules *config.ChallengeRules, ogTags map[string]string, localizer *localization.SimpleLocalizer) templ.Component {
return BaseWithChallengeAndOGTagsWithOptions(DefaultOptions(), title, body, impressum, challenge, rules, ogTags, localizer)
}
func BaseWithChallengeAndOGTagsWithOptions(opts Options, title string, body templ.Component, impressum *config.Impressum, challenge *challenge.Challenge, rules *config.ChallengeRules, ogTags map[string]string, localizer *localization.SimpleLocalizer) templ.Component {
return base(opts, title, body, impressum, struct {
return base(title, body, impressum, struct {
Rules *config.ChallengeRules `json:"rules"`
Challenge any `json:"challenge"`
}{
@@ -53,27 +27,11 @@ func BaseWithChallengeAndOGTagsWithOptions(opts Options, title string, body temp
}
func ErrorPage(msg, mail, code string, localizer *localization.SimpleLocalizer) templ.Component {
return ErrorPageWithOptions(DefaultOptions(), msg, mail, code, localizer)
}
func ErrorPageWithOptions(opts Options, msg, mail, code string, localizer *localization.SimpleLocalizer) templ.Component {
return errorPage(opts, msg, mail, code, localizer)
}
func StaticHappy(localizer *localization.SimpleLocalizer) templ.Component {
return StaticHappyWithOptions(DefaultOptions(), localizer)
}
func StaticHappyWithOptions(opts Options, localizer *localization.SimpleLocalizer) templ.Component {
return staticHappy(opts, localizer)
return errorPage(msg, mail, code, localizer)
}
func Bench(localizer *localization.SimpleLocalizer) templ.Component {
return BenchWithOptions(DefaultOptions(), localizer)
}
func BenchWithOptions(opts Options, localizer *localization.SimpleLocalizer) templ.Component {
return bench(opts, localizer)
return bench(localizer)
}
func honeypotLink(href string) templ.Component {
+13 -13
View File
@@ -9,12 +9,12 @@ import (
"github.com/google/uuid"
)
templ base(opts Options, title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) {
templ base(title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) {
<!DOCTYPE html>
<html lang={ localizer.GetLang() }>
<head>
<title>{ title }</title>
<link rel="stylesheet" href={ opts.BasePrefix + xess.URL }/>
<link rel="stylesheet" href={ anubis.BasePrefix + xess.URL }/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="robots" content="noindex,nofollow"/>
for key, value := range ogTags {
@@ -60,11 +60,11 @@ templ base(opts Options, title string, body templ.Component, impressum *config.I
</style>
@templ.JSONScript("anubis_version", anubis.Version)
@templ.JSONScript("anubis_challenge", challenge)
@templ.JSONScript("anubis_base_prefix", opts.BasePrefix)
@templ.JSONScript("anubis_public_url", opts.PublicURL)
@templ.JSONScript("anubis_base_prefix", anubis.BasePrefix)
@templ.JSONScript("anubis_public_url", anubis.PublicUrl)
</head>
<body id="top">
@honeypotLink(opts.BasePrefix + fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString()))
@honeypotLink(anubis.BasePrefix + fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString()))
<main>
<h1 id="title" class="centered-div">{ title }</h1>
@body
@@ -79,7 +79,7 @@ templ base(opts Options, title string, body templ.Component, impressum *config.I
if impressum != nil {
<p>
@templ.Raw(impressum.Footer)
-- <a href={ templ.SafeURL(opts.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a>
-- <a href={ templ.SafeURL(anubis.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)) }>Imprint</a>
</p>
}
<p>{ localizer.T("version_info") } <code>{ anubis.Version }</code>.</p>
@@ -90,9 +90,9 @@ templ base(opts Options, title string, body templ.Component, impressum *config.I
</html>
}
templ errorPage(opts Options, message, mail, code string, localizer *localization.SimpleLocalizer) {
templ errorPage(message, mail, code string, localizer *localization.SimpleLocalizer) {
<div class="centered-div">
<img id="image" alt="Sad Anubis" style="width:100%;max-width:256px;" src={ opts.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>
if code != "" {
<code><pre>{ code }</pre></code>
@@ -110,19 +110,19 @@ templ errorPage(opts Options, message, mail, code string, localizer *localizatio
</div>
}
templ staticHappy(opts Options, localizer *localization.SimpleLocalizer) {
templ StaticHappy(localizer *localization.SimpleLocalizer) {
<div class="centered-div">
<img
style="display:none;"
style="width:100%;max-width:256px;"
src={ opts.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
src={ "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
anubis.Version }
/>
<p>{ localizer.T("static_check_endpoint") }</p>
</div>
}
templ bench(opts Options, localizer *localization.SimpleLocalizer) {
templ bench(localizer *localization.SimpleLocalizer) {
<div style="height:20rem;display:flex">
<table style="margin-top:1rem;display:grid;grid-template:auto 1fr/auto auto;gap:0 0.5rem">
<thead
@@ -145,9 +145,9 @@ templ bench(opts Options, localizer *localization.SimpleLocalizer) {
></tbody>
</table>
<div class="centered-div">
<img id="image" style="width:100%;max-width:256px;" src={ opts.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">{ localizer.T("loading") }</p>
<script async type="module" src={ opts.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>
<noscript>
<p>{ localizer.T("benchmark_requires_js") }</p>
+18 -18
View File
@@ -17,7 +17,7 @@ import (
"github.com/google/uuid"
)
func base(opts Options, title string, body templ.Component, impressum *config.Impressum, challenge any, ogTags map[string]string, localizer *localization.SimpleLocalizer) 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) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -69,9 +69,9 @@ func base(opts Options, title string, body templ.Component, impressum *config.Im
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 templ.SafeURL
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(opts.BasePrefix + xess.URL)
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(anubis.BasePrefix + xess.URL)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 17, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 17, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -125,11 +125,11 @@ func base(opts Options, title string, body templ.Component, impressum *config.Im
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.JSONScript("anubis_base_prefix", opts.BasePrefix).Render(ctx, templ_7745c5c3_Buffer)
templ_7745c5c3_Err = templ.JSONScript("anubis_base_prefix", anubis.BasePrefix).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.JSONScript("anubis_public_url", opts.PublicURL).Render(ctx, templ_7745c5c3_Buffer)
templ_7745c5c3_Err = templ.JSONScript("anubis_public_url", anubis.PublicUrl).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -137,7 +137,7 @@ func base(opts Options, title string, body templ.Component, impressum *config.Im
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = honeypotLink(opts.BasePrefix+fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())).Render(ctx, templ_7745c5c3_Buffer)
templ_7745c5c3_Err = honeypotLink(anubis.BasePrefix+fmt.Sprintf("%shoneypot/%s/init", anubis.APIPrefix, uuid.NewString())).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -245,9 +245,9 @@ func base(opts Options, title string, body templ.Component, impressum *config.Im
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 templ.SafeURL
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(opts.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)))
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(anubis.BasePrefix + fmt.Sprintf("%simprint", anubis.APIPrefix)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 82, Col: 96}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 82, Col: 98}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
@@ -292,7 +292,7 @@ func base(opts Options, title string, body templ.Component, impressum *config.Im
})
}
func errorPage(opts Options, message, mail, code string, localizer *localization.SimpleLocalizer) templ.Component {
func errorPage(message, mail, code string, 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 {
@@ -318,9 +318,9 @@ func errorPage(opts Options, message, mail, code string, localizer *localization
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(opts.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version)
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(anubis.BasePrefix + "/.within.website/x/cmd/anubis/static/img/reject.webp?cacheBuster=" + anubis.Version)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 95, Col: 179}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 95, Col: 181}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
@@ -446,7 +446,7 @@ func errorPage(opts Options, message, mail, code string, localizer *localization
})
}
func staticHappy(opts Options, localizer *localization.SimpleLocalizer) templ.Component {
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 {
@@ -472,7 +472,7 @@ func staticHappy(opts Options, localizer *localization.SimpleLocalizer) templ.Co
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var26 string
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(opts.BasePrefix + "/.within.website/x/cmd/anubis/static/img/happy.webp?cacheBuster=" +
templ_7745c5c3_Var26, 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: 119, Col: 18}
@@ -502,7 +502,7 @@ func staticHappy(opts Options, localizer *localization.SimpleLocalizer) templ.Co
})
}
func bench(opts Options, localizer *localization.SimpleLocalizer) templ.Component {
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 {
@@ -606,9 +606,9 @@ func bench(opts Options, localizer *localization.SimpleLocalizer) templ.Componen
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var35 string
templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(opts.BasePrefix + "/.within.website/x/cmd/anubis/static/img/pensive.webp?cacheBuster=" + anubis.Version)
templ_7745c5c3_Var35, 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: 148, Col: 164}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 148, Col: 166}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
if templ_7745c5c3_Err != nil {
@@ -632,9 +632,9 @@ func bench(opts Options, localizer *localization.SimpleLocalizer) templ.Componen
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var37 string
templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(opts.BasePrefix + "/.within.website/x/cmd/anubis/static/js/bench.mjs?cacheBuster=" + anubis.Version)
templ_7745c5c3_Var37, 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: 150, Col: 136}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 150, Col: 138}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
if templ_7745c5c3_Err != nil {
+1 -1
View File
@@ -59,7 +59,7 @@ func TestBasePrefixInLinks(t *testing.T) {
// Render the base template to a buffer
var buf strings.Builder
component := base(Options{BasePrefix: tt.basePrefix}, tt.name, templ.NopComponent, impressum, nil, nil, localizer)
component := base(tt.name, templ.NopComponent, impressum, nil, nil, localizer)
err := component.Render(context.Background(), &buf)
if err != nil {
t.Fatalf("failed to render template: %v", err)