Remove unused code
This commit is contained in:
@@ -1,235 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.t-juice.club/torjus/apiary/models"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
// var _ LoginAttemptStore = &BBoltStore{}
|
||||
|
||||
var bktKeyLogins []byte = []byte("logins")
|
||||
|
||||
type BBoltStore struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
func NewBBoltStore(path string) (*BBoltStore, error) {
|
||||
db, err := bolt.Open(path, 0o666, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening database: %w", err)
|
||||
}
|
||||
|
||||
var store BBoltStore
|
||||
store.db = db
|
||||
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(bktKeyLogins)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating database bucket: %w", err)
|
||||
}
|
||||
|
||||
return &store, nil
|
||||
}
|
||||
|
||||
func (s *BBoltStore) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
func (s *BBoltStore) AddAttempt(l *models.LoginAttempt) error {
|
||||
data, err := json.Marshal(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(bktKeyLogins)
|
||||
seq, err := bkt.NextSequence()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := itob(seq)
|
||||
return bkt.Put(key, data)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BBoltStore) All() (<-chan models.LoginAttempt, error) {
|
||||
ch := make(chan models.LoginAttempt)
|
||||
|
||||
go func() {
|
||||
_ = s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(bktKeyLogins)
|
||||
|
||||
c := bkt.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
var l models.LoginAttempt
|
||||
if err := json.Unmarshal(v, &l); err != nil {
|
||||
close(ch)
|
||||
panic(err)
|
||||
}
|
||||
ch <- l
|
||||
}
|
||||
|
||||
close(ch)
|
||||
|
||||
return nil
|
||||
})
|
||||
}()
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (s *BBoltStore) Stats(statType LoginStats, limit int) ([]StatsResult, error) {
|
||||
if statType == LoginStatsTotals {
|
||||
return s.statTotals()
|
||||
}
|
||||
|
||||
counts := make(map[string]int)
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(bktKeyLogins)
|
||||
|
||||
c := bkt.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
var l models.LoginAttempt
|
||||
if err := json.Unmarshal(v, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch statType {
|
||||
case LoginStatsPasswords:
|
||||
counts[l.Password]++
|
||||
case LoginStatsCountry:
|
||||
counts[l.Country]++
|
||||
case LoginStatsIP:
|
||||
counts[l.RemoteIP.String()]++
|
||||
case LoginStatsUsername:
|
||||
counts[l.Username]++
|
||||
default:
|
||||
return fmt.Errorf("invalid stat type")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating stats: %w", err)
|
||||
}
|
||||
|
||||
if limit < 1 {
|
||||
return toResults(counts), nil
|
||||
}
|
||||
if limit >= len(counts) {
|
||||
return toResults(counts), nil
|
||||
}
|
||||
|
||||
var si StatItems
|
||||
for key := range counts {
|
||||
si = append(si, StatItem{Key: key, Count: counts[key]})
|
||||
}
|
||||
sort.Sort(si)
|
||||
|
||||
output := make(map[string]int)
|
||||
for i := len(si) - 1; i > len(si)-limit-1; i-- {
|
||||
output[si[i].Key] = si[i].Count
|
||||
}
|
||||
|
||||
return toResults(output), nil
|
||||
}
|
||||
|
||||
func (s *BBoltStore) statTotals() ([]StatsResult, error) {
|
||||
passwords := make(map[string]int)
|
||||
usernames := make(map[string]int)
|
||||
ips := make(map[string]int)
|
||||
countries := make(map[string]int)
|
||||
var count int
|
||||
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(bktKeyLogins)
|
||||
|
||||
c := bkt.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
var l models.LoginAttempt
|
||||
if err := json.Unmarshal(v, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
passwords[l.Password] += 1
|
||||
usernames[l.Username] += 1
|
||||
ips[l.RemoteIP.String()] += 1
|
||||
countries[l.Country] += 1
|
||||
count++
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := []StatsResult{
|
||||
{Name: "UniquePasswords", Count: len(passwords)},
|
||||
{Name: "UniqueUsernames", Count: len(usernames)},
|
||||
{Name: "UniqueIPs", Count: len(ips)},
|
||||
{Name: "UniqueCountries", Count: len(countries)},
|
||||
{Name: "TotalLoginAttempts", Count: count},
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (s *BBoltStore) Query(query AttemptQuery) ([]models.LoginAttempt, error) {
|
||||
var results []models.LoginAttempt
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(bktKeyLogins)
|
||||
|
||||
c := bkt.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
var l models.LoginAttempt
|
||||
if err := json.Unmarshal(v, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch query.QueryType {
|
||||
case AttemptQueryTypeIP:
|
||||
if l.RemoteIP.String() == query.Query {
|
||||
results = append(results, l)
|
||||
}
|
||||
case AttemptQueryTypePassword:
|
||||
if strings.Contains(l.Password, query.Query) {
|
||||
results = append(results, l)
|
||||
}
|
||||
case AttemptQueryTypeUsername:
|
||||
if strings.Contains(l.Username, query.Query) {
|
||||
results = append(results, l)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s *BBoltStore) IsHealthy() error {
|
||||
// TODO: Do actual healthcheck
|
||||
return nil
|
||||
}
|
||||
|
||||
func itob(v uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, v)
|
||||
return b
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package store_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"git.t-juice.club/torjus/apiary/honeypot/ssh/store"
|
||||
)
|
||||
|
||||
func TestBBoltStore(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
f, err := os.CreateTemp(dir, "apiary-test-bbolt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fname := f.Name()
|
||||
f.Close()
|
||||
s, err := store.NewBBoltStore(fname)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testLoginAttemptStore(s, t)
|
||||
}
|
||||
|
||||
func FuzzBBoltStore(f *testing.F) {
|
||||
dir := f.TempDir()
|
||||
file, err := os.CreateTemp(dir, "apiary-test-bbolt")
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
fname := file.Name()
|
||||
file.Close()
|
||||
s, err := store.NewBBoltStore(fname)
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
fuzzLoginAttemptStore(s, f)
|
||||
}
|
Reference in New Issue
Block a user