@marcel91200 / caddy Mirror · read-only / commits / 789efa5d
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 01:30 UTC

logging: add a regexp filter (#4426)

Kévin Dunglas committed Nov 23, 2021 at 18:00 UTC 789efa5deef53071b57479d37e4022bf372c4eef
3 files changed +74
caddytest/integration/caddyfile_adapt/log_filters.txt
+6
@@ -19,6 +19,7 @@ log {
19 ipv4 24
20 ipv6 32
21 }
22 + request>headers>Regexp regexp secret REDACTED
23 }
24 }
25 }
@@ -55,6 +56,11 @@ log {
56 ],
57 "filter": "cookie"
58 },
59 + "request\u003eheaders\u003eRegexp": {
60 + "filter": "regexp",
61 + "regexp": "secret",
62 + "value": "REDACTED"
63 + },
64 "request\u003eheaders\u003eServer": {
65 "filter": "delete"
66 },
modules/logging/filters.go
+57
@@ -19,6 +19,7 @@ import (
19 "net"
20 "net/http"
21 "net/url"
22 + "regexp"
23 "strconv"
24
25 "github.com/caddyserver/caddy/v2"
@@ -32,6 +33,7 @@ func init() {
33 caddy.RegisterModule(IPMaskFilter{})
34 caddy.RegisterModule(QueryFilter{})
35 caddy.RegisterModule(CookieFilter{})
36 + caddy.RegisterModule(RegexpFilter{})
37 }
38
39 // LogFieldFilter can filter (or manipulate)
@@ -426,6 +428,58 @@ OUTER:
428 return in
429 }
430
431 +// RegexpFilter is a Caddy log field filter that
432 +// replaces the field matching the provided regexp with the indicated string.
433 +type RegexpFilter struct {
434 + // The regular expression pattern defining what to replace.
435 + RawRegexp string `json:"regexp,omitempty"`
436 +
437 + // The value to use as replacement
438 + Value string `json:"value,omitempty"`
439 +
440 + regexp *regexp.Regexp
441 +}
442 +
443 +// CaddyModule returns the Caddy module information.
444 +func (RegexpFilter) CaddyModule() caddy.ModuleInfo {
445 + return caddy.ModuleInfo{
446 + ID: "caddy.logging.encoders.filter.regexp",
447 + New: func() caddy.Module { return new(RegexpFilter) },
448 + }
449 +}
450 +
451 +// UnmarshalCaddyfile sets up the module from Caddyfile tokens.
452 +func (f *RegexpFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
453 + for d.Next() {
454 + if d.NextArg() {
455 + f.RawRegexp = d.Val()
456 + }
457 + if d.NextArg() {
458 + f.Value = d.Val()
459 + }
460 + }
461 + return nil
462 +}
463 +
464 +// Provision compiles m's regexp.
465 +func (m *RegexpFilter) Provision(ctx caddy.Context) error {
466 + r, err := regexp.Compile(m.RawRegexp)
467 + if err != nil {
468 + return err
469 + }
470 +
471 + m.regexp = r
472 +
473 + return nil
474 +}
475 +
476 +// Filter filters the input field with the replacement value if it matches the regexp.
477 +func (f *RegexpFilter) Filter(in zapcore.Field) zapcore.Field {
478 + in.String = f.regexp.ReplaceAllString(in.String, f.Value)
479 +
480 + return in
481 +}
482 +
483 // Interface guards
484 var (
485 _ LogFieldFilter = (*DeleteFilter)(nil)
@@ -433,14 +487,17 @@ var (
487 _ LogFieldFilter = (*IPMaskFilter)(nil)
488 _ LogFieldFilter = (*QueryFilter)(nil)
489 _ LogFieldFilter = (*CookieFilter)(nil)
490 + _ LogFieldFilter = (*RegexpFilter)(nil)
491
492 _ caddyfile.Unmarshaler = (*DeleteFilter)(nil)
493 _ caddyfile.Unmarshaler = (*ReplaceFilter)(nil)
494 _ caddyfile.Unmarshaler = (*IPMaskFilter)(nil)
495 _ caddyfile.Unmarshaler = (*QueryFilter)(nil)
496 _ caddyfile.Unmarshaler = (*CookieFilter)(nil)
497 + _ caddyfile.Unmarshaler = (*RegexpFilter)(nil)
498
499 _ caddy.Provisioner = (*IPMaskFilter)(nil)
500 + _ caddy.Provisioner = (*RegexpFilter)(nil)
501
502 _ caddy.Validator = (*QueryFilter)(nil)
503 )
modules/logging/filters_test.go
+11
@@ -3,6 +3,7 @@ package logging
3 import (
4 "testing"
5
6 + "github.com/caddyserver/caddy/v2"
7 "go.uber.org/zap/zapcore"
8 )
9
@@ -67,3 +68,13 @@ func TestValidateCookieFilter(t *testing.T) {
68 t.Fatalf("unknown action type must be invalid")
69 }
70 }
71 +
72 +func TestRegexpFilter(t *testing.T) {
73 + f := RegexpFilter{RawRegexp: `secret`, Value: "REDACTED"}
74 + f.Provision(caddy.Context{})
75 +
76 + out := f.Filter(zapcore.Field{String: "foo-secret-bar"})
77 + if out.String != "foo-REDACTED-bar" {
78 + t.Fatalf("field has not been filtered: %s", out.String)
79 + }
80 +}