This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
nginx-ldap-auth/data/storage.go
Tiago Augusto Pimenta bdce35bc55 Refactor
2018-10-09 20:59:52 -03:00

132 lines
2.4 KiB
Go

package data
import (
"sort"
"sync"
"time"
)
type passtimer struct {
password string
timer *time.Timer
}
type userpass struct {
correct *passtimer
wrong []passtimer
}
type Storage struct {
passwords map[string]*userpass
lock sync.RWMutex
success time.Duration
wrong time.Duration
}
func NewStorage(success, wrong time.Duration) *Storage {
return &Storage{
passwords: map[string]*userpass{},
lock: sync.RWMutex{},
success: success,
wrong: wrong,
}
}
func (p *Storage) Get(username, password string) (bool, bool) {
p.lock.RLock()
defer p.lock.RUnlock()
data, found := p.passwords[username]
if !found {
return false, false
}
if data.correct != nil && (*data.correct).password == password {
return true, true
}
_, found = containsWrongPassword(data, password)
return false, found
}
func (p *Storage) Put(username, password string, ok bool) {
p.lock.Lock()
defer p.lock.Unlock()
data, found := p.passwords[username]
if !found {
data = &userpass{}
p.passwords[username] = data
}
timeout := p.wrong
if ok {
timeout = p.success
}
pass := passtimer{
password: password,
timer: time.AfterFunc(timeout, func() {
p.remove(username, password, ok)
}),
}
if ok {
if data.correct != nil {
data.correct.timer.Stop()
}
data.correct = &pass
} else {
pos, found := containsWrongPassword(data, password)
if found {
data.wrong[pos].timer.Stop()
} else {
data.wrong = append(data.wrong, passtimer{})
copy(data.wrong[pos+1:], data.wrong[pos:])
}
data.wrong[pos] = pass
}
}
func (p *Storage) remove(username, password string, ok bool) {
p.lock.Lock()
defer p.lock.Unlock()
data, found := p.passwords[username]
if !found {
return
}
if ok {
if data.correct != nil {
data.correct.timer.Stop()
data.correct = nil
}
} else {
pos, found := containsWrongPassword(data, password)
if found {
data.wrong[pos].timer.Stop()
data.wrong = data.wrong[:pos+copy(data.wrong[pos:], data.wrong[pos+1:])]
}
}
if data.correct == nil && len(data.wrong) == 0 {
delete(p.passwords, username)
}
}
func containsWrongPassword(data *userpass, password string) (int, bool) {
size := len(data.wrong)
if size == 0 {
return 0, false
}
pos := sort.Search(size, func(i int) bool {
return data.wrong[i].password >= password
})
return pos, pos < size &&
data.wrong[pos].password == password
}