Compare commits

..

2 commits

Author SHA1 Message Date
1e99
b0baf85078 add endpoint to check if password exists 2024-10-30 00:36:53 +01:00
1e99
c8bbe24d4d add configurable clear interval 2024-10-30 00:25:53 +01:00
4 changed files with 48 additions and 11 deletions

View file

@ -26,6 +26,7 @@ func run() error {
mux.Handle("GET /", routes.ServeFiles(embedFS, "static")) mux.Handle("GET /", routes.ServeFiles(embedFS, "static"))
mux.Handle("POST /api/password", routes.CreatePassword(storage, 12*1024, base64.StdEncoding)) mux.Handle("POST /api/password", routes.CreatePassword(storage, 12*1024, base64.StdEncoding))
mux.Handle("GET /api/password/{id}", routes.GetPassword(storage, base64.StdEncoding)) mux.Handle("GET /api/password/{id}", routes.GetPassword(storage, base64.StdEncoding))
mux.Handle("HEAD /api/password/{id}", routes.HasPassword(storage))
address := os.Getenv("PASSED_ADDRESS") address := os.Getenv("PASSED_ADDRESS")
if address == "" { if address == "" {

24
routes/has_password.go Normal file
View file

@ -0,0 +1,24 @@
package routes
import (
"net/http"
"git.1e99.eu/1e99/passed/storage"
)
func HasPassword(store storage.Store) http.HandlerFunc {
return func(res http.ResponseWriter, req *http.Request) {
id := req.PathValue("id")
found, err := store.HasPassword(id)
if err != nil {
http.Error(res, "", http.StatusInternalServerError)
return
}
if found {
res.WriteHeader(http.StatusNoContent)
} else {
res.WriteHeader(http.StatusNotFound)
}
}
}

View file

@ -6,11 +6,12 @@ import (
"time" "time"
) )
func NewRamStore() Store { func NewRamStore(clearInterval time.Duration) Store {
store := &ram{ store := &ram{
passwords: make(map[string]entry), clearInterval: clearInterval,
lock: sync.Mutex{}, passwords: make(map[string]entry),
close: make(chan bool), lock: sync.Mutex{},
close: make(chan bool),
} }
go store.clearExpired() go store.clearExpired()
@ -18,9 +19,10 @@ func NewRamStore() Store {
} }
type ram struct { type ram struct {
passwords map[string]entry clearInterval time.Duration
lock sync.Mutex passwords map[string]entry
close chan bool lock sync.Mutex
close chan bool
} }
func (store *ram) CreatePassword(password []byte, expiresAt time.Time) (string, error) { func (store *ram) CreatePassword(password []byte, expiresAt time.Time) (string, error) {
@ -58,13 +60,21 @@ func (store *ram) GetPassword(id string) ([]byte, error) {
return password.password, nil return password.password, nil
} }
func (store *ram) HasPassword(id string) (bool, error) {
store.lock.Lock()
defer store.lock.Unlock()
_, found := store.passwords[id]
return found, nil
}
func (store *ram) Close() error { func (store *ram) Close() error {
store.close <- true store.close <- true
return nil return nil
} }
func (store *ram) clearExpired() error { func (store *ram) clearExpired() error {
ticker := time.NewTicker(20 * time.Second) ticker := time.NewTicker(store.clearInterval)
defer ticker.Stop() defer ticker.Stop()
for { for {
@ -73,7 +83,6 @@ func (store *ram) clearExpired() error {
return nil return nil
case <-ticker.C: case <-ticker.C:
store.lock.Lock() store.lock.Lock()
defer store.lock.Unlock()
time := time.Now() time := time.Now()
for id, password := range store.passwords { for id, password := range store.passwords {
@ -81,6 +90,8 @@ func (store *ram) clearExpired() error {
delete(store.passwords, id) delete(store.passwords, id)
} }
} }
store.lock.Unlock()
} }
} }
} }

View file

@ -21,6 +21,7 @@ type entry struct {
type Store interface { type Store interface {
CreatePassword(password []byte, expiresAt time.Time) (string, error) CreatePassword(password []byte, expiresAt time.Time) (string, error)
GetPassword(id string) ([]byte, error) GetPassword(id string) ([]byte, error)
HasPassword(id string) (bool, error)
Close() error Close() error
} }
@ -30,10 +31,10 @@ func NewStore() (Store, error) {
switch storeType { switch storeType {
case "ram": case "ram":
return NewRamStore(), nil return NewRamStore(20 * time.Second), 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(), nil return NewRamStore(20 * time.Second), nil
} }
} }