package handlers import ( "encoding/json" "net/http" "strings" ) const minPasswordLength = 8 // HandleRegister creates a new user with a password. func (hdlr *Handlers) HandleRegister() http.HandlerFunc { return func( writer http.ResponseWriter, request *http.Request, ) { request.Body = http.MaxBytesReader( writer, request.Body, hdlr.maxBodySize(), ) hdlr.handleRegister(writer, request) } } func (hdlr *Handlers) handleRegister( writer http.ResponseWriter, request *http.Request, ) { type registerRequest struct { Nick string `json:"nick"` Password string `json:"password"` } var payload registerRequest err := json.NewDecoder(request.Body).Decode(&payload) if err != nil { hdlr.respondError( writer, request, "invalid request body", http.StatusBadRequest, ) return } payload.Nick = strings.TrimSpace(payload.Nick) if !validNickRe.MatchString(payload.Nick) { hdlr.respondError( writer, request, "invalid nick format", http.StatusBadRequest, ) return } if len(payload.Password) < minPasswordLength { hdlr.respondError( writer, request, "password must be at least 8 characters", http.StatusBadRequest, ) return } sessionID, clientID, token, err := hdlr.params.Database.RegisterUser( request.Context(), payload.Nick, payload.Password, ) if err != nil { hdlr.handleRegisterError( writer, request, err, ) return } hdlr.deliverMOTD(request, clientID, sessionID) hdlr.respondJSON(writer, request, map[string]any{ "id": sessionID, "nick": payload.Nick, "token": token, }, http.StatusCreated) } func (hdlr *Handlers) handleRegisterError( writer http.ResponseWriter, request *http.Request, err error, ) { if strings.Contains(err.Error(), "UNIQUE") { hdlr.respondError( writer, request, "nick already taken", http.StatusConflict, ) return } hdlr.log.Error( "register user failed", "error", err, ) hdlr.respondError( writer, request, "internal error", http.StatusInternalServerError, ) } // HandleLogin authenticates a user with nick and password. func (hdlr *Handlers) HandleLogin() http.HandlerFunc { return func( writer http.ResponseWriter, request *http.Request, ) { request.Body = http.MaxBytesReader( writer, request.Body, hdlr.maxBodySize(), ) hdlr.handleLogin(writer, request) } } func (hdlr *Handlers) handleLogin( writer http.ResponseWriter, request *http.Request, ) { type loginRequest struct { Nick string `json:"nick"` Password string `json:"password"` } var payload loginRequest err := json.NewDecoder(request.Body).Decode(&payload) if err != nil { hdlr.respondError( writer, request, "invalid request body", http.StatusBadRequest, ) return } payload.Nick = strings.TrimSpace(payload.Nick) if payload.Nick == "" || payload.Password == "" { hdlr.respondError( writer, request, "nick and password required", http.StatusBadRequest, ) return } sessionID, _, token, err := hdlr.params.Database.LoginUser( request.Context(), payload.Nick, payload.Password, ) if err != nil { hdlr.respondError( writer, request, "invalid credentials", http.StatusUnauthorized, ) return } hdlr.respondJSON(writer, request, map[string]any{ "id": sessionID, "nick": payload.Nick, "token": token, }, http.StatusOK) }