diff --git a/main.go b/main.go index 31097be..08c5302 100644 --- a/main.go +++ b/main.go @@ -38,6 +38,7 @@ func main() { r := chi.NewRouter() r.Post("/user/register", s.Register) r.Post("/user/login", s.Login) - r.With(serve.WithPlayerID(sessions)).Get("/queue", s.Queue) + r.With(serve.WithSession(sessions)).Get("/user/me", s.Me) + r.With(serve.WithSession(sessions)).Get("/queue", s.Queue) http.ListenAndServe(":8080", r) } diff --git a/serve/session.go b/serve/session.go index e18fd70..abc1f25 100644 --- a/serve/session.go +++ b/serve/session.go @@ -34,25 +34,25 @@ func SetSession(w http.ResponseWriter, s player.Session) { }) } -// WithPlayerID is a middleware that adds a player ID to the request context +// WithSession is a middleware that adds a player ID to the request context // based on the session cookie content. If there is no such cookie, or its -// value is invalid, the request fails with a 403 error. -func WithPlayerID(sessions player.RowQuerier) func(http.Handler) http.Handler { +// value is invalid, the request fails with a 401 error. +func WithSession(sessions player.RowQuerier) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie(sessionCookie) if err != nil { - http.Error(w, "Forbidden", http.StatusForbidden) + http.Error(w, "unauthorized", http.StatusUnauthorized) return } id, err := player.ParseSession(c.Value) if err != nil { - http.Error(w, "Forbidden", http.StatusForbidden) + http.Error(w, "unauthorized", http.StatusUnauthorized) return } p, err := player.FromSession(r.Context(), sessions, id, time.Now()) if err != nil { - http.Error(w, "Forbidden", http.StatusForbidden) + http.Error(w, "unauthorized", http.StatusUnauthorized) return } ctx := with(r.Context(), p) @@ -61,7 +61,7 @@ func WithPlayerID(sessions player.RowQuerier) func(http.Handler) http.Handler { } } -// Player returns the player ID set by WithPlayerID in the request context. -func PlayerID(ctx context.Context) player.ID { - return value[player.ID](ctx) +// Session returns the session ID set by WithSession in the request context. +func Session(ctx context.Context) player.Session { + return value[player.Session](ctx) } diff --git a/server.go b/server.go index 4269386..96d8f6b 100644 --- a/server.go +++ b/server.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/json" "errors" "log/slog" "net/http" @@ -20,14 +21,14 @@ import ( type Server struct { l *lobby.Lobby - creds credsDB - sessions player.Execer + creds db + sessions db mu sync.Mutex pp map[player.ID]*websocket.Conn } -type credsDB interface { +type db interface { player.RowQuerier player.Execer } @@ -133,13 +134,32 @@ func (s *Server) Login(w http.ResponseWriter, r *http.Request) { slog.InfoContext(ctx, "logged in", "player", p, "id", id) } +func (s *Server) Me(w http.ResponseWriter, r *http.Request) { + id := serve.Session(r.Context()) + if id == (player.Session{}) { + panic("missing player ID") + } + p, err := player.FromSession(r.Context(), s.sessions, id, time.Now()) + if err != nil { + panic("session with no player id: " + err.Error()) + } + q := struct { + ID player.ID `json:"id"` + }{p} + json.NewEncoder(w).Encode(q) +} + // Queue connects players to games. The connection immediately upgrades. // This handler MUST be wrapped in [serve.WithPlayerID]. func (s *Server) Queue(w http.ResponseWriter, r *http.Request) { - p := serve.PlayerID(r.Context()) - if p == (player.ID{}) { + id := serve.Session(r.Context()) + if id == (player.Session{}) { panic("missing player ID") } + p, err := player.FromSession(r.Context(), s.sessions, id, time.Now()) + if p == (player.ID{}) { + panic("session with no player id: " + err.Error()) + } person, err := s.accept(w, r, p) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest)