91 lines
1.4 KiB
Go
91 lines
1.4 KiB
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"math/rand/v2"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func NewRamStore() Store {
|
||
|
store := &ram{
|
||
|
passwords: make(map[string]entry),
|
||
|
lock: sync.Mutex{},
|
||
|
}
|
||
|
|
||
|
go func() {
|
||
|
ticker := time.Tick(25 * time.Second)
|
||
|
|
||
|
for {
|
||
|
store.clearExpired()
|
||
|
<-ticker
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
return store
|
||
|
}
|
||
|
|
||
|
type ram struct {
|
||
|
passwords map[string]entry
|
||
|
lock sync.Mutex
|
||
|
}
|
||
|
|
||
|
func (store *ram) CreatePassword(password []byte, expiresAt time.Time) (string, error) {
|
||
|
store.lock.Lock()
|
||
|
defer store.lock.Unlock()
|
||
|
|
||
|
for range 1000 {
|
||
|
id := store.generateId(24)
|
||
|
_, found := store.passwords[id]
|
||
|
if found {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
store.passwords[id] = entry{
|
||
|
password: password,
|
||
|
expiresAt: expiresAt,
|
||
|
}
|
||
|
|
||
|
return id, nil
|
||
|
}
|
||
|
|
||
|
return "", ErrFull
|
||
|
}
|
||
|
|
||
|
func (store *ram) GetPassword(id string) ([]byte, error) {
|
||
|
store.lock.Lock()
|
||
|
defer store.lock.Unlock()
|
||
|
|
||
|
password, found := store.passwords[id]
|
||
|
if !found {
|
||
|
return nil, ErrNotFound
|
||
|
}
|
||
|
|
||
|
delete(store.passwords, id)
|
||
|
return password.password, nil
|
||
|
}
|
||
|
|
||
|
func (store *ram) clearExpired() error {
|
||
|
store.lock.Lock()
|
||
|
defer store.lock.Unlock()
|
||
|
time := time.Now()
|
||
|
|
||
|
for id, password := range store.passwords {
|
||
|
if time.After(password.expiresAt) {
|
||
|
delete(store.passwords, id)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (store *ram) generateId(length int) string {
|
||
|
runes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||
|
|
||
|
str := make([]rune, length)
|
||
|
for i := range str {
|
||
|
str[i] = runes[rand.IntN(len(runes))]
|
||
|
}
|
||
|
|
||
|
return string(str)
|
||
|
}
|