mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
77 lines
1.5 KiB
Go
77 lines
1.5 KiB
Go
package captcha
|
|
|
|
import (
|
|
"container/list"
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type challenge struct {
|
|
id string
|
|
answer string
|
|
expiresAt time.Time
|
|
}
|
|
|
|
type memoryStore struct {
|
|
mu sync.Mutex
|
|
entries map[string]*list.Element
|
|
order *list.List
|
|
limit int
|
|
expiration time.Duration
|
|
now func() time.Time
|
|
}
|
|
|
|
func newMemoryStore(limit int, expiration time.Duration) *memoryStore {
|
|
return &memoryStore{
|
|
entries: make(map[string]*list.Element), order: list.New(),
|
|
limit: limit, expiration: expiration, now: time.Now,
|
|
}
|
|
}
|
|
|
|
func (s *memoryStore) put(id, answer string) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
now := s.now()
|
|
s.removeExpired(now)
|
|
if len(s.entries) >= s.limit {
|
|
return errors.New("captcha store is full")
|
|
}
|
|
if _, exists := s.entries[id]; exists {
|
|
return errors.New("captcha ID already exists")
|
|
}
|
|
s.entries[id] = s.order.PushBack(challenge{id: id, answer: answer, expiresAt: now.Add(s.expiration)})
|
|
return nil
|
|
}
|
|
|
|
func (s *memoryStore) consume(id string) string {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
now := s.now()
|
|
s.removeExpired(now)
|
|
e, ok := s.entries[id]
|
|
if !ok {
|
|
return ""
|
|
}
|
|
value := e.Value.(challenge)
|
|
s.remove(e)
|
|
if !now.Before(value.expiresAt) {
|
|
return ""
|
|
}
|
|
return value.answer
|
|
}
|
|
|
|
func (s *memoryStore) removeExpired(now time.Time) {
|
|
for e := s.order.Front(); e != nil; e = s.order.Front() {
|
|
if now.Before(e.Value.(challenge).expiresAt) {
|
|
return
|
|
}
|
|
s.remove(e)
|
|
}
|
|
}
|
|
|
|
func (s *memoryStore) remove(e *list.Element) {
|
|
delete(s.entries, e.Value.(challenge).id)
|
|
s.order.Remove(e)
|
|
}
|