mirror of
https://github.com/TecharoHQ/anubis.git
synced 2025-08-03 17:59:24 -04:00
fix(lib): add the ability to set a custom slog Logger (#915)
* fix(lib): add the ability to set a custom slog Logger Closes #864 * test(lib): amend s.check usage Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Signed-off-by: Xe Iaso <xe.iaso@techaro.lol>
This commit is contained in:
parent
6ae386a11a
commit
1f7fcf938b
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
<!-- This changes the project to: -->
|
<!-- This changes the project to: -->
|
||||||
|
|
||||||
|
- Downstream consumers can change the default [log/slog#Logger](https://pkg.go.dev/log/slog#Logger) instance that Anubis uses by setting `opts.Logger` to your slog instance of choice ([#864](https://github.com/TecharoHQ/anubis/issues/864)).
|
||||||
- The [Thoth client](https://anubis.techaro.lol/docs/admin/thoth) is now public in the repo instead of being an internal package.
|
- The [Thoth client](https://anubis.techaro.lol/docs/admin/thoth) is now public in the repo instead of being an internal package.
|
||||||
- [Custom-AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client)'s default User-Agent has an increased weight by default ([#852](https://github.com/TecharoHQ/anubis/issues/852)).
|
- [Custom-AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client)'s default User-Agent has an increased weight by default ([#852](https://github.com/TecharoHQ/anubis/issues/852)).
|
||||||
- The [`segments`](./admin/configuration/expressions.mdx#segments) function was added for splitting a path into its slash-separated segments.
|
- The [`segments`](./admin/configuration/expressions.mdx#segments) function was added for splitting a path into its slash-separated segments.
|
||||||
|
@ -26,8 +26,8 @@ func InitSlog(level string) {
|
|||||||
slog.SetDefault(slog.New(h))
|
slog.SetDefault(slog.New(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRequestLogger(r *http.Request) *slog.Logger {
|
func GetRequestLogger(base *slog.Logger, r *http.Request) *slog.Logger {
|
||||||
return slog.With(
|
return base.With(
|
||||||
"host", r.Host,
|
"host", r.Host,
|
||||||
"method", r.Method,
|
"method", r.Method,
|
||||||
"path", r.URL.Path,
|
"path", r.URL.Path,
|
||||||
|
@ -75,6 +75,7 @@ type Server struct {
|
|||||||
hs512Secret []byte
|
hs512Secret []byte
|
||||||
opts Options
|
opts Options
|
||||||
store store.Interface
|
store store.Interface
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getTokenKeyfunc() jwt.Keyfunc {
|
func (s *Server) getTokenKeyfunc() jwt.Keyfunc {
|
||||||
@ -150,7 +151,7 @@ func (s *Server) maybeReverseProxyOrPage(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpStatusOnly bool) {
|
func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpStatusOnly bool) {
|
||||||
lg := internal.GetRequestLogger(r)
|
lg := internal.GetRequestLogger(s.logger, r)
|
||||||
|
|
||||||
// Adjust cookie path if base prefix is not empty
|
// Adjust cookie path if base prefix is not empty
|
||||||
cookiePath := "/"
|
cookiePath := "/"
|
||||||
@ -158,7 +159,7 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpS
|
|||||||
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
|
cookiePath = strings.TrimSuffix(anubis.BasePrefix, "/") + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
cr, rule, err := s.check(r)
|
cr, rule, err := s.check(r, lg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
localizer := localization.GetLocalizer(r)
|
localizer := localization.GetLocalizer(r)
|
||||||
@ -274,7 +275,7 @@ func (s *Server) checkRules(w http.ResponseWriter, r *http.Request, cr policy.Ch
|
|||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host})
|
s.ClearCookie(w, CookieOpts{Path: cookiePath, Host: r.Host})
|
||||||
slog.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule)
|
lg.Error("CONFIG ERROR: unknown rule", "rule", cr.Rule)
|
||||||
s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.Rules\"", localizer.T("internal_server_error")))
|
s.respondWithError(w, r, fmt.Sprintf("%s \"maybeReverseProxy.Rules\"", localizer.T("internal_server_error")))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -310,7 +311,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(s.logger, r)
|
||||||
localizer := localization.GetLocalizer(r)
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
redir := r.FormValue("redir")
|
redir := r.FormValue("redir")
|
||||||
@ -329,7 +330,7 @@ func (s *Server) MakeChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
r.URL.Path = redir
|
r.URL.Path = redir
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
cr, rule, err := s.check(r)
|
cr, rule, err := s.check(r, lg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
@ -381,7 +382,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(s.logger, r)
|
||||||
localizer := localization.GetLocalizer(r)
|
localizer := localization.GetLocalizer(r)
|
||||||
|
|
||||||
redir := r.FormValue("redir")
|
redir := r.FormValue("redir")
|
||||||
@ -428,7 +429,7 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cr, rule, err := s.check(r)
|
cr, rule, err := s.check(r, lg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Error("check failed", "err", err)
|
lg.Error("check failed", "err", err)
|
||||||
s.respondWithError(w, r, fmt.Sprintf("%s \"passChallenge\"", localizer.T("internal_server_error")))
|
s.respondWithError(w, r, fmt.Sprintf("%s \"passChallenge\"", localizer.T("internal_server_error")))
|
||||||
@ -509,7 +510,7 @@ func cr(name string, rule config.Rule, weight int) policy.CheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check evaluates the list of rules, and returns the result
|
// Check evaluates the list of rules, and returns the result
|
||||||
func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error) {
|
func (s *Server) check(r *http.Request, lg *slog.Logger) (policy.CheckResult, *policy.Bot, error) {
|
||||||
host := r.Header.Get("X-Real-Ip")
|
host := r.Header.Get("X-Real-Ip")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
return decaymap.Zilch[policy.CheckResult](), nil, fmt.Errorf("[misconfiguration] X-Real-Ip header is not set")
|
return decaymap.Zilch[policy.CheckResult](), nil, fmt.Errorf("[misconfiguration] X-Real-Ip header is not set")
|
||||||
@ -533,7 +534,7 @@ func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error)
|
|||||||
case config.RuleDeny, config.RuleAllow, config.RuleBenchmark, config.RuleChallenge:
|
case config.RuleDeny, config.RuleAllow, config.RuleBenchmark, config.RuleChallenge:
|
||||||
return cr("bot/"+b.Name, b.Action, weight), &b, nil
|
return cr("bot/"+b.Name, b.Action, weight), &b, nil
|
||||||
case config.RuleWeigh:
|
case config.RuleWeigh:
|
||||||
slog.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust)
|
lg.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust)
|
||||||
weight += b.Weight.Adjust
|
weight += b.Weight.Adjust
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,7 +543,7 @@ func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error)
|
|||||||
for _, t := range s.policy.Thresholds {
|
for _, t := range s.policy.Thresholds {
|
||||||
result, _, err := t.Program.ContextEval(r.Context(), &policy.ThresholdRequest{Weight: weight})
|
result, _, err := t.Program.ContextEval(r.Context(), &policy.ThresholdRequest{Weight: weight})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error when evaluating threshold expression", "expression", t.Expression.String(), "err", err)
|
lg.Error("error when evaluating threshold expression", "expression", t.Expression.String(), "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ func TestCheckDefaultDifficultyMatchesPolicy(t *testing.T) {
|
|||||||
|
|
||||||
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
||||||
|
|
||||||
cr, bot, err := s.check(req)
|
cr, bot, err := s.check(req, s.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -583,7 +583,7 @@ func TestCloudflareWorkersRule(t *testing.T) {
|
|||||||
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
||||||
req.Header.Add("Cf-Worker", "true")
|
req.Header.Add("Cf-Worker", "true")
|
||||||
|
|
||||||
cr, _, err := s.check(req)
|
cr, _, err := s.check(req, s.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -601,7 +601,7 @@ func TestCloudflareWorkersRule(t *testing.T) {
|
|||||||
|
|
||||||
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
req.Header.Add("X-Real-Ip", "127.0.0.1")
|
||||||
|
|
||||||
cr, _, err := s.check(req)
|
cr, _, err := s.check(req, s.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ type Options struct {
|
|||||||
OpenGraph config.OpenGraph
|
OpenGraph config.OpenGraph
|
||||||
ServeRobotsTXT bool
|
ServeRobotsTXT bool
|
||||||
CookieSecure bool
|
CookieSecure bool
|
||||||
|
Logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int) (*policy.ParsedConfig, error) {
|
func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int) (*policy.ParsedConfig, error) {
|
||||||
@ -89,8 +90,12 @@ func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(opts Options) (*Server, error) {
|
func New(opts Options) (*Server, error) {
|
||||||
|
if opts.Logger == nil {
|
||||||
|
opts.Logger = slog.With("subsystem", "anubis")
|
||||||
|
}
|
||||||
|
|
||||||
if opts.ED25519PrivateKey == nil && opts.HS512Secret == nil {
|
if opts.ED25519PrivateKey == nil && opts.HS512Secret == nil {
|
||||||
slog.Debug("opts.PrivateKey not set, generating a new one")
|
opts.Logger.Debug("opts.PrivateKey not set, generating a new one")
|
||||||
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("lib: can't generate private key: %v", err)
|
return nil, fmt.Errorf("lib: can't generate private key: %v", err)
|
||||||
@ -108,6 +113,7 @@ func New(opts Options) (*Server, error) {
|
|||||||
opts: opts,
|
opts: opts,
|
||||||
OGTags: ogtags.NewOGTagCache(opts.Target, opts.Policy.OpenGraph, opts.Policy.Store),
|
OGTags: ogtags.NewOGTagCache(opts.Target, opts.Policy.OpenGraph, opts.Policy.Store),
|
||||||
store: opts.Policy.Store,
|
store: opts.Policy.Store,
|
||||||
|
logger: opts.Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
@ -120,7 +120,7 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, cr policy.C
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lg := internal.GetRequestLogger(r)
|
lg := internal.GetRequestLogger(s.logger, r)
|
||||||
|
|
||||||
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")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user