mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-09-09 12:50:42 -04:00

Some admins have noticed that clients are not waiting the right amount of time in order to access a resource protected by the metarefresh challenge. This patch adds a check to make sure that clients have waited at least 95% (difficulty times 950 milliseconds instead of difficulity times 1000 milliseconds) of the time they should. If this scales, maybe time is the best way to go for Anubis in the near future instead of anything else computational. Signed-off-by: Xe Iaso <me@xeiaso.net>
60 lines
1.7 KiB
Go
60 lines
1.7 KiB
Go
package metarefresh
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/TecharoHQ/anubis"
|
|
"github.com/TecharoHQ/anubis/lib/challenge"
|
|
"github.com/TecharoHQ/anubis/lib/localization"
|
|
"github.com/a-h/templ"
|
|
)
|
|
|
|
//go:generate go tool github.com/a-h/templ/cmd/templ generate
|
|
|
|
func init() {
|
|
challenge.Register("metarefresh", &Impl{})
|
|
}
|
|
|
|
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) {
|
|
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)
|
|
}
|
|
|
|
q := u.Query()
|
|
q.Set("redir", r.URL.String())
|
|
q.Set("challenge", in.Challenge.RandomData)
|
|
q.Set("id", in.Challenge.ID)
|
|
u.RawQuery = q.Encode()
|
|
|
|
loc := localization.GetLocalizer(r)
|
|
|
|
result := page(u.String(), in.Rule.Challenge.Difficulty, loc)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *challenge.ValidateInput) error {
|
|
wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 950 * time.Millisecond)
|
|
|
|
if time.Now().Before(wantTime) {
|
|
return challenge.NewError("validate", "insufficent time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339)))
|
|
}
|
|
|
|
gotChallenge := r.FormValue("challenge")
|
|
|
|
if subtle.ConstantTimeCompare([]byte(in.Challenge.RandomData), []byte(gotChallenge)) != 1 {
|
|
return challenge.NewError("validate", "invalid response", fmt.Errorf("%w: wanted response %s but got %s", challenge.ErrFailed, in.Challenge.RandomData, gotChallenge))
|
|
}
|
|
|
|
return nil
|
|
}
|