Add bearer token auth and clean up debug logging

- Bearer token auth via --token flag or DREAMDICT_TOKEN env var
- Timing-safe comparison with crypto/subtle
- /health exempt for monitoring without credentials
- 401 response for missing/invalid tokens
- Auth disabled when no token configured (backwards compatible)
- Remove debug logging from cetempublico loader

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-04-03 08:54:40 -07:00
parent 2cc1832439
commit 56e073f753
3 changed files with 58 additions and 11 deletions

View File

@@ -2,6 +2,7 @@ package main
import (
"context"
"crypto/subtle"
"encoding/json"
"flag"
"fmt"
@@ -22,6 +23,7 @@ func main() {
port := flag.Int("port", 0, "Listen port (default 7777)")
host := flag.String("host", "", "Listen host (default 127.0.0.1)")
dbPath := flag.String("db", "", "Path to dict.db")
token := flag.String("token", "", "Bearer token for API auth (or DREAMDICT_TOKEN env)")
logLevel := flag.String("log-level", "info", "Log level: debug, info, warn, error")
flag.Parse()
@@ -51,6 +53,10 @@ func main() {
}
}
if *token == "" {
*token = os.Getenv("DREAMDICT_TOKEN")
}
var level slog.Level
switch *logLevel {
case "debug":
@@ -102,9 +108,16 @@ func main() {
serverStart = time.Now()
addr := fmt.Sprintf("%s:%d", *host, *port)
var handler http.Handler = mux
if *token != "" {
handler = authMiddleware(*token, mux)
slog.Info("bearer token auth enabled")
}
srv := &http.Server{
Addr: addr,
Handler: loggingMiddleware(mux),
Handler: loggingMiddleware(handler),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
@@ -172,6 +185,22 @@ func loggingMiddleware(next http.Handler) http.Handler {
})
}
func authMiddleware(token string, next http.Handler) http.Handler {
expected := "Bearer " + token
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Health endpoint is exempt so monitoring works without credentials
if r.URL.Path == "/health" {
next.ServeHTTP(w, r)
return
}
if subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), []byte(expected)) != 1 {
writeError(w, 401, "unauthorized", "invalid or missing bearer token")
return
}
next.ServeHTTP(w, r)
})
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)