// backend/handlers_auth.go package main import ( "encoding/json" "net/http" "scm.bstein.dev/bstein/Pegasus/backend/internal" ) type jellyfinClient interface { AuthenticateByName(username, password string) (internal.AuthResult, error) RefreshLibrary(userToken string) } func loginHandler(um *internal.UserMap, jf jellyfinClient) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var f struct { Username string `json:"username"` Password string `json:"password"` } if err := json.NewDecoder(r.Body).Decode(&f); err != nil { http.Error(w, "bad json", http.StatusBadRequest) return } res, err := jf.AuthenticateByName(f.Username, f.Password) if err != nil { http.Error(w, "invalid credentials", http.StatusUnauthorized) return } if _, err := um.Resolve(f.Username); err != nil { internal.Logf("login ok but map missing for %q (JF name=%q)", f.Username, res.User.Name) http.Error(w, "no mapping", http.StatusForbidden) return } if err := internal.SetSession(w, f.Username, res.AccessToken); err != nil { http.Error(w, "session error", http.StatusInternalServerError) return } writeJSON(w, map[string]any{"ok": true}) } } func logoutHandler() http.HandlerFunc { return func(w http.ResponseWriter, _ *http.Request) { internal.ClearSession(w) writeJSON(w, map[string]any{"ok": true}) } } func whoamiHandler(um *internal.UserMap) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cl, err := internal.CurrentUser(r) if err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } dr, err := um.Resolve(cl.Username) if err != nil { http.Error(w, "no mapping", http.StatusForbidden) return } all, _ := um.ResolveAll(cl.Username) writeJSON(w, map[string]any{ "username": cl.Username, "root": dr, "roots": all, }) } }