diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index e503a78..8b2c9aa 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add the `DIFFICULTY_IN_JWT` option, which allows one to add the `difficulty` field in the JWT claims which indicates the difficulty of the token ([#1063](https://github.com/TecharoHQ/anubis/pull/1063)). - Ported the client-side JS to TypeScript to avoid egregious errors in the future. - Fixes concurrency problems with very old browsers ([#1082](https://github.com/TecharoHQ/anubis/issues/1082)). +- Randomly use the Refresh header instead of the meta refresh tag in the metarefresh challenge. - Update OpenRC service to truncate the runtime directory before starting Anubis. ### Bug Fixes diff --git a/lib/challenge/interface.go b/lib/challenge/interface.go index 963d6ca..c7a1944 100644 --- a/lib/challenge/interface.go +++ b/lib/challenge/interface.go @@ -61,7 +61,7 @@ type Impl interface { Setup(mux *http.ServeMux) // Issue a new challenge to the user, called by the Anubis. - Issue(r *http.Request, lg *slog.Logger, in *IssueInput) (templ.Component, error) + Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in *IssueInput) (templ.Component, error) // Validate a challenge, making sure that it passes muster. Validate(r *http.Request, lg *slog.Logger, in *ValidateInput) error diff --git a/lib/challenge/metarefresh/metarefresh.go b/lib/challenge/metarefresh/metarefresh.go index 75ac70f..c554b91 100644 --- a/lib/challenge/metarefresh/metarefresh.go +++ b/lib/challenge/metarefresh/metarefresh.go @@ -23,7 +23,7 @@ type Impl struct{} func (i *Impl) Setup(mux *http.ServeMux) {} -func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput) (templ.Component, error) { +func (i *Impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in *challenge.IssueInput) (templ.Component, error) { 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) @@ -35,9 +35,15 @@ func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput) q.Set("id", in.Challenge.ID) u.RawQuery = q.Encode() + showMeta := in.Challenge.RandomData[0]%2 == 0 + + if !showMeta { + w.Header().Add("Refresh", fmt.Sprintf("%d; url=%s", in.Rule.Challenge.Difficulty+1, u.String())) + } + loc := localization.GetLocalizer(r) - result := page(u.String(), in.Rule.Challenge.Difficulty, loc) + result := page(u.String(), in.Rule.Challenge.Difficulty, showMeta, loc) return result, nil } diff --git a/lib/challenge/metarefresh/metarefresh.templ b/lib/challenge/metarefresh/metarefresh.templ index dccf765..c074f59 100644 --- a/lib/challenge/metarefresh/metarefresh.templ +++ b/lib/challenge/metarefresh/metarefresh.templ @@ -7,12 +7,14 @@ import ( "github.com/TecharoHQ/anubis/lib/localization" ) -templ page(redir string, difficulty int, loc *localization.SimpleLocalizer) { +templ page(redir string, difficulty int, showMeta bool, loc *localization.SimpleLocalizer) {
{ loc.T("loading") }

{ loc.T("connection_security") }

- + if showMeta { + + }
} diff --git a/lib/challenge/metarefresh/metarefresh_templ.go b/lib/challenge/metarefresh/metarefresh_templ.go index 048260b..f54c45a 100644 --- a/lib/challenge/metarefresh/metarefresh_templ.go +++ b/lib/challenge/metarefresh/metarefresh_templ.go @@ -15,7 +15,7 @@ import ( "github.com/TecharoHQ/anubis/lib/localization" ) -func page(redir string, difficulty int, 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 { @@ -88,20 +88,30 @@ func page(redir string, difficulty int, loc *localization.SimpleLocalizer) templ if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") 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+1, redir)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `metarefresh.templ`, Line: 16, Col: 85} + if showMeta { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } - _, 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, "\">") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/lib/challenge/preact/preact.go b/lib/challenge/preact/preact.go index 0276d7d..a785f98 100644 --- a/lib/challenge/preact/preact.go +++ b/lib/challenge/preact/preact.go @@ -38,7 +38,7 @@ type impl struct{} func (i *impl) Setup(mux *http.ServeMux) {} -func (i *impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput) (templ.Component, error) { +func (i *impl) Issue(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in *challenge.IssueInput) (templ.Component, error) { 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) diff --git a/lib/challenge/proofofwork/proofofwork.go b/lib/challenge/proofofwork/proofofwork.go index 8cd3127..b9be014 100644 --- a/lib/challenge/proofofwork/proofofwork.go +++ b/lib/challenge/proofofwork/proofofwork.go @@ -27,7 +27,7 @@ type Impl struct { 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(w http.ResponseWriter, r *http.Request, lg *slog.Logger, in *chall.IssueInput) (templ.Component, error) { loc := localization.GetLocalizer(r) return page(loc), nil } diff --git a/lib/challenge/proofofwork/proofofwork_test.go b/lib/challenge/proofofwork/proofofwork_test.go index 4e71bcf..c0611a5 100644 --- a/lib/challenge/proofofwork/proofofwork_test.go +++ b/lib/challenge/proofofwork/proofofwork_test.go @@ -4,6 +4,7 @@ import ( "errors" "log/slog" "net/http" + "net/http/httptest" "testing" "github.com/TecharoHQ/anubis/lib/challenge" @@ -133,7 +134,7 @@ func TestBasic(t *testing.T) { }, } - if _, err := i.Issue(cs.req, lg, inp); err != nil { + if _, err := i.Issue(httptest.NewRecorder(), cs.req, lg, inp); err != nil { t.Errorf("can't issue challenge: %v", err) } diff --git a/lib/http.go b/lib/http.go index 7209d58..1332035 100644 --- a/lib/http.go +++ b/lib/http.go @@ -29,19 +29,19 @@ var domainMatchRegexp = regexp.MustCompile(`^((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[ // internal glob matcher. Matching is case-insensitive on hostnames. func matchRedirectDomain(allowed []string, host string) bool { h := strings.ToLower(strings.TrimSpace(host)) - for _, pat := range allowed { - p := strings.ToLower(strings.TrimSpace(pat)) - if strings.Contains(p, glob.GLOB) { - if glob.Glob(p, h) { - return true - } - continue - } - if p == h { - return true - } - } - return false + for _, pat := range allowed { + p := strings.ToLower(strings.TrimSpace(pat)) + if strings.Contains(p, glob.GLOB) { + if glob.Glob(p, h) { + return true + } + continue + } + if p == h { + return true + } + } + return false } type CookieOpts struct { @@ -214,7 +214,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C Store: s.store, } - component, err := impl.Issue(r, lg, in) + component, err := impl.Issue(w, r, lg, in) if err != nil { lg.Error("[unexpected] challenge component 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, fmt.Sprintf("%s \"RenderIndex\"", localizer.T("internal_server_error")))