-
Notifications
You must be signed in to change notification settings - Fork 0
/
safeline.go
99 lines (90 loc) · 2.09 KB
/
safeline.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package traefik_safeline
import (
"context"
"fmt"
"log"
"net/http"
"os"
"sync"
"github.com/xbingW/t1k"
)
// Package example a example plugin.
// Config the plugin configuration.
type Config struct {
// Addr is the address for the detector
Addr string `yaml:"addr"`
PoolSize int `yaml:"pool_size"`
}
// CreateConfig creates the default plugin configuration.
func CreateConfig() *Config {
return &Config{
Addr: "",
PoolSize: 100,
}
}
// Safeline a plugin.
type Safeline struct {
next http.Handler
server *t1k.Server
name string
config *Config
logger *log.Logger
mu sync.Mutex
}
// New created a new plugin.
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
logger := log.New(os.Stdout, "safeline", log.LstdFlags)
logger.Printf("config: %+v", config)
return &Safeline{
next: next,
name: name,
config: config,
logger: logger,
}, nil
}
func (s *Safeline) initServer() error {
if s.server != nil {
return nil
}
s.mu.Lock()
defer s.mu.Unlock()
if s.server == nil {
server, err := t1k.NewWithPoolSize(s.config.Addr, s.config.PoolSize)
if err != nil {
return err
}
s.server = server
}
return nil
}
func (s *Safeline) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
defer func() {
if r := recover(); r != nil {
s.logger.Printf("panic: %s", r)
}
}()
if err := s.initServer(); err != nil {
s.logger.Printf("error in initServer: %s", err)
s.next.ServeHTTP(rw, req)
return
}
rw.Header().Set("X-Chaitin-waf", "safeline")
result, err := s.server.DetectHttpRequest(req)
if err != nil {
s.logger.Printf("error in detection: \n%+v\n", err)
s.next.ServeHTTP(rw, req)
return
}
if result.Blocked() {
rw.WriteHeader(result.StatusCode())
msg := fmt.Sprintf(`{"code": %d, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "%s"}`,
result.StatusCode(),
result.EventID(),
)
_, _ = rw.Write([]byte(msg))
return
}
s.next.ServeHTTP(rw, req)
//rw.WriteHeader(http.StatusForbidden)
//_, _ = rw.Write([]byte("Inject by safeline\n"))
}