celchecker.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package policy
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/TecharoHQ/anubis/internal"
  6. "github.com/TecharoHQ/anubis/internal/dns"
  7. "github.com/TecharoHQ/anubis/lib/config"
  8. "github.com/TecharoHQ/anubis/lib/policy/expressions"
  9. "github.com/google/cel-go/cel"
  10. "github.com/google/cel-go/common/types"
  11. )
  12. type CELChecker struct {
  13. program cel.Program
  14. src string
  15. }
  16. func NewCELChecker(cfg *config.ExpressionOrList, dnsObj *dns.Dns) (*CELChecker, error) {
  17. env, err := expressions.BotEnvironment(dnsObj)
  18. if err != nil {
  19. return nil, err
  20. }
  21. program, err := expressions.Compile(env, cfg.String())
  22. if err != nil {
  23. return nil, fmt.Errorf("can't compile CEL program: %w", err)
  24. }
  25. return &CELChecker{
  26. src: cfg.String(),
  27. program: program,
  28. }, nil
  29. }
  30. func (cc *CELChecker) Hash() string {
  31. return internal.FastHash(cc.src)
  32. }
  33. func (cc *CELChecker) Check(r *http.Request) (bool, error) {
  34. result, _, err := cc.program.ContextEval(r.Context(), &CELRequest{r})
  35. if err != nil {
  36. return false, err
  37. }
  38. if val, ok := result.(types.Bool); ok {
  39. return bool(val), nil
  40. }
  41. return false, nil
  42. }
  43. type CELRequest struct {
  44. *http.Request
  45. }
  46. func (cr *CELRequest) Parent() cel.Activation { return nil }
  47. func (cr *CELRequest) ResolveName(name string) (any, bool) {
  48. switch name {
  49. case "remoteAddress":
  50. return cr.Header.Get("X-Real-Ip"), true
  51. case "contentLength":
  52. return cr.ContentLength, true
  53. case "host":
  54. return cr.Host, true
  55. case "method":
  56. return cr.Method, true
  57. case "userAgent":
  58. return cr.UserAgent(), true
  59. case "path":
  60. return cr.URL.Path, true
  61. case "query":
  62. return expressions.URLValues{Values: cr.URL.Query()}, true
  63. case "headers":
  64. return expressions.HTTPHeaders{Header: cr.Header}, true
  65. case "load_1m":
  66. return expressions.Load1(), true
  67. case "load_5m":
  68. return expressions.Load5(), true
  69. case "load_15m":
  70. return expressions.Load15(), true
  71. default:
  72. return nil, false
  73. }
  74. }