From b8ede7ef36d2f67fcffc694b1328fe67c003deef Mon Sep 17 00:00:00 2001 From: z1glr Date: Sat, 11 Jan 2025 17:10:41 +0000 Subject: [PATCH] added chaging of password --- backend/pkg/db/users/users.go | 37 +++++++++++++--- backend/pkg/router/router.go | 4 +- backend/pkg/router/user.go | 26 +++++++++++ client/src/app/account/page.tsx | 77 +++++++++++++++++++++++++++++++++ client/src/lib.ts | 10 +++++ 5 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 client/src/app/account/page.tsx diff --git a/backend/pkg/db/users/users.go b/backend/pkg/db/users/users.go index fb954b4..72928f1 100644 --- a/backend/pkg/db/users/users.go +++ b/backend/pkg/db/users/users.go @@ -24,11 +24,6 @@ func hashPassword(password string) ([]byte, error) { return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) } -// validates a password against the password-rules -func ValidatePassword(password string) bool { - return len(password) >= 12 && len(password) <= 64 -} - func Get() (map[string]User, error) { if users, hit := c.Get("users"); !hit { refresh() @@ -41,7 +36,7 @@ func Get() (map[string]User, error) { type UserAdd struct { UserName string `json:"userName" validate:"required" db:"userName"` - Password string `json:"password" validate:"required,min=8"` + Password string `json:"password" validate:"required,min=12"` Admin bool `json:"admin" db:"admin"` } @@ -70,6 +65,36 @@ func Add(user UserAdd) error { } } +type UserChangePassword struct { + UserName string `json:"userName" validate:"required" db:"userName"` + Password string `json:"password" validate:"required,min=12"` +} + +func ChangePassword(user UserChangePassword) error { + // try to hash teh password + if hash, err := hashPassword(user.Password); err != nil { + return err + } else { + execStruct := struct { + UserName string `db:"userName"` + Password []byte `db:"password"` + TokenID string `db:"tokenID"` + }{ + UserName: user.UserName, + Password: hash, + TokenID: uuid.NewString(), + } + + if _, err := db.DB.NamedExec("UPDATE USERS SET tokenID = :tokenID, password = :password WHERE name = :userName", execStruct); err != nil { + return err + } else { + refresh() + + return nil + } + } +} + func refresh() { // get the usersRaw from the database var usersRaw []User diff --git a/backend/pkg/router/router.go b/backend/pkg/router/router.go index 88db1fb..4f52ec8 100644 --- a/backend/pkg/router/router.go +++ b/backend/pkg/router/router.go @@ -84,7 +84,9 @@ func init() { "events": postEvent, "users": postUser, }, - "PATCH": {}, + "PATCH": { + "users/password": patchPassword, + }, "DELETE": { "event": deleteEvent, }, diff --git a/backend/pkg/router/user.go b/backend/pkg/router/user.go index 6d2088d..6411389 100644 --- a/backend/pkg/router/user.go +++ b/backend/pkg/router/user.go @@ -34,3 +34,29 @@ func postUser(args HandlerArgs) responseMessage { return response } + +func patchPassword(args HandlerArgs) responseMessage { + response := responseMessage{} + // parse the body + var body users.UserChangePassword + + if err := args.C.BodyParser(&body); err != nil { + response.Status = fiber.StatusBadRequest + + logger.Log().Msgf("can't parse body: %v", err) + } else { + body.UserName = args.User.UserName + + if err := validate.Struct(body); err != nil { + response.Status = fiber.StatusBadRequest + + logger.Info().Msgf("invalid body: %v", err) + } else if err := users.ChangePassword(body); err != nil { + response.Status = fiber.StatusInternalServerError + + logger.Error().Msgf("can't update password: %v", err) + } + } + + return response +} diff --git a/client/src/app/account/page.tsx b/client/src/app/account/page.tsx new file mode 100644 index 0000000..d698513 --- /dev/null +++ b/client/src/app/account/page.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { apiCall, vaidatePassword as validatePassword } from "@/lib"; +import { + Button, + Card, + CardBody, + CardFooter, + CardHeader, + Form, + Input, +} from "@nextui-org/react"; +import { FormEvent, useState } from "react"; + +export default function Account() { + const [password, setPassword] = useState(""); + const errors = validatePassword(password); + + async function changePassword(e: FormEvent) { + const data = Object.fromEntries(new FormData(e.currentTarget)); + + const result = await apiCall("PATCH", "users/password", undefined, data); + + if (result.ok) { + setPassword(""); + } + } + + return ( + <> +

Account

+
+ + +

Change Password

+
+ +
{ + e.preventDefault(); + changePassword(e); + }} + > + + 0 && errors.length > 0} + errorMessage={ +
    + {errors.map((e, ii) => ( +
  • {e}
  • + ))} +
+ } + /> +
+ + + +
+
+
+ + ); +} diff --git a/client/src/lib.ts b/client/src/lib.ts index 54f2ab7..267fcaa 100644 --- a/client/src/lib.ts +++ b/client/src/lib.ts @@ -80,3 +80,13 @@ export class DateFormatter { return this.formatter.format(dt); } } + +export function vaidatePassword(password: string): string[] { + const errors = []; + + if (password.length < 1) { + errors.push("Password must be 16 characters or more"); + } + + return errors; +}