apiary/honeypot/ssh/store/cache.go

119 lines
3.4 KiB
Go
Raw Normal View History

2021-09-17 00:01:43 +00:00
package store
2022-01-13 08:10:36 +00:00
import "git.t-juice.club/torjus/apiary/models"
2021-09-17 00:01:43 +00:00
2022-08-26 10:21:52 +00:00
var _ LoginAttemptStore = &CachingStore{}
2021-09-17 00:01:43 +00:00
type CachingStore struct {
backend LoginAttemptStore
totalStatsCache []StatsResult
usernameQueryCache map[string][]models.LoginAttempt
passwordQueryCache map[string][]models.LoginAttempt
ipQueryCache map[string][]models.LoginAttempt
2021-11-03 20:24:23 +00:00
uniqueUsernames map[string]struct{}
uniquePasswords map[string]struct{}
uniqueIPs map[string]struct{}
uniqueCountries map[string]struct{}
totalLoginsCount int
2021-09-17 00:01:43 +00:00
}
func NewCachingStore(backend LoginAttemptStore) *CachingStore {
2021-11-03 20:24:23 +00:00
cs := &CachingStore{
2021-09-17 00:01:43 +00:00
backend: backend,
usernameQueryCache: make(map[string][]models.LoginAttempt),
passwordQueryCache: make(map[string][]models.LoginAttempt),
ipQueryCache: make(map[string][]models.LoginAttempt),
2021-11-03 20:24:23 +00:00
uniqueUsernames: make(map[string]struct{}),
uniquePasswords: make(map[string]struct{}),
uniqueIPs: make(map[string]struct{}),
uniqueCountries: make(map[string]struct{}),
2021-09-17 00:01:43 +00:00
}
2021-11-03 20:24:23 +00:00
all, err := backend.All()
if err != nil {
//TODO: Handle better maybe?
panic(err)
}
2022-08-26 10:21:52 +00:00
var loginCount int
2021-11-03 20:24:23 +00:00
2022-08-26 10:21:52 +00:00
for attempt := range all {
2021-11-03 20:24:23 +00:00
cs.uniqueUsernames[attempt.Username] = struct{}{}
cs.uniquePasswords[attempt.Password] = struct{}{}
cs.uniqueIPs[attempt.RemoteIP.String()] = struct{}{}
cs.uniqueCountries[attempt.Country] = struct{}{}
2022-08-26 10:21:52 +00:00
loginCount++
2021-11-03 20:24:23 +00:00
}
2022-08-26 10:21:52 +00:00
cs.totalLoginsCount = loginCount
2021-11-03 20:24:23 +00:00
return cs
2021-09-17 00:01:43 +00:00
}
func (s *CachingStore) AddAttempt(l *models.LoginAttempt) error {
s.totalStatsCache = nil
delete(s.ipQueryCache, l.RemoteIP.String())
delete(s.passwordQueryCache, l.Password)
delete(s.usernameQueryCache, l.Username)
2021-11-03 20:24:23 +00:00
s.totalLoginsCount++
s.uniqueUsernames[l.Username] = struct{}{}
s.uniquePasswords[l.Password] = struct{}{}
s.uniqueIPs[l.RemoteIP.String()] = struct{}{}
s.uniqueCountries[l.Country] = struct{}{}
2021-09-17 00:01:43 +00:00
return s.backend.AddAttempt(l)
}
2022-08-26 10:21:52 +00:00
func (s *CachingStore) All() (<-chan models.LoginAttempt, error) {
2021-09-17 00:01:43 +00:00
return s.backend.All()
}
func (s *CachingStore) Stats(statType LoginStats, limit int) ([]StatsResult, error) {
// Only cache totals for now, as they are the most queried
if statType == LoginStatsTotals {
2021-11-03 20:24:23 +00:00
return []StatsResult{
{Name: "UniquePasswords", Count: len(s.uniquePasswords)},
{Name: "UniqueUsernames", Count: len(s.uniqueUsernames)},
{Name: "UniqueIPs", Count: len(s.uniqueIPs)},
{Name: "UniqueCountries", Count: len(s.uniqueCountries)},
{Name: "TotalLoginAttempts", Count: s.totalLoginsCount},
}, nil
2021-09-17 00:01:43 +00:00
}
return s.backend.Stats(statType, limit)
}
func (s *CachingStore) Query(query AttemptQuery) ([]models.LoginAttempt, error) {
switch query.QueryType {
case AttemptQueryTypeIP:
if attempts, ok := s.ipQueryCache[query.Query]; ok {
return attempts, nil
}
case AttemptQueryTypePassword:
if attempts, ok := s.passwordQueryCache[query.Query]; ok {
return attempts, nil
}
case AttemptQueryTypeUsername:
if attempts, ok := s.usernameQueryCache[query.Query]; ok {
return attempts, nil
}
}
attempts, err := s.backend.Query(query)
if err != nil {
return attempts, err
}
switch query.QueryType {
case AttemptQueryTypeIP:
s.ipQueryCache[query.Query] = attempts
case AttemptQueryTypeUsername:
s.ipQueryCache[query.Query] = attempts
case AttemptQueryTypePassword:
s.ipQueryCache[query.Query] = attempts
}
return attempts, err
}
2021-11-05 23:37:28 +00:00
2021-11-05 23:41:27 +00:00
func (s *CachingStore) IsHealthy() error {
2021-11-05 23:37:28 +00:00
return s.backend.IsHealthy()
}