From 04b3a835cdac83001ea67166e129d5ac99fb313d Mon Sep 17 00:00:00 2001 From: Julien Voisin Date: Thu, 28 May 2026 17:35:14 +0200 Subject: [PATCH] perf(lib): iterate s.policy.Bots by index to drop per-call heap copy (#1639) Signed-off-by: jvoisin --- docs/docs/CHANGELOG.md | 2 ++ internal/hash.go | 5 ++--- lib/challenge/proofofwork/proofofwork.go | 4 ++-- lib/policy/bot.go | 19 +++++++++++++++---- lib/policy/policy.go | 1 + 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index 96793f27..73fe7c03 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -30,6 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add config option to add ASN to logs/metrics. - Log weight when issuing challenge - Fix `path_regex` and CEL `path` rules not matching when using Traefik `forwardAuth` middleware. Anubis now checks `X-Forwarded-Uri` (Traefik) in addition to `X-Original-URI` (nginx) when resolving the request path in subrequest mode ([#1628](https://github.com/TecharoHQ/anubis/issues/1628)). +- Marginally increase the performances of requests processing +- Marginally improve the performances of PoW validation ## v1.25.0: Necron diff --git a/internal/hash.go b/internal/hash.go index aeec173d..c2913b6a 100644 --- a/internal/hash.go +++ b/internal/hash.go @@ -11,9 +11,8 @@ import ( // SHA256sum computes a cryptographic hash. Still used for proof-of-work challenges // where we need the security properties of a cryptographic hash function. func SHA256sum(text string) string { - hash := sha256.New() - hash.Write([]byte(text)) - return hex.EncodeToString(hash.Sum(nil)) + sum := sha256.Sum256([]byte(text)) + return hex.EncodeToString(sum[:]) } // FastHash is a high-performance non-cryptographic hash function suitable for diff --git a/lib/challenge/proofofwork/proofofwork.go b/lib/challenge/proofofwork/proofofwork.go index 3e4bce3b..385237be 100644 --- a/lib/challenge/proofofwork/proofofwork.go +++ b/lib/challenge/proofofwork/proofofwork.go @@ -45,7 +45,7 @@ func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *chall.ValidateInpu return chall.NewError("validate", "invalid response", fmt.Errorf("%w nonce", chall.ErrMissingField)) } - nonce, err := strconv.Atoi(nonceStr) + _, err := strconv.Atoi(nonceStr) if err != nil { return chall.NewError("validate", "invalid response", fmt.Errorf("%w: nonce: %w", chall.ErrInvalidFormat, err)) @@ -66,7 +66,7 @@ func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *chall.ValidateInpu return chall.NewError("validate", "invalid response", fmt.Errorf("%w response", chall.ErrMissingField)) } - calcString := fmt.Sprintf("%s%d", challenge, nonce) + calcString := challenge + nonceStr calculated := internal.SHA256sum(calcString) if subtle.ConstantTimeCompare([]byte(response), []byte(calculated)) != 1 { diff --git a/lib/policy/bot.go b/lib/policy/bot.go index 25c04870..2cf965b1 100644 --- a/lib/policy/bot.go +++ b/lib/policy/bot.go @@ -1,8 +1,6 @@ package policy import ( - "fmt" - "github.com/TecharoHQ/anubis/internal" "github.com/TecharoHQ/anubis/lib/config" "github.com/TecharoHQ/anubis/lib/policy/checker" @@ -13,9 +11,22 @@ type Bot struct { Challenge *config.ChallengeRules Weight *config.Weight Name string - Action config.Rule + // hash caches the result of Hash() when populated at parse time, see ParseConfig + hash string + Action config.Rule } +// Hash returns a stable identifier for this Bot derived from its Name +// and Rules. When the cached value is present (populated by +// ParseConfig) it is returned directly; otherwise the hash is +// recomputed on demand so callers do not have to know about the cache. func (b Bot) Hash() string { - return internal.FastHash(fmt.Sprintf("%s::%s", b.Name, b.Rules.Hash())) + if b.hash != "" { + return b.hash + } + var rulesHash string + if b.Rules != nil { // defensive, should never happen + rulesHash = b.Rules.Hash() + } + return internal.FastHash(b.Name + "::" + rulesHash) } diff --git a/lib/policy/policy.go b/lib/policy/policy.go index 6b329a86..5e4065b7 100644 --- a/lib/policy/policy.go +++ b/lib/policy/policy.go @@ -219,6 +219,7 @@ func ParseConfig(ctx context.Context, fin io.Reader, fname string, defaultDiffic result.Impressum = c.Impressum parsedBot.Rules = cl + parsedBot.hash = parsedBot.Hash() result.Bots = append(result.Bots, parsedBot) }