mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -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