rework environment variables
This commit is contained in:
parent
1599edb83c
commit
d6e016719a
3 changed files with 91 additions and 62 deletions
37
config/config.go
Normal file
37
config/config.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Env(name string, out any, def string) {
|
||||||
|
raw := os.Getenv(name)
|
||||||
|
if raw == "" {
|
||||||
|
raw = def
|
||||||
|
log.Printf("No \"%s\" provided, defaulting to \"%s\".", name, def)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := out.(type) {
|
||||||
|
case *int:
|
||||||
|
i, err := strconv.ParseInt(raw, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("\"%s\" is not a number.", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = int(i)
|
||||||
|
|
||||||
|
case *bool:
|
||||||
|
switch raw {
|
||||||
|
case "true", "TRUE", "1":
|
||||||
|
*value = true
|
||||||
|
case "false", "FALSE", "0":
|
||||||
|
*value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
case *string:
|
||||||
|
*value = raw
|
||||||
|
}
|
||||||
|
}
|
91
main.go
91
main.go
|
@ -3,12 +3,12 @@ package main
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.1e99.eu/1e99/passed/config"
|
||||||
"git.1e99.eu/1e99/passed/middlewares"
|
"git.1e99.eu/1e99/passed/middlewares"
|
||||||
"git.1e99.eu/1e99/passed/routes"
|
"git.1e99.eu/1e99/passed/routes"
|
||||||
"git.1e99.eu/1e99/passed/storage"
|
"git.1e99.eu/1e99/passed/storage"
|
||||||
|
@ -18,21 +18,63 @@ import (
|
||||||
var embedFS embed.FS
|
var embedFS embed.FS
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
storage, err := storage.NewStore()
|
storage, err := newStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
clearIntervalString := os.Getenv("STORE_CLEAR_EXPIRED_INTERVAL")
|
var address string
|
||||||
if clearIntervalString == "" {
|
var logRequests bool
|
||||||
log.Printf("No STORE_CLEAR_EXPIRED_INTERVAL provided, defaulting to 30 seconds.")
|
var maxPasswordLength int
|
||||||
clearIntervalString = "30"
|
config.Env("PASSED_ADDRESS", &address, ":3000")
|
||||||
|
config.Env("PASSED_LOG_REQUESTS", &logRequests, "true")
|
||||||
|
config.Env("PASSED_MAX_LENGTH", &maxPasswordLength, "12288")
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
handler := http.Handler(mux)
|
||||||
|
|
||||||
|
mux.Handle("GET /", routes.ServeFiles(embedFS, "static"))
|
||||||
|
mux.Handle(
|
||||||
|
"POST /api/password",
|
||||||
|
middlewares.RateLimiter(
|
||||||
|
routes.CreatePassword(storage, maxPasswordLength, base64.StdEncoding),
|
||||||
|
1*time.Minute,
|
||||||
|
5,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
mux.Handle("GET /api/password/{id}", routes.GetPassword(storage, base64.StdEncoding))
|
||||||
|
mux.Handle("HEAD /api/password/{id}", routes.HasPassword(storage))
|
||||||
|
|
||||||
|
if logRequests {
|
||||||
|
handler = middlewares.Logger(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInterval, err := strconv.ParseInt(clearIntervalString, 10, 64)
|
log.Printf("Listening on %s.", address)
|
||||||
|
err = http.ListenAndServe(address, handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("STORE_CLEAR_EXPIRED_INTERVAL is not a number.")
|
return err
|
||||||
clearInterval = 30
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStore() (store storage.Store, err error) {
|
||||||
|
var storeType string
|
||||||
|
var clearInterval int
|
||||||
|
config.Env("PASSED_STORE", &storeType, "ram")
|
||||||
|
config.Env("PASSED_STORE_CLEAR_INTERVAL", &clearInterval, "30")
|
||||||
|
|
||||||
|
switch storeType {
|
||||||
|
case "ram":
|
||||||
|
store = storage.NewRamStore()
|
||||||
|
case "dir", "directory":
|
||||||
|
var path string
|
||||||
|
config.Env("PASSED_STORE_DIR_PATH", &path, "passwords")
|
||||||
|
|
||||||
|
store = storage.NewDirStore(path)
|
||||||
|
default:
|
||||||
|
err = errors.New("unknown storage type")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -40,7 +82,7 @@ func run() error {
|
||||||
for {
|
for {
|
||||||
<-ticker
|
<-ticker
|
||||||
|
|
||||||
err := storage.ClearExpired()
|
err := store.ClearExpired()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to clear expired passwords: %s", err)
|
log.Printf("Failed to clear expired passwords: %s", err)
|
||||||
continue
|
continue
|
||||||
|
@ -50,32 +92,7 @@ func run() error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
return
|
||||||
mux.Handle("GET /", routes.ServeFiles(embedFS, "static"))
|
|
||||||
mux.Handle(
|
|
||||||
"POST /api/password",
|
|
||||||
middlewares.RateLimiter(
|
|
||||||
routes.CreatePassword(storage, 12*1024, base64.StdEncoding),
|
|
||||||
1*time.Minute,
|
|
||||||
5,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
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")
|
|
||||||
if address == "" {
|
|
||||||
log.Printf("No PASSED_ADDRESS provided, defaulting to \":3000\"")
|
|
||||||
address = ":3000"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Listening on %s", address)
|
|
||||||
err = http.ListenAndServe(address, middlewares.Logger(mux))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -2,10 +2,7 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,28 +18,6 @@ type Store interface {
|
||||||
ClearExpired() error
|
ClearExpired() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore() (Store, error) {
|
|
||||||
storeType := os.Getenv("PASSED_STORE_TYPE")
|
|
||||||
storeType = strings.ToLower(storeType)
|
|
||||||
|
|
||||||
switch storeType {
|
|
||||||
case "ram":
|
|
||||||
return NewRamStore(), nil
|
|
||||||
case "dir":
|
|
||||||
path := os.Getenv("PASSED_STORE_DIR_PATH")
|
|
||||||
if path == "" {
|
|
||||||
log.Printf("No PASSED_STORE_DIR_PATH provided, defaulting to \"passwords\".")
|
|
||||||
path = "passwords"
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewDirStore(path), nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
log.Printf("No PASSED_STORE_TYPE provided, defaulting to memory store.")
|
|
||||||
return NewRamStore(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateId(length int) string {
|
func generateId(length int) string {
|
||||||
runes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
runes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue