feat(admin): sessions, staff auth and adminctl

One Redis session store and one cookie for all three identities. Staff
login returns the same error for every failure mode and spends a bcrypt
comparison against a dummy hash when no user exists, so neither the message
nor the timing confirms which addresses have accounts.

Staff users are created only by adminctl. There is no signup endpoint: a
licensing authority that can be joined over the internet is not one.

Pins gin and go-redis to the versions server/ already uses rather than the
latest tidy would pick.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrhid6
2026-07-25 19:05:28 +01:00
co-authored by Claude Opus 5
parent a636a48e07
commit 480a578deb
8 changed files with 496 additions and 3 deletions
+9
View File
@@ -11,6 +11,7 @@ import (
"time"
"github.com/joho/godotenv"
"github.com/mrhid6/vantage/admin/internal/auth"
"github.com/mrhid6/vantage/admin/internal/config"
"github.com/mrhid6/vantage/admin/internal/db"
"github.com/mrhid6/vantage/admin/internal/inject"
@@ -28,6 +29,14 @@ func main() {
licensing.SetSigningKey(cfg.SigningKey)
auth.InitRedis(cfg.RedisAddr)
pingCtx, pingCancel := context.WithTimeout(context.Background(), 10*time.Second)
if err := auth.Ping(pingCtx); err != nil {
pingCancel()
log.Fatalf("redis: %v", err)
}
pingCancel()
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
if err := db.Connect(ctx, cfg); err != nil {
cancel()