package api import ( "crypto/rand" "errors" "net/http" "time" "gardomatic.kleiax.de/internal/auth" "gardomatic.kleiax.de/internal/platform/validate" "gardomatic.kleiax.de/internal/storage" ) const authenticatedUserIDSessionKey = "authenticatedUserID" const ( accountSessionIDKey = "accountSessionID" accountSessionCreatedAtKey = "accountSessionCreatedAt" ) func (app *application) createSessionHandler(w http.ResponseWriter, r *http.Request) { var input struct { Email string `json:"email"` Password string `json:"password"` } err := app.readJSON(w, r, &input) if err != nil { app.badRequestResponse(w, r, err) return } v := validate.New() storage.ValidateEmail(v, input.Email) auth.ValidatePasswordPlaintext(v, input.Password) if !v.Valid() { app.failedValidationResponse(w, r, v.Errors) return } user, err := app.models.Users.GetByEmail(input.Email) if err != nil { switch { case errors.Is(err, storage.ErrRecordNotFound): app.invalidCredentialsResponse(w, r) default: app.serverErrorResponse(w, r, err) } return } match, err := user.Password.Matches(input.Password) if err != nil { app.serverErrorResponse(w, r, err) return } if !match { app.invalidCredentialsResponse(w, r) return } if err := app.sessions.RenewToken(r.Context()); err != nil { app.serverErrorResponse(w, r, err) return } app.sessions.Put(r.Context(), authenticatedUserIDSessionKey, user.ID) app.sessions.Put(r.Context(), accountSessionIDKey, rand.Text()) app.sessions.Put(r.Context(), accountSessionCreatedAtKey, time.Now().UTC().Unix()) if err := app.writeJSON(w, http.StatusCreated, envelope{"user": user}, nil); err != nil { app.serverErrorResponse(w, r, err) } } func (app *application) showSessionHandler(w http.ResponseWriter, r *http.Request) { user, found := app.contextGetAuthenticatedUser(r) if !found { app.authenticationRequiredResponse(w, r) return } if err := app.writeJSON(w, http.StatusOK, envelope{"user": user}, nil); err != nil { app.serverErrorResponse(w, r, err) } } func (app *application) deleteSessionHandler(w http.ResponseWriter, r *http.Request) { if err := app.sessions.Destroy(r.Context()); err != nil { app.serverErrorResponse(w, r, err) return } w.WriteHeader(http.StatusNoContent) }