Cleanup return codes and add docs comment for swagger

This commit is contained in:
Zoe Roux 2024-09-02 14:55:22 +02:00
parent 7b08afde06
commit 95da0184a0
No known key found for this signature in database
3 changed files with 48 additions and 15 deletions

View File

@ -16,7 +16,9 @@ import (
)
type LoginDto struct {
// Either the email or the username.
Login string `json:"login" validate:"required"`
// Password of the account.
Password string `json:"password" validate:"required"`
}
@ -25,12 +27,13 @@ type LoginDto struct {
// @Tags sessions
// @Accept json
// @Produce json
// @Param device query uuid false "The device the created session will be used on"
// @Param user body LoginDto false "Account informations"
// @Success 201 {object} dbc.Session
// @Failure 400 {object} problem.Problem "Invalid login body"
// @Failure 400 {object} problem.Problem "Invalid password"
// @Failure 404 {object} problem.Problem "Account does not exists"
// @Param device query string false "The device the created session will be used on"
// @Param login body LoginDto false "Account informations"
// @Success 201 {object} dbc.Session
// @Failure 400 {object} problem.Problem "Invalid login body"
// @Failure 403 {object} problem.Problem "Invalid password"
// @Failure 404 {object} problem.Problem "Account does not exists"
// @Failure 422 {object} problem.Problem "User does not have a password (registered via oidc, please login via oidc)"
// @Router /sessions [post]
func (h *Handler) Login(c echo.Context) error {
var req LoginDto
@ -47,7 +50,7 @@ func (h *Handler) Login(c echo.Context) error {
return echo.NewHTTPError(http.StatusNotFound, "No account exists with the specified email or username.")
}
if dbuser.Password == nil {
return echo.NewHTTPError(http.StatusBadRequest, "Can't login with password, this account was created with OIDC.")
return echo.NewHTTPError(http.StatusUnprocessableEntity, "Can't login with password, this account was created with OIDC.")
}
match, err := argon2id.ComparePasswordAndHash(req.Password, *dbuser.Password)
@ -55,7 +58,7 @@ func (h *Handler) Login(c echo.Context) error {
return err
}
if !match {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid password")
return echo.NewHTTPError(http.StatusForbidden, "Invalid password")
}
user := MapDbUser(&dbuser)
@ -88,9 +91,20 @@ func (h *Handler) createSession(c echo.Context, user *User) error {
return c.JSON(201, session)
}
// @Summary Get JWT
// @Description Convert a session token to a short lived JWT.
// @Tags sessions
// @Accept json
// @Produce json
// @Param user body LoginDto false "Account informations"
// @Success 200 {object} dbc.Session
// @Failure 400 {object} problem.Problem "Invalid login body"
// @Failure 400 {object} problem.Problem "Invalid password"
// @Failure 404 {object} problem.Problem "Account does not exists"
// @Router /jwt [get]
func (h *Handler) CreateJwt(c echo.Context, user *User) error {
claims := maps.Clone(user.Claims)
claims["sub"] = user.ID.String()
claims["sub"] = user.Id.String()
claims["iss"] = h.config.Issuer
claims["exp"] = &jwt.NumericDate{
Time: time.Now().UTC().Add(time.Hour),

View File

@ -1,11 +1,11 @@
-- name: GetUserFromSession :one
-- name: GetUserFromToken :one
select
u.*
from
users as u
left join sessions as s on u.id = s.user_id
where
s.id = $1
s.token = $1
limit 1;
-- name: TouchSession :exec
@ -27,7 +27,7 @@ order by
last_used;
-- name: CreateSession :one
insert into sessions(id, user_id, device)
insert into sessions(token, user_id, device)
values ($1, $2, $3)
returning
*;
@ -38,3 +38,9 @@ where id = $1
returning
*;
-- name: DeleteSessionByToken :one
delete from sessions
where token = $1
returning
*;

View File

@ -13,30 +13,43 @@ import (
)
type User struct {
ID uuid.UUID `json:"id"`
// Id of the user.
Id uuid.UUID `json:"id"`
// Username of the user. Can be used as a login.
Username string `json:"username"`
// Email of the user. Can be used as a login.
Email string `json:"email" format:"email"`
// When was this account created?
CreatedDate time.Time `json:"createdDate"`
// When was the last time this account made any authorized request?
LastSeen time.Time `json:"lastSeen"`
// List of custom claims JWT created via get /jwt will have
Claims jwt.MapClaims `json:"claims"`
// List of other login method available for this user. Access tokens wont be returned here.
Oidc map[string]OidcHandle `json:"oidc,omitempty"`
}
type OidcHandle struct {
// Id of this oidc handle.
Id string `json:"id"`
// Username of the user on the external service.
Username string `json:"username"`
// Link to the profile of the user on the external service. Null if unknown or irrelevant.
ProfileUrl *string `json:"profileUrl" format:"url"`
}
type RegisterDto struct {
// Username of the new account, can't contain @ signs. Can be used for login.
Username string `json:"username" validate:"required,excludes=@"`
// Valid email that could be used for forgotten password requests. Can be used for login.
Email string `json:"email" validate:"required,email" format:"email"`
// Password to use.
Password string `json:"password" validate:"required"`
}
func MapDbUser(user *dbc.User) User {
return User{
ID: user.ID,
Id: user.ID,
Username: user.Username,
Email: user.Email,
CreatedDate: user.CreatedDate,
@ -53,7 +66,7 @@ func MapDbUser(user *dbc.User) User {
// @Produce json
// @Param afterId query string false "used for pagination." Format(uuid)
// @Success 200 {object} User[]
// @Failure 400 {object} problem.Problem
// @Failure 400 {object} problem.Problem "Invalid after id"
// @Router /users [get]
func (h *Handler) ListUsers(c echo.Context) error {
ctx := context.Background()