mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-23 17:52:36 -04:00
Add edit password
This commit is contained in:
parent
dbe8e319c8
commit
31d545530b
@ -12,6 +12,23 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const clearOtherSessions = `-- name: ClearOtherSessions :exec
|
||||
delete from sessions as s using users as u
|
||||
where s.user_pk = u.pk
|
||||
and s.id != $1
|
||||
and u.id = $2
|
||||
`
|
||||
|
||||
type ClearOtherSessionsParams struct {
|
||||
SessionId uuid.UUID `json:"sessionId"`
|
||||
UserId uuid.UUID `json:"userId"`
|
||||
}
|
||||
|
||||
func (q *Queries) ClearOtherSessions(ctx context.Context, arg ClearOtherSessionsParams) error {
|
||||
_, err := q.db.Exec(ctx, clearOtherSessions, arg.SessionId, arg.UserId)
|
||||
return err
|
||||
}
|
||||
|
||||
const createSession = `-- name: CreateSession :one
|
||||
insert into sessions(token, user_pk, device)
|
||||
values ($1, $2, $3)
|
||||
|
@ -417,6 +417,60 @@ const docTemplate = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/me/password": {
|
||||
"patch": {
|
||||
"security": [
|
||||
{
|
||||
"Jwt": []
|
||||
}
|
||||
],
|
||||
"description": "Edit your password",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "Edit password",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Invalidate other sessions",
|
||||
"name": "invalidate",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"description": "New password",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.EditPasswordDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -535,7 +589,7 @@ const docTemplate = `{
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "User id of the user to delete",
|
||||
"description": "User id of the user to edit",
|
||||
"name": "id",
|
||||
"in": "path"
|
||||
},
|
||||
@ -560,12 +614,30 @@ const docTemplate = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"main.EditPasswordDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "password1234"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main.EditUserDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -411,6 +411,60 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/me/password": {
|
||||
"patch": {
|
||||
"security": [
|
||||
{
|
||||
"Jwt": []
|
||||
}
|
||||
],
|
||||
"description": "Edit your password",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "Edit password",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Invalidate other sessions",
|
||||
"name": "invalidate",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"description": "New password",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.EditPasswordDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -529,7 +583,7 @@
|
||||
{
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "User id of the user to delete",
|
||||
"description": "User id of the user to edit",
|
||||
"name": "id",
|
||||
"in": "path"
|
||||
},
|
||||
@ -554,12 +608,30 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Invalid body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/main.KError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"main.EditPasswordDto": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "password1234"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main.EditUserDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -217,6 +217,7 @@ func main() {
|
||||
r.DELETE("/users/me", h.DeleteSelf)
|
||||
r.PATCH("/users/:id", h.EditUser)
|
||||
r.PATCH("/users/me", h.EditSelf)
|
||||
r.PATCH("/users/me/password", h.ChangePassword)
|
||||
g.POST("/users", h.Register)
|
||||
|
||||
g.POST("/sessions", h.Login)
|
||||
|
@ -43,3 +43,8 @@ where s.user_pk = u.pk
|
||||
returning
|
||||
s.*;
|
||||
|
||||
-- name: ClearOtherSessions :exec
|
||||
delete from sessions as s using users as u
|
||||
where s.user_pk = u.pk
|
||||
and s.id != @session_id
|
||||
and u.id = @user_id;
|
||||
|
@ -58,6 +58,10 @@ type EditUserDto struct {
|
||||
Claims jwt.MapClaims `json:"claims,omitempty" example:"preferOriginal: true"`
|
||||
}
|
||||
|
||||
type EditPasswordDto struct {
|
||||
Password string `json:"password" validate:"required" example:"password1234"`
|
||||
}
|
||||
|
||||
func MapDbUser(user *dbc.User) User {
|
||||
return User{
|
||||
Pk: user.Pk,
|
||||
@ -293,6 +297,7 @@ func (h *Handler) DeleteSelf(c echo.Context) error {
|
||||
// @Param user body EditUserDto false "Edited user info"
|
||||
// @Success 200 {object} User
|
||||
// @Success 403 {object} KError "You can't edit a protected claim"
|
||||
// @Success 422 {object} KError "Invalid body"
|
||||
// @Router /users/me [patch]
|
||||
func (h *Handler) EditSelf(c echo.Context) error {
|
||||
var req EditUserDto
|
||||
@ -340,6 +345,7 @@ func (h *Handler) EditSelf(c echo.Context) error {
|
||||
// @Param user body EditUserDto false "Edited user info"
|
||||
// @Success 200 {object} User
|
||||
// @Success 403 {object} KError "You don't have permissions to edit another account"
|
||||
// @Success 422 {object} KError "Invalid body"
|
||||
// @Router /users/{id} [patch]
|
||||
func (h *Handler) EditUser(c echo.Context) error {
|
||||
err := CheckPermissions(c, []string{"user.write"})
|
||||
@ -375,3 +381,55 @@ func (h *Handler) EditUser(c echo.Context) error {
|
||||
|
||||
return c.JSON(200, MapDbUser(&ret))
|
||||
}
|
||||
|
||||
// @Summary Edit password
|
||||
// @Description Edit your password
|
||||
// @Tags users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Jwt
|
||||
// @Param invalidate query bool false "Invalidate other sessions" default(true)
|
||||
// @Param user body EditPasswordDto false "New password"
|
||||
// @Success 204
|
||||
// @Success 422 {object} KError "Invalid body"
|
||||
// @Router /users/me/password [patch]
|
||||
func (h *Handler) ChangePassword(c echo.Context) error {
|
||||
uid, err := GetCurrentUserId(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sid, err := GetCurrentSessionId(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req EditPasswordDto
|
||||
err = c.Bind(&req)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error())
|
||||
}
|
||||
if err = c.Validate(&req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = h.db.UpdateUser(context.Background(), dbc.UpdateUserParams{
|
||||
Id: uid,
|
||||
Password: &req.Password,
|
||||
})
|
||||
if err == pgx.ErrNoRows {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "Invalid token, user not found")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = h.db.ClearOtherSessions(context.Background(), dbc.ClearOtherSessionsParams{
|
||||
SessionId: sid,
|
||||
UserId: uid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
@ -28,6 +28,32 @@ func GetCurrentUserId(c echo.Context) (uuid.UUID, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func GetCurrentSessionId(c echo.Context) (uuid.UUID, error) {
|
||||
user := c.Get("user").(*jwt.Token)
|
||||
if user == nil {
|
||||
return uuid.UUID{}, echo.NewHTTPError(401, "Unauthorized")
|
||||
}
|
||||
claims, ok := user.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return uuid.UUID{}, echo.NewHTTPError(403, "Could not retrieve claims")
|
||||
}
|
||||
sid, ok := claims["sid"]
|
||||
if !ok {
|
||||
return uuid.UUID{}, echo.NewHTTPError(403, "Could not retrieve session")
|
||||
}
|
||||
|
||||
sid_str, ok := sid.(string)
|
||||
if !ok {
|
||||
return uuid.UUID{}, echo.NewHTTPError(403, "Invalid session id claim.")
|
||||
}
|
||||
|
||||
ret, err := uuid.Parse(sid_str)
|
||||
if err != nil {
|
||||
return uuid.UUID{}, echo.NewHTTPError(403, "Invalid id")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CheckPermissions(c echo.Context, perms []string) error {
|
||||
token, ok := c.Get("user").(*jwt.Token)
|
||||
if !ok {
|
||||
|
Loading…
x
Reference in New Issue
Block a user