mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-07-21 19:48:59 +02:00
119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
// Package cache implements utility routines for manipulating cache.
|
|
// It supports currently local file and redis cache.
|
|
package cache
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
ttl_map "github.com/leprosus/golang-ttl-map"
|
|
simpleredis "github.com/maxlerebourg/simpleredis"
|
|
|
|
logger "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/logger"
|
|
)
|
|
|
|
const (
|
|
cacheBannedValue = "t"
|
|
cacheNoBannedValue = "f"
|
|
)
|
|
|
|
// CacheMiss error string when cache is miss.
|
|
const CacheMiss = "cache:miss"
|
|
|
|
//nolint:gochecknoglobals
|
|
var (
|
|
redis simpleredis.SimpleRedis
|
|
cache = ttl_map.New()
|
|
)
|
|
|
|
type localCache struct{}
|
|
|
|
func (localCache) getDecision(clientIP string) (bool, error) {
|
|
banned, isCached := cache.Get(clientIP)
|
|
bannedString, isValid := banned.(string)
|
|
if isCached && isValid && len(bannedString) > 0 {
|
|
return bannedString == cacheBannedValue, nil
|
|
}
|
|
return false, fmt.Errorf(CacheMiss)
|
|
}
|
|
|
|
func (localCache) setDecision(clientIP string, value string, duration int64) {
|
|
cache.Set(clientIP, value, duration)
|
|
}
|
|
|
|
func (localCache) deleteDecision(clientIP string) {
|
|
cache.Del(clientIP)
|
|
}
|
|
|
|
type redisCache struct{}
|
|
|
|
func (redisCache) getDecision(clientIP string) (bool, error) {
|
|
banned, err := redis.Get(clientIP)
|
|
bannedString := string(banned)
|
|
if err == nil && len(bannedString) > 0 {
|
|
return bannedString == cacheBannedValue, nil
|
|
}
|
|
if err.Error() == simpleredis.RedisMiss {
|
|
return false, fmt.Errorf(CacheMiss)
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
func (redisCache) setDecision(clientIP string, value string, duration int64) {
|
|
if err := redis.Set(clientIP, []byte(value), duration); err != nil {
|
|
logger.Error(fmt.Sprintf("cache:setDecisionRedisCache %s", err.Error()))
|
|
}
|
|
}
|
|
|
|
func (redisCache) deleteDecision(clientIP string) {
|
|
if err := redis.Del(clientIP); err != nil {
|
|
logger.Error(fmt.Sprintf("cache:deleteDecisionRedisCache %s", err.Error()))
|
|
}
|
|
}
|
|
|
|
type cacheInterface interface {
|
|
setDecision(clientIP string, value string, duration int64)
|
|
getDecision(clientIP string) (bool, error)
|
|
deleteDecision(clientIP string)
|
|
}
|
|
|
|
// Client Cache client.
|
|
type Client struct {
|
|
cache cacheInterface
|
|
}
|
|
|
|
// New Initialize cache client.
|
|
func (client *Client) New(isRedis bool, host, pass, database string) {
|
|
if isRedis {
|
|
redis.Init(host, pass, database)
|
|
client.cache = &redisCache{}
|
|
} else {
|
|
client.cache = &localCache{}
|
|
}
|
|
logger.Debug(fmt.Sprintf("cache:New initialized isRedis:%v", isRedis))
|
|
}
|
|
|
|
// DeleteDecision delete decision in cache.
|
|
func (client *Client) DeleteDecision(clientIP string) {
|
|
logger.Debug(fmt.Sprintf("cache:DeleteDecision ip:%v", clientIP))
|
|
client.cache.deleteDecision(clientIP)
|
|
}
|
|
|
|
// GetDecision check in the cache if the IP has the banned / not banned value.
|
|
// Otherwise return with an error to add the IP in cache if we are on.
|
|
func (client *Client) GetDecision(clientIP string) (bool, error) {
|
|
logger.Debug(fmt.Sprintf("cache:GetDecision ip:%v", clientIP))
|
|
return client.cache.getDecision(clientIP)
|
|
}
|
|
|
|
// SetDecision update the cache with the IP as key and the value banned / not banned.
|
|
func (client *Client) SetDecision(clientIP string, isBanned bool, duration int64) {
|
|
logger.Debug(fmt.Sprintf("cache:SetDecision ip:%v isBanned:%v duration:%vs", clientIP, isBanned, duration))
|
|
var value string
|
|
if isBanned {
|
|
value = cacheBannedValue
|
|
} else {
|
|
value = cacheNoBannedValue
|
|
}
|
|
client.cache.setDecision(clientIP, value, duration)
|
|
}
|