// account-api ist der Aufrufpunkt fuer IAM-16: setzt die bereits fertigen // IAM-08-Handler (internal/auth, internal/authtoken, internal/totp) zu // einem laufenden Login/Account-HTTP-Dienst zusammen. REINES WIRING — // keine Aenderung an den bestehenden Paketen. Tenant-gescoped (Modell C): // ein Dienst pro Mandanten-Datenbank, wie internal/auth.LoginService es // bereits vorsieht. package main import ( "context" "log" "net/http" "os" "github.com/jackc/pgx/v5/pgxpool" "gitea.perlbach24.de/scripte/nexarch/internal/auth" "gitea.perlbach24.de/scripte/nexarch/internal/authtoken" "gitea.perlbach24.de/scripte/nexarch/internal/totp" "gitea.perlbach24.de/scripte/nexarch/internal/user" ) func requireEnv(name string) string { v := os.Getenv(name) if v == "" { log.Fatalf("%s muss gesetzt sein", name) } return v } func main() { dsn := requireEnv("NEXARCH_ACCOUNT_TENANT_DSN") tenantSlug := requireEnv("NEXARCH_ACCOUNT_TENANT_SLUG") jwtSecret := requireEnv("NEXARCH_ACCOUNT_JWT_SECRET") totpIssuer := os.Getenv("NEXARCH_ACCOUNT_TOTP_ISSUER") if totpIssuer == "" { totpIssuer = "NEXARCH" } addr := os.Getenv("NEXARCH_ACCOUNT_API_LISTEN_ADDR") if addr == "" { addr = "127.0.0.1:8099" } ctx := context.Background() pool, err := pgxpool.New(ctx, dsn) if err != nil { log.Fatalf("datenbankverbindung: %v", err) } defer pool.Close() users := user.NewTenantUserStore(pool) totpStore := totp.NewStore(pool) tokenIssuer := auth.NewTokenIssuer(jwtSecret) loginService := auth.NewLoginService(users, tokenIssuer, tenantSlug) authHandler := auth.NewHandler(loginService) totpHandler := totp.NewHandler(users, totpStore, loginService, totpIssuer) profileHandler := auth.NewProfileHandler(users) changePasswordHandler := auth.NewChangePasswordHandler(users) resetStore := authtoken.NewStore(pool) resetHandler := authtoken.NewHandler(resetStore, users, authtoken.LogNotifier{}) mux := http.NewServeMux() mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) // Login ist DER EINE Endpunkt, den das Frontend aufruft (deckt 2FA // optional mit ab) — siehe internal/totp/handler.go-Dokumentation. mux.HandleFunc("POST /auth/login", totpHandler.Login) mux.HandleFunc("POST /auth/logout", authHandler.Logout) mux.HandleFunc("POST /auth/password-reset/request", resetHandler.RequestReset) mux.HandleFunc("POST /auth/password-reset/complete", resetHandler.CompleteReset) mux.HandleFunc("GET /account/me", auth.RequireAuth(tokenIssuer, profileHandler.Me)) mux.HandleFunc("POST /account/change-password", auth.RequireAuth(tokenIssuer, changePasswordHandler.ChangePassword)) mux.HandleFunc("GET /auth/totp/status", auth.RequireAuth(tokenIssuer, totpHandler.Status)) mux.HandleFunc("POST /auth/totp/setup/begin", auth.RequireAuth(tokenIssuer, totpHandler.SetupBegin)) mux.HandleFunc("POST /auth/totp/setup/confirm", auth.RequireAuth(tokenIssuer, totpHandler.SetupConfirm)) log.Printf("account-api: listening on %s (tenant %s)", addr, tenantSlug) if err := http.ListenAndServe(addr, mux); err != nil { log.Fatalf("http server: %v", err) } }