mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 02:27:11 -04:00 
			
		
		
		
	Add edit password
This commit is contained in:
		
							parent
							
								
									dbe8e319c8
								
							
						
					
					
						commit
						31d545530b
					
				| @ -12,6 +12,23 @@ import ( | |||||||
| 	"github.com/google/uuid" | 	"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 | const createSession = `-- name: CreateSession :one | ||||||
| insert into sessions(token, user_pk, device) | insert into sessions(token, user_pk, device) | ||||||
| 	values ($1, $2, $3) | 	values ($1, $2, $3) | ||||||
|  | |||||||
| @ -417,6 +417,60 @@ const docTemplate = `{ | |||||||
|                         "schema": { |                         "schema": { | ||||||
|                             "$ref": "#/definitions/main.KError" |                             "$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", |                         "type": "string", | ||||||
|                         "format": "uuid", |                         "format": "uuid", | ||||||
|                         "description": "User id of the user to delete", |                         "description": "User id of the user to edit", | ||||||
|                         "name": "id", |                         "name": "id", | ||||||
|                         "in": "path" |                         "in": "path" | ||||||
|                     }, |                     }, | ||||||
| @ -560,12 +614,30 @@ const docTemplate = `{ | |||||||
|                         "schema": { |                         "schema": { | ||||||
|                             "$ref": "#/definitions/main.KError" |                             "$ref": "#/definitions/main.KError" | ||||||
|                         } |                         } | ||||||
|  |                     }, | ||||||
|  |                     "422": { | ||||||
|  |                         "description": "Invalid body", | ||||||
|  |                         "schema": { | ||||||
|  |                             "$ref": "#/definitions/main.KError" | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "definitions": { |     "definitions": { | ||||||
|  |         "main.EditPasswordDto": { | ||||||
|  |             "type": "object", | ||||||
|  |             "required": [ | ||||||
|  |                 "password" | ||||||
|  |             ], | ||||||
|  |             "properties": { | ||||||
|  |                 "password": { | ||||||
|  |                     "type": "string", | ||||||
|  |                     "example": "password1234" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "main.EditUserDto": { |         "main.EditUserDto": { | ||||||
|             "type": "object", |             "type": "object", | ||||||
|             "properties": { |             "properties": { | ||||||
|  | |||||||
| @ -411,6 +411,60 @@ | |||||||
|                         "schema": { |                         "schema": { | ||||||
|                             "$ref": "#/definitions/main.KError" |                             "$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", |                         "type": "string", | ||||||
|                         "format": "uuid", |                         "format": "uuid", | ||||||
|                         "description": "User id of the user to delete", |                         "description": "User id of the user to edit", | ||||||
|                         "name": "id", |                         "name": "id", | ||||||
|                         "in": "path" |                         "in": "path" | ||||||
|                     }, |                     }, | ||||||
| @ -554,12 +608,30 @@ | |||||||
|                         "schema": { |                         "schema": { | ||||||
|                             "$ref": "#/definitions/main.KError" |                             "$ref": "#/definitions/main.KError" | ||||||
|                         } |                         } | ||||||
|  |                     }, | ||||||
|  |                     "422": { | ||||||
|  |                         "description": "Invalid body", | ||||||
|  |                         "schema": { | ||||||
|  |                             "$ref": "#/definitions/main.KError" | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "definitions": { |     "definitions": { | ||||||
|  |         "main.EditPasswordDto": { | ||||||
|  |             "type": "object", | ||||||
|  |             "required": [ | ||||||
|  |                 "password" | ||||||
|  |             ], | ||||||
|  |             "properties": { | ||||||
|  |                 "password": { | ||||||
|  |                     "type": "string", | ||||||
|  |                     "example": "password1234" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "main.EditUserDto": { |         "main.EditUserDto": { | ||||||
|             "type": "object", |             "type": "object", | ||||||
|             "properties": { |             "properties": { | ||||||
|  | |||||||
| @ -217,6 +217,7 @@ func main() { | |||||||
| 	r.DELETE("/users/me", h.DeleteSelf) | 	r.DELETE("/users/me", h.DeleteSelf) | ||||||
| 	r.PATCH("/users/:id", h.EditUser) | 	r.PATCH("/users/:id", h.EditUser) | ||||||
| 	r.PATCH("/users/me", h.EditSelf) | 	r.PATCH("/users/me", h.EditSelf) | ||||||
|  | 	r.PATCH("/users/me/password", h.ChangePassword) | ||||||
| 	g.POST("/users", h.Register) | 	g.POST("/users", h.Register) | ||||||
| 
 | 
 | ||||||
| 	g.POST("/sessions", h.Login) | 	g.POST("/sessions", h.Login) | ||||||
|  | |||||||
| @ -43,3 +43,8 @@ where s.user_pk = u.pk | |||||||
| returning | returning | ||||||
| 	s.*; | 	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"` | 	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 { | func MapDbUser(user *dbc.User) User { | ||||||
| 	return User{ | 	return User{ | ||||||
| 		Pk:          user.Pk, | 		Pk:          user.Pk, | ||||||
| @ -293,6 +297,7 @@ func (h *Handler) DeleteSelf(c echo.Context) error { | |||||||
| // @Param        user     body  EditUserDto  false  "Edited user info" | // @Param        user     body  EditUserDto  false  "Edited user info" | ||||||
| // @Success      200  {object}  User | // @Success      200  {object}  User | ||||||
| // @Success      403  {object}  KError  "You can't edit a protected claim" | // @Success      403  {object}  KError  "You can't edit a protected claim" | ||||||
|  | // @Success      422  {object}  KError  "Invalid body" | ||||||
| // @Router /users/me [patch] | // @Router /users/me [patch] | ||||||
| func (h *Handler) EditSelf(c echo.Context) error { | func (h *Handler) EditSelf(c echo.Context) error { | ||||||
| 	var req EditUserDto | 	var req EditUserDto | ||||||
| @ -340,6 +345,7 @@ func (h *Handler) EditSelf(c echo.Context) error { | |||||||
| // @Param        user     body  EditUserDto  false  "Edited user info" | // @Param        user     body  EditUserDto  false  "Edited user info" | ||||||
| // @Success      200  {object}  User | // @Success      200  {object}  User | ||||||
| // @Success      403  {object}  KError  "You don't have permissions to edit another account" | // @Success      403  {object}  KError  "You don't have permissions to edit another account" | ||||||
|  | // @Success      422  {object}  KError  "Invalid body" | ||||||
| // @Router /users/{id} [patch] | // @Router /users/{id} [patch] | ||||||
| func (h *Handler) EditUser(c echo.Context) error { | func (h *Handler) EditUser(c echo.Context) error { | ||||||
| 	err := CheckPermissions(c, []string{"user.write"}) | 	err := CheckPermissions(c, []string{"user.write"}) | ||||||
| @ -375,3 +381,55 @@ func (h *Handler) EditUser(c echo.Context) error { | |||||||
| 
 | 
 | ||||||
| 	return c.JSON(200, MapDbUser(&ret)) | 	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 | 	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 { | func CheckPermissions(c echo.Context, perms []string) error { | ||||||
| 	token, ok := c.Get("user").(*jwt.Token) | 	token, ok := c.Get("user").(*jwt.Token) | ||||||
| 	if !ok { | 	if !ok { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user