From c0126c203609dcf748a11b26225ebf49a918c0a6 Mon Sep 17 00:00:00 2001 From: jdl Date: Sat, 13 Jun 2026 15:18:17 +0200 Subject: [PATCH] Audit changes. --- hub/api/db/generated.go | 1 + hub/app.go | 13 +++++++++---- hub/errs/db.go | 1 + hub/handlers.go | 10 ++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/hub/api/db/generated.go b/hub/api/db/generated.go index ab8e095..6122628 100644 --- a/hub/api/db/generated.go +++ b/hub/api/db/generated.go @@ -69,6 +69,7 @@ func Config_UpdateFull( ) (err error) { Config_Sanitize(row) if err = Config_Validate(row); err != nil { + return err } diff --git a/hub/app.go b/hub/app.go index 2695d1a..516aae9 100644 --- a/hub/app.go +++ b/hub/app.go @@ -8,6 +8,7 @@ import ( "path/filepath" "vppn/hub/api" + "git.crumpington.com/lib/go/keyedmutex" "git.crumpington.com/lib/go/webutil" ) @@ -28,6 +29,9 @@ type App struct { mux *http.ServeMux tmpl map[string]*template.Template insecure bool + + // Per-remote address sign-in serialization lock. + signInLock keyedmutex.KeyedMutex[string] } func NewApp(conf Config) (*App, error) { @@ -37,10 +41,11 @@ func NewApp(conf Config) (*App, error) { } app := &App{ - api: api, - mux: http.NewServeMux(), - tmpl: webutil.ParseTemplateSet(templateFuncs, templateFS), - insecure: conf.Insecure, + api: api, + mux: http.NewServeMux(), + tmpl: webutil.ParseTemplateSet(templateFuncs, templateFS), + insecure: conf.Insecure, + signInLock: keyedmutex.New[string](), } app.registerRoutes() diff --git a/hub/errs/db.go b/hub/errs/db.go index 85e4b61..4d3eea5 100644 --- a/hub/errs/db.go +++ b/hub/errs/db.go @@ -28,6 +28,7 @@ func DB(err error) error { return ErrAlreadyExists } } + log.Printf("Unexpected error: %v", err) return ErrUnexpected } diff --git a/hub/handlers.go b/hub/handlers.go index c907f23..869c423 100644 --- a/hub/handlers.go +++ b/hub/handlers.go @@ -3,7 +3,9 @@ package hub import ( "encoding/json" "log" + "math/rand/v2" "net/http" + "time" "vppn/hub/api" "vppn/hub/errs" "vppn/m" @@ -26,6 +28,12 @@ func (a *App) _signin(s *api.Session, w http.ResponseWriter, r *http.Request) er } func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { + if !a.signInLock.TryLock(r.RemoteAddr) { + time.Sleep(time.Duration(rand.Int64N(int64(4 * time.Second)))) + return errs.ErrNotAuthorized + } + defer a.signInLock.Unlock(r.RemoteAddr) + var pwd string err := webutil.NewFormScanner(r.Form). Scan("Password", &pwd). @@ -36,8 +44,10 @@ func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Reque sess, err := a.api.Session_SignIn(pwd) if err != nil { + time.Sleep(time.Duration(rand.Int64N(int64(4 * time.Second)))) return err } + a.setCookie(w, sessionIDCookieName, sess.SessionID) return a.redirect(w, r, "/")