rework password expiration cleaning
This commit is contained in:
parent
e3805b1a04
commit
aaa1715f32
4 changed files with 69 additions and 90 deletions
15
main.go
15
main.go
|
@ -22,7 +22,20 @@ func run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer storage.Close()
|
go func() {
|
||||||
|
ticker := time.Tick(20 * time.Second)
|
||||||
|
for {
|
||||||
|
<-ticker
|
||||||
|
|
||||||
|
err := storage.ClearExpired()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to clear expired passwords: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Cleared expired passwords.")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("GET /", routes.ServeFiles(embedFS, "static"))
|
mux.Handle("GET /", routes.ServeFiles(embedFS, "static"))
|
||||||
|
|
|
@ -8,23 +8,16 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDirStore(clearInterval time.Duration, path string) Store {
|
func NewDirStore(path string) Store {
|
||||||
store := &dir{
|
store := &dir{
|
||||||
clearInterval: clearInterval,
|
path: path,
|
||||||
timeLayout: time.RFC3339Nano,
|
|
||||||
path: path,
|
|
||||||
close: make(chan bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go store.clearExpired()
|
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
type dir struct {
|
type dir struct {
|
||||||
clearInterval time.Duration
|
path string
|
||||||
timeLayout string
|
|
||||||
path string
|
|
||||||
close chan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *dir) Create(password []byte, expiresAt time.Time) (string, error) {
|
func (store *dir) Create(password []byte, expiresAt time.Time) (string, error) {
|
||||||
|
@ -98,56 +91,45 @@ func (store *dir) Delete(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *dir) Close() error {
|
func (store *dir) ClearExpired() error {
|
||||||
store.close <- true
|
now := time.Now()
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (store *dir) clearExpired() error {
|
entries, err := os.ReadDir(store.path)
|
||||||
ticker := time.NewTicker(store.clearInterval)
|
if err != nil {
|
||||||
defer ticker.Stop()
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for _, file := range entries {
|
||||||
select {
|
id := file.Name()
|
||||||
case <-store.close:
|
path := store.getPath(id)
|
||||||
return nil
|
file, err := os.OpenFile(
|
||||||
case <-ticker.C:
|
path,
|
||||||
// TODO: Error handling?
|
os.O_RDONLY,
|
||||||
now := time.Now()
|
0,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
entries, err := os.ReadDir(store.path)
|
defer file.Close()
|
||||||
|
|
||||||
|
var entry entry
|
||||||
|
err = gob.NewDecoder(file).Decode(&entry)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if now.After(entry.ExpiresAt) {
|
||||||
|
// Close file early as we need to delete it
|
||||||
|
file.Close()
|
||||||
|
err = store.Delete(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range entries {
|
|
||||||
id := file.Name()
|
|
||||||
path := store.getPath(id)
|
|
||||||
file, err := os.OpenFile(
|
|
||||||
path,
|
|
||||||
os.O_RDONLY,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
var entry entry
|
|
||||||
err = gob.NewDecoder(file).Decode(&entry)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if now.After(entry.ExpiresAt) {
|
|
||||||
// Close file early as we need to delete it
|
|
||||||
file.Close()
|
|
||||||
store.Delete(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *dir) getPath(id string) string {
|
func (store *dir) getPath(id string) string {
|
||||||
|
|
|
@ -5,23 +5,18 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewRamStore(clearInterval time.Duration) Store {
|
func NewRamStore() Store {
|
||||||
store := &ram{
|
store := &ram{
|
||||||
clearInterval: clearInterval,
|
passwords: make(map[string]entry),
|
||||||
passwords: make(map[string]entry),
|
lock: sync.Mutex{},
|
||||||
lock: sync.Mutex{},
|
|
||||||
close: make(chan bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go store.clearExpired()
|
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
type ram struct {
|
type ram struct {
|
||||||
clearInterval time.Duration
|
passwords map[string]entry
|
||||||
passwords map[string]entry
|
lock sync.Mutex
|
||||||
lock sync.Mutex
|
|
||||||
close chan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *ram) Create(password []byte, expiresAt time.Time) (string, error) {
|
func (store *ram) Create(password []byte, expiresAt time.Time) (string, error) {
|
||||||
|
@ -63,30 +58,19 @@ func (store *ram) Delete(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *ram) Close() error {
|
func (store *ram) ClearExpired() error {
|
||||||
store.close <- true
|
store.lock.Lock()
|
||||||
return nil
|
defer store.lock.Unlock()
|
||||||
}
|
time := time.Now()
|
||||||
|
|
||||||
func (store *ram) clearExpired() error {
|
for id, password := range store.passwords {
|
||||||
ticker := time.NewTicker(store.clearInterval)
|
if time.After(password.ExpiresAt) {
|
||||||
defer ticker.Stop()
|
err := store.Delete(id)
|
||||||
|
if err != nil {
|
||||||
for {
|
return err
|
||||||
select {
|
|
||||||
case <-store.close:
|
|
||||||
return nil
|
|
||||||
case <-ticker.C:
|
|
||||||
store.lock.Lock()
|
|
||||||
time := time.Now()
|
|
||||||
|
|
||||||
for id, password := range store.passwords {
|
|
||||||
if time.After(password.ExpiresAt) {
|
|
||||||
store.Delete(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store.lock.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ type Store interface {
|
||||||
Create(password []byte, expiresAt time.Time) (string, error)
|
Create(password []byte, expiresAt time.Time) (string, error)
|
||||||
Get(id string) ([]byte, error)
|
Get(id string) ([]byte, error)
|
||||||
Delete(id string) error
|
Delete(id string) error
|
||||||
Close() error
|
ClearExpired() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore() (Store, error) {
|
func NewStore() (Store, error) {
|
||||||
|
@ -32,7 +32,7 @@ func NewStore() (Store, error) {
|
||||||
|
|
||||||
switch storeType {
|
switch storeType {
|
||||||
case "ram":
|
case "ram":
|
||||||
return NewRamStore(20 * time.Second), nil
|
return NewRamStore(), nil
|
||||||
case "dir":
|
case "dir":
|
||||||
path := os.Getenv("PASSED_STORE_DIR_PATH")
|
path := os.Getenv("PASSED_STORE_DIR_PATH")
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
@ -40,11 +40,11 @@ func NewStore() (Store, error) {
|
||||||
path = "passwords"
|
path = "passwords"
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewDirStore(60*time.Second, path), nil
|
return NewDirStore(path), nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Printf("No PASSED_STORE_TYPE provided, defaulting to memory store.")
|
log.Printf("No PASSED_STORE_TYPE provided, defaulting to memory store.")
|
||||||
return NewRamStore(20 * time.Second), nil
|
return NewRamStore(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue