mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-07-21 11:38:59 +02:00
🐛 fix all incoherence (#71)
* 🐛 fix all incoherence * 🐛 fix comment + lint
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ip "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip"
|
ip "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip"
|
||||||
@@ -144,20 +145,17 @@ func ValidateParams(config *Config) error {
|
|||||||
}
|
}
|
||||||
// We need to either have crowdsecLapiKey defined or the BouncerCert and Bouncerkey
|
// We need to either have crowdsecLapiKey defined or the BouncerCert and Bouncerkey
|
||||||
if lapiKey == "" && (certBouncer == "" || certBouncerKey == "") {
|
if lapiKey == "" && (certBouncer == "" || certBouncerKey == "") {
|
||||||
return fmt.Errorf("CrowdsecLapiKey || (CrowdsecLapiTLSCertificateBouncer && CrowdsecLapiTLSCertificateBouncerKey): cannot be both empty")
|
return fmt.Errorf("CrowdsecLapiKey || (CrowdsecLapiTLSCertificateBouncer && CrowdsecLapiTLSCertificateBouncerKey): cannot be all empty")
|
||||||
} else if lapiKey != "" && (certBouncer == "" || certBouncerKey == "") {
|
} else if lapiKey != "" && (certBouncer == "" || certBouncerKey == "") {
|
||||||
// check LAPIKey
|
lapiKey = strings.TrimSpace(lapiKey)
|
||||||
lapiKey = strings.TrimSuffix(lapiKey, "\n")
|
if err = validateParamsAPIKey(lapiKey); err != nil {
|
||||||
err = validateParamsAPIKey(lapiKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case https to contact Crowdsec LAPI and certificate must be provided
|
// Case https to contact Crowdsec LAPI and certificate must be provided
|
||||||
if config.CrowdsecLapiScheme == HTTPS && !config.CrowdsecLapiTLSInsecureVerify {
|
if config.CrowdsecLapiScheme == HTTPS && !config.CrowdsecLapiTLSInsecureVerify {
|
||||||
err = validateParamsTLS(config)
|
if err = validateParamsTLS(config); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,107 +163,16 @@ func ValidateParams(config *Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateParamsAPIKey(lapiKey string) error {
|
|
||||||
for i := 0; i < len(lapiKey); i++ {
|
|
||||||
c := lapiKey[i]
|
|
||||||
if !validHeaderFieldByte(c) {
|
|
||||||
return fmt.Errorf("CrowdsecLapiKey contains the following forbidden caracter %q", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// validHeaderFieldByte reports whether b is a valid byte in a header
|
// validHeaderFieldByte reports whether b is a valid byte in a header
|
||||||
// field name. RFC 7230 says:
|
// field name. RFC 7230 says:
|
||||||
//
|
// valid ! # $ % & ' * + - . ^ _ ` | ~ DIGIT ALPHA
|
||||||
// header-field = field-name ":" OWS field-value OWS
|
|
||||||
// field-name = token
|
|
||||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
|
||||||
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
|
||||||
// token = 1*tchar
|
|
||||||
func validHeaderFieldByte(b byte) bool {
|
|
||||||
// isTokenTable is a copy of net/http/lex.go's isTokenTable.
|
|
||||||
// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
|
// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
|
||||||
var isTokenTable = [127]bool{
|
func validateParamsAPIKey(lapiKey string) error {
|
||||||
'!': true,
|
reg := regexp.MustCompile("^[a-zA-Z0-9 !#$%&'*+-.^_`|~]*$")
|
||||||
'#': true,
|
if !reg.Match([]byte(lapiKey)) {
|
||||||
'$': true,
|
return fmt.Errorf("CrowdsecLapiKey doesn't valid this regexp: '/%s/'", reg.String())
|
||||||
'%': true,
|
|
||||||
'&': true,
|
|
||||||
'\'': true,
|
|
||||||
'*': true,
|
|
||||||
'+': true,
|
|
||||||
'-': true,
|
|
||||||
'.': true,
|
|
||||||
'0': true,
|
|
||||||
'1': true,
|
|
||||||
'2': true,
|
|
||||||
'3': true,
|
|
||||||
'4': true,
|
|
||||||
'5': true,
|
|
||||||
'6': true,
|
|
||||||
'7': true,
|
|
||||||
'8': true,
|
|
||||||
'9': true,
|
|
||||||
'A': true,
|
|
||||||
'B': true,
|
|
||||||
'C': true,
|
|
||||||
'D': true,
|
|
||||||
'E': true,
|
|
||||||
'F': true,
|
|
||||||
'G': true,
|
|
||||||
'H': true,
|
|
||||||
'I': true,
|
|
||||||
'J': true,
|
|
||||||
'K': true,
|
|
||||||
'L': true,
|
|
||||||
'M': true,
|
|
||||||
'N': true,
|
|
||||||
'O': true,
|
|
||||||
'P': true,
|
|
||||||
'Q': true,
|
|
||||||
'R': true,
|
|
||||||
'S': true,
|
|
||||||
'T': true,
|
|
||||||
'U': true,
|
|
||||||
'W': true,
|
|
||||||
'V': true,
|
|
||||||
'X': true,
|
|
||||||
'Y': true,
|
|
||||||
'Z': true,
|
|
||||||
'^': true,
|
|
||||||
'_': true,
|
|
||||||
'`': true,
|
|
||||||
'a': true,
|
|
||||||
'b': true,
|
|
||||||
'c': true,
|
|
||||||
'd': true,
|
|
||||||
'e': true,
|
|
||||||
'f': true,
|
|
||||||
'g': true,
|
|
||||||
'h': true,
|
|
||||||
'i': true,
|
|
||||||
'j': true,
|
|
||||||
'k': true,
|
|
||||||
'l': true,
|
|
||||||
'm': true,
|
|
||||||
'n': true,
|
|
||||||
'o': true,
|
|
||||||
'p': true,
|
|
||||||
'q': true,
|
|
||||||
'r': true,
|
|
||||||
's': true,
|
|
||||||
't': true,
|
|
||||||
'u': true,
|
|
||||||
'v': true,
|
|
||||||
'w': true,
|
|
||||||
'x': true,
|
|
||||||
'y': true,
|
|
||||||
'z': true,
|
|
||||||
'|': true,
|
|
||||||
'~': true,
|
|
||||||
}
|
}
|
||||||
return int(b) < len(isTokenTable) && isTokenTable[b]
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateParamsTLS(config *Config) error {
|
func validateParamsTLS(config *Config) error {
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ func Test_GetVariable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_ValidateParams(t *testing.T) {
|
func Test_ValidateParams(t *testing.T) {
|
||||||
|
cfg1 := New()
|
||||||
|
cfg1.CrowdsecLapiKey = "test\n\n"
|
||||||
|
cfg2 := New()
|
||||||
|
cfg2.CrowdsecLapiKey = "test@"
|
||||||
cfg3 := getMinimalConfig()
|
cfg3 := getMinimalConfig()
|
||||||
cfg3.CrowdsecMode = "bad"
|
cfg3.CrowdsecMode = "bad"
|
||||||
cfg4 := getMinimalConfig()
|
cfg4 := getMinimalConfig()
|
||||||
@@ -90,6 +94,8 @@ func Test_ValidateParams(t *testing.T) {
|
|||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{name: "Validate minimal config", args: args{config: getMinimalConfig()}, wantErr: false},
|
{name: "Validate minimal config", args: args{config: getMinimalConfig()}, wantErr: false},
|
||||||
|
{name: "Validate a non trimed crowdsec lapi key", args: args{config: cfg1}, wantErr: false},
|
||||||
|
{name: "Not validate unauthorized character in crowdsec lapi key", args: args{config: cfg2}, wantErr: true},
|
||||||
{name: "Not validate an absent crowdsec lapi key", args: args{config: New()}, wantErr: true},
|
{name: "Not validate an absent crowdsec lapi key", args: args{config: New()}, wantErr: true},
|
||||||
{name: "Not validate a not listed item", args: args{config: cfg3}, wantErr: true},
|
{name: "Not validate a not listed item", args: args{config: cfg3}, wantErr: true},
|
||||||
{name: "Not validate a bad number", args: args{config: cfg4}, wantErr: true},
|
{name: "Not validate a bad number", args: args{config: cfg4}, wantErr: true},
|
||||||
@@ -141,8 +147,9 @@ func Test_validateParamsIPs(t *testing.T) {
|
|||||||
{name: "Not validate localhost", args: args{listIP: []string{0: "localhost"}}, wantErr: true},
|
{name: "Not validate localhost", args: args{listIP: []string{0: "localhost"}}, wantErr: true},
|
||||||
{name: "Not validate a weird ip", args: args{listIP: []string{0: "0.0.0.0/89"}}, wantErr: true},
|
{name: "Not validate a weird ip", args: args{listIP: []string{0: "0.0.0.0/89"}}, wantErr: true},
|
||||||
{name: "Not validate a weird ip 2", args: args{listIP: []string{0: "0.0.0.256/12"}}, wantErr: true},
|
{name: "Not validate a weird ip 2", args: args{listIP: []string{0: "0.0.0.256/12"}}, wantErr: true},
|
||||||
|
{name: "Validate an ip not trimed", args: args{listIP: []string{0: " 0.0.0.0/0"}}, wantErr: false},
|
||||||
{name: "Validate an ip", args: args{listIP: []string{0: "0.0.0.0/12"}}, wantErr: false},
|
{name: "Validate an ip", args: args{listIP: []string{0: "0.0.0.0/12"}}, wantErr: false},
|
||||||
{name: "Validate a ip list", args: args{listIP: []string{0: "0.0.0.0/0", 1: "1.1.1.1/1"}}, wantErr: false},
|
{name: "Validate an ip list", args: args{listIP: []string{0: "0.0.0.0/0", 1: "1.1.1.1/1"}}, wantErr: false},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -185,6 +192,31 @@ func Test_validateParamsRequired(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_validateParamsAPIKey(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
lapiKey string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "Validate all the valid characters", args: args{lapiKey: "test!#$%&'*+-.^_`|~"}, wantErr: false},
|
||||||
|
{name: "Not validate a @", args: args{lapiKey: "test@"}, wantErr: true},
|
||||||
|
{name: "Not validate a (", args: args{lapiKey: "test("}, wantErr: true},
|
||||||
|
{name: "Not validate a [", args: args{lapiKey: "test["}, wantErr: true},
|
||||||
|
{name: "Not validate a ?", args: args{lapiKey: "test?"}, wantErr: true},
|
||||||
|
{name: "Not validate a \\n, (must be trimed before)", args: args{lapiKey: "test\n"}, wantErr: true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := validateParamsAPIKey(tt.args.lapiKey); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("validateParamsAPIKey() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_GetTLSConfigCrowdsec(t *testing.T) {
|
func Test_GetTLSConfigCrowdsec(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
config *Config
|
config *Config
|
||||||
|
|||||||
+2
-3
@@ -23,9 +23,8 @@ type Checker struct {
|
|||||||
func NewChecker(trustedIPs []string) (*Checker, error) {
|
func NewChecker(trustedIPs []string) (*Checker, error) {
|
||||||
checker := &Checker{}
|
checker := &Checker{}
|
||||||
|
|
||||||
for _, ipMask := range trustedIPs {
|
for _, ipMaskRaw := range trustedIPs {
|
||||||
// remove leading and trailing spaces
|
ipMask := strings.TrimSpace(ipMaskRaw)
|
||||||
ipMask = strings.TrimSpace(ipMask)
|
|
||||||
if ipAddr := net.ParseIP(ipMask); ipAddr != nil {
|
if ipAddr := net.ParseIP(ipMask); ipAddr != nil {
|
||||||
checker.authorizedIPs = append(checker.authorizedIPs, &ipAddr)
|
checker.authorizedIPs = append(checker.authorizedIPs, &ipAddr)
|
||||||
logger.Debug(fmt.Sprintf("IP %v is trusted", ipAddr))
|
logger.Debug(fmt.Sprintf("IP %v is trusted", ipAddr))
|
||||||
|
|||||||
Reference in New Issue
Block a user