From 875bec168acc15cd1993ad2bc085385804de754b Mon Sep 17 00:00:00 2001 From: Virgula0 Date: Wed, 12 Feb 2025 20:24:21 +0100 Subject: [PATCH] adding update password + some refactor TODO: manage 404 on UniformResponse on Get operations --- server/backend/internal/errors/errors.go | 3 +- .../backend/internal/repository/repository.go | 25 ++ .../restapi/authenticate/handler_user.go | 80 ++++- server/backend/internal/restapi/routes.go | 7 + server/backend/internal/usecase/usecase.go | 8 + server/entities/user.go | 10 + .../frontend/internal/constants/constants.go | 2 + .../internal/pages/handshakes/handshake.go | 4 +- server/frontend/internal/pages/login/login.go | 40 ++- server/frontend/internal/pages/routes.go | 8 + .../internal/repository/repository.go | 314 ++++++------------ server/frontend/internal/usecase/usecase.go | 4 + server/frontend/static/scripts/dashboard.js | 27 ++ server/frontend/views/handshake.html | 51 ++- 14 files changed, 356 insertions(+), 227 deletions(-) diff --git a/server/backend/internal/errors/errors.go b/server/backend/internal/errors/errors.go index 4c17f58..779fb5a 100644 --- a/server/backend/internal/errors/errors.go +++ b/server/backend/internal/errors/errors.go @@ -17,7 +17,8 @@ var ErrInvalidType = errors.New("failed conversion while fetching db for type: " var ErrNoClientFound = errors.New("no client found") var ErrNotValidClientIP = errors.New("not valid client IP") var ErrClientIsBusy = errors.New("client is busy") -var ErrCannotDeleteElement = errors.New("unable to delete element") +var ErrOldPasswordMismatch = errors.New("old password is not correct") +var ErrPasswordConfirmationDoNotMatch = errors.New("password confirmation does not match") var ErrCertsNotInitialized = errors.New("caCerts not initialized in repository ") var ErrFailToGeneratePrivateKey = errors.New("fail to generate private key ") diff --git a/server/backend/internal/repository/repository.go b/server/backend/internal/repository/repository.go index 95e1b8d..28a6322 100644 --- a/server/backend/internal/repository/repository.go +++ b/server/backend/internal/repository/repository.go @@ -151,6 +151,18 @@ func (repo *Repository) GetUserByUsername(username string) (*entities.User, *ent return &user, &role, nil } +// GetUserByUserID REST/API retrives the user by userID +func (repo *Repository) GetUserByUserID(userUUID string) (*entities.User, error) { + var user entities.User + + query := fmt.Sprintf("SELECT * FROM %s WHERE uuid = ?", entities.UserTableName) + + row := repo.dbUser.QueryRow(query, userUUID) + err := row.Scan(&user.UserUUID, &user.Username, &user.Password) + + return &user, err +} + // GetClientsInstalled returns all installed clients func (repo *Repository) GetClientsInstalled() (clients []*entities.Client, length int, e error) { clientBuilder := func() (any, []any) { @@ -531,6 +543,19 @@ func (repo *Repository) UpdateCerts(client *entities.Client, caCert, clientCert, return err } +// UpdateUserPassword REST/API update user password +func (repo *Repository) UpdateUserPassword(userUUID, password string) error { + psw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return err + } + _, err = repo.dbUser.Exec( + fmt.Sprintf("UPDATE %s SET password = ? WHERE uuid = ?", entities.UserTableName), + string(psw), userUUID, + ) + return err +} + // CreateHandshake creates a new handshake record func (repo *Repository) CreateHandshake(userUUID, ssid, bssid, status, handshakePcap string) (string, error) { handshakeID := uuid.New().String() diff --git a/server/backend/internal/restapi/authenticate/handler_user.go b/server/backend/internal/restapi/authenticate/handler_user.go index f7a026a..2b85a7f 100644 --- a/server/backend/internal/restapi/authenticate/handler_user.go +++ b/server/backend/internal/restapi/authenticate/handler_user.go @@ -1,7 +1,10 @@ package authenticate import ( + "github.com/Virgula0/progetto-dp/server/backend/internal/errors" + "github.com/Virgula0/progetto-dp/server/backend/internal/utils" "github.com/Virgula0/progetto-dp/server/entities" + "golang.org/x/crypto/bcrypt" "net/http" rr "github.com/Virgula0/progetto-dp/server/backend/internal/response" @@ -9,7 +12,6 @@ import ( // CheckTokenValidity Used for verifying if the JWT is still valid func (u Handler) CheckTokenValidity(w http.ResponseWriter, _ *http.Request) { - c := rr.Initializer{ResponseWriter: w} c.JSON(http.StatusOK, entities.UniformResponse{ @@ -17,3 +19,79 @@ func (u Handler) CheckTokenValidity(w http.ResponseWriter, _ *http.Request) { Details: "valid", }) } + +// UpdateUserPassword update user password +func (u Handler) UpdateUserPassword(w http.ResponseWriter, r *http.Request) { + c := rr.Initializer{ResponseWriter: w} + + userID, err := u.Usecase.GetUserIDFromToken(r) + + if err != nil { + c.JSON(http.StatusInternalServerError, entities.UniformResponse{ + StatusCode: http.StatusInternalServerError, + Details: err.Error(), + }) + return + } + + var request entities.UpdateUserPasswordRequest + + if err = utils.ValidateJSON(&request, r); err != nil { + c.JSON(http.StatusBadRequest, entities.UniformResponse{ + StatusCode: http.StatusBadRequest, + Details: err.Error(), + }) + return + } + + if request.NewPassword != request.NewPasswordConfirm { + c.JSON(http.StatusBadRequest, entities.UniformResponse{ + StatusCode: http.StatusBadRequest, + Details: errors.ErrPasswordConfirmationDoNotMatch.Error(), + }) + return + } + + user, err := u.Usecase.GetUserByUserID(userID.String()) + + if err != nil { + c.JSON(http.StatusBadRequest, entities.UniformResponse{ + StatusCode: http.StatusBadRequest, + Details: err.Error(), + }) + return + } + + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(request.OldPassword)) + if err != nil { + statusCode := http.StatusUnauthorized + c.JSON(statusCode, entities.UniformResponse{ + StatusCode: statusCode, + Details: errors.ErrOldPasswordMismatch.Error(), + }) + return + } + + if !utils.IsValidPassword(request.NewPassword) { + statusCode := http.StatusUnauthorized + c.JSON(statusCode, entities.UniformResponse{ + StatusCode: statusCode, + Details: errors.ErrBadPasswordCriteria.Error(), + }) + return + } + + err = u.Usecase.UpdateUserPassword(userID.String(), request.NewPassword) + + if err != nil { + c.JSON(http.StatusInternalServerError, entities.UniformResponse{ + StatusCode: http.StatusInternalServerError, + Details: err.Error(), + }) + return + } + + c.JSON(http.StatusOK, entities.UpdateUserPasswordResponse{ + Status: "updated", + }) +} diff --git a/server/backend/internal/restapi/routes.go b/server/backend/internal/restapi/routes.go index 4349c70..be2a319 100644 --- a/server/backend/internal/restapi/routes.go +++ b/server/backend/internal/restapi/routes.go @@ -25,6 +25,7 @@ const DeleteClient = "/delete/client" const DeleteRaspberryPI = "/delete/raspberrypi" const ManageHandshake = "/manage/handshake" const UpdateClientEncryptionStatus = "/encryption-status" +const UpdateUserPassword = "/user/password" func (h ServiceHandler) InitRoutes(router *mux.Router) { @@ -45,6 +46,12 @@ func (h ServiceHandler) InitRoutes(router *mux.Router) { HandleFunc(RouteAuthenticate, authenticateHandler.LoginHandler). Methods("POST") + updatePasswordRouter := router.PathPrefix(RouteIndex).Subrouter() + updatePasswordRouter. + HandleFunc(UpdateUserPassword, authenticateHandler.UpdateUserPassword). + Methods("POST") + updatePasswordRouter.Use(authMiddleware.EnsureTokenIsValid) + // SIGN-UP -- NOT AUTHENTICATED -- registerRouter := router.PathPrefix(RouteIndex).Subrouter() registerRouter. diff --git a/server/backend/internal/usecase/usecase.go b/server/backend/internal/usecase/usecase.go index 783e34d..e109aa9 100644 --- a/server/backend/internal/usecase/usecase.go +++ b/server/backend/internal/usecase/usecase.go @@ -229,10 +229,18 @@ func (uc *Usecase) GetUserByUsername(username string) (*entities.User, *entities return uc.repo.GetUserByUsername(username) } +func (uc *Usecase) GetUserByUserID(userUUID string) (*entities.User, error) { + return uc.repo.GetUserByUserID(userUUID) +} + func (uc *Usecase) CreateUser(userEntity *entities.User, role constants.Role) error { return uc.repo.CreateUser(userEntity, role) } +func (uc *Usecase) UpdateUserPassword(userUUID, password string) error { + return uc.repo.UpdateUserPassword(userUUID, password) +} + func (uc *Usecase) GetClientsInstalledByUserID(userUUID string, offset uint) ([]*entities.Client, int, error) { return uc.repo.GetClientsInstalledByUserID(userUUID, offset) } diff --git a/server/entities/user.go b/server/entities/user.go index c896341..02f14c1 100644 --- a/server/entities/user.go +++ b/server/entities/user.go @@ -7,3 +7,13 @@ type User struct { Username string `db:"USERNAME"` Password string `db:"PASSWORD"` } + +type UpdateUserPasswordRequest struct { + OldPassword string `json:"oldPassword" validate:"required"` + NewPassword string `json:"newPassword" validate:"required"` + NewPasswordConfirm string `json:"newPasswordConfirm" validate:"required"` +} + +type UpdateUserPasswordResponse struct { + Status string `json:"status"` +} diff --git a/server/frontend/internal/constants/constants.go b/server/frontend/internal/constants/constants.go index 322bfab..6e772d3 100644 --- a/server/frontend/internal/constants/constants.go +++ b/server/frontend/internal/constants/constants.go @@ -47,6 +47,7 @@ const ( DeleteHandshake = "/delete-handshake" CreateHandshake = "/create-handshake" UpdateEncryption = "/update-encryption" + UpdatePassword = "/update-password" ) // Endpoints BE @@ -63,4 +64,5 @@ const ( BackendHandshake = "manage/handshake" BackendDeleteRaspberryPI = "delete/raspberrypi" UpdateClientEncryption = "encryption-status" + UpdateUserPassword = "user/password" ) diff --git a/server/frontend/internal/pages/handshakes/handshake.go b/server/frontend/internal/pages/handshakes/handshake.go index fcb7f7d..185cd90 100644 --- a/server/frontend/internal/pages/handshakes/handshake.go +++ b/server/frontend/internal/pages/handshakes/handshake.go @@ -157,12 +157,12 @@ func (u Page) UpdateTask(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, fmt.Sprintf("%s?page=1&success=%s", constants.HandshakePage, url.QueryEscape(fmt.Sprintf("%s updated", crackingRequest.Handshake.UUID))), http.StatusFound) } -type DeleteHandshakeReqeust struct { +type DeleteHandshakeRequest struct { UUID string `form:"uuid" validate:"required"` } func (u Page) DeleteHandshake(w http.ResponseWriter, r *http.Request) { - var request DeleteHandshakeReqeust + var request DeleteHandshakeRequest token := r.Context().Value(constants.AuthToken) // Check if the token exists diff --git a/server/frontend/internal/pages/login/login.go b/server/frontend/internal/pages/login/login.go index 286dc96..c5dbf37 100644 --- a/server/frontend/internal/pages/login/login.go +++ b/server/frontend/internal/pages/login/login.go @@ -2,13 +2,14 @@ package login import ( "fmt" + "github.com/Virgula0/progetto-dp/server/entities" "github.com/Virgula0/progetto-dp/server/frontend/internal/utils" "net/http" "net/url" "time" "github.com/Virgula0/progetto-dp/server/frontend/internal/constants" - "github.com/Virgula0/progetto-dp/server/frontend/internal/errors" + customErrors "github.com/Virgula0/progetto-dp/server/frontend/internal/errors" "github.com/Virgula0/progetto-dp/server/frontend/internal/usecase" ) @@ -49,7 +50,7 @@ func (u Page) PerformLogin(w http.ResponseWriter, r *http.Request) { } if loginResponse.StatusCode != http.StatusOK { - errorQuery := url.QueryEscape(errors.ErrInvalidCredentials.Error()) // Ensures the string is URL-safe + errorQuery := url.QueryEscape(customErrors.ErrInvalidCredentials.Error()) // Ensures the string is URL-safe http.Redirect(w, r, fmt.Sprintf("%s?error=%s", constants.Login, errorQuery), http.StatusFound) return } @@ -66,3 +67,38 @@ func (u Page) PerformLogin(w http.ResponseWriter, r *http.Request) { // Redirect to posts http.Redirect(w, r, fmt.Sprintf("%s?page=1", constants.HandshakePage), http.StatusFound) } + +type UpdateUserPassword struct { + OldPassword string `form:"old_password" validate:"required"` + NewPassword string `form:"new_password" validate:"required"` + ConfirmPassword string `form:"confirm_password" validate:"required"` +} + +func (u Page) UpdateUserPassword(w http.ResponseWriter, r *http.Request) { + token := r.Context().Value(constants.AuthToken) + + // Check if the token exists + if token == nil { + http.Redirect(w, r, fmt.Sprintf("%s?page=1&error=%s", constants.Login, url.QueryEscape(customErrors.ErrNotAuthenticated.Error())), http.StatusFound) + return + } + + var request UpdateUserPassword + if err := utils.ValidatePOSTFormRequest(&request, r); err != nil { + http.Redirect(w, r, fmt.Sprintf("%s?error=%s", constants.HandshakePage, err.Error()), http.StatusFound) + return + } + + rr := &entities.UpdateUserPasswordRequest{ + OldPassword: request.OldPassword, + NewPassword: request.NewPassword, + NewPasswordConfirm: request.ConfirmPassword, + } + + if _, err := u.Usecase.UpdateUserPassword(token.(string), rr); err != nil { + http.Redirect(w, r, fmt.Sprintf("%s?error=%s", constants.HandshakePage, err.Error()), http.StatusFound) + return + } + + http.Redirect(w, r, fmt.Sprintf("%s?page=1&success=updated", constants.HandshakePage), http.StatusFound) +} diff --git a/server/frontend/internal/pages/routes.go b/server/frontend/internal/pages/routes.go index 718dd6a..70171b6 100644 --- a/server/frontend/internal/pages/routes.go +++ b/server/frontend/internal/pages/routes.go @@ -28,6 +28,7 @@ const DeleteClient = constants.DeleteClient const DeleteHandshake = constants.DeleteHandshake const CreateHandshake = constants.CreateHandshake const UpdateClientEncryptionStatus = constants.UpdateEncryption +const UpdateUserPassword = constants.UpdatePassword // InitRoutes // @@ -52,6 +53,13 @@ func (h ServiceHandler) InitRoutes(router *mux.Router) { HandleFunc(Login, loginInstance.PerformLogin). Methods("POST") + // UPDATE USER PASSWORD + changePasswordRouter := router.PathPrefix(RouteIndex).Subrouter() + changePasswordRouter. + HandleFunc(UpdateUserPassword, loginInstance.UpdateUserPassword). + Methods("POST") + changePasswordRouter.Use(authenticated.TokenValidation) + loginRouterTemplate := router.PathPrefix(RouteIndex).Subrouter() loginRouterTemplate. HandleFunc(Login, loginInstance.LoginTemplate). diff --git a/server/frontend/internal/repository/repository.go b/server/frontend/internal/repository/repository.go index a2e0219..6eafa14 100644 --- a/server/frontend/internal/repository/repository.go +++ b/server/frontend/internal/repository/repository.go @@ -7,32 +7,22 @@ import ( "fmt" "io" "net/http" - "strconv" "time" "github.com/Virgula0/progetto-dp/server/entities" "github.com/Virgula0/progetto-dp/server/frontend/internal/constants" ) -/* -repository.go contains simple methods for performing requests to the backend -*/ - type Repository struct { client *http.Client } -// CustomTransport wraps around an existing http.RoundTripper type CustomTransport struct { Transport http.RoundTripper } -// RoundTrip executes a single HTTP transaction and sets default headers func (c *CustomTransport) RoundTrip(req *http.Request) (*http.Response, error) { - // Set default headers here req.Header.Set("Content-Type", "application/json") - - // Use the embedded RoundTripper to execute the actual request return c.Transport.RoundTrip(req) } @@ -47,6 +37,18 @@ func NewRepository() (*Repository, error) { }, nil } +// Helper function to check for UniformResponse errors +func (repo *Repository) checkUniformError(responseBytes []byte) error { + var uniformResponse entities.UniformResponse + if err := json.Unmarshal(responseBytes, &uniformResponse); err != nil { + return err + } + if uniformResponse.Details != "" { + return fmt.Errorf(uniformResponse.Details) + } + return nil +} + func (repo *Repository) GenericHTTPRequest(baseURL, method, endpoint string, headers map[string]string, requestData []byte) ([]byte, error) { req, err := http.NewRequestWithContext(context.Background(), method, fmt.Sprintf("%s%s", baseURL, endpoint), bytes.NewBuffer(requestData)) if err != nil { @@ -63,287 +65,159 @@ func (repo *Repository) GenericHTTPRequest(baseURL, method, endpoint string, hea } defer resp.Body.Close() - responseBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - return responseBody, nil + return io.ReadAll(resp.Body) } func (repo *Repository) GenericHTTPRequestToBackend(method, endpoint string, headers map[string]string, requestData []byte) ([]byte, error) { return repo.GenericHTTPRequest(constants.BackendBaseURL, method, endpoint, headers, requestData) } +// Common handler for endpoints returning UniformResponse func (repo *Repository) uniformResponseRefactored(requestData any, endpoint, method string, headers map[string]string) (*entities.UniformResponse, error) { - - // Marshal the data into JSON jsonData, err := json.Marshal(requestData) if err != nil { return nil, err } responseBody, err := repo.GenericHTTPRequestToBackend(method, endpoint, headers, jsonData) - if err != nil { return nil, err } var backendResponse entities.UniformResponse - - err = json.Unmarshal(responseBody, &backendResponse) - if err != nil { + if err := json.Unmarshal(responseBody, &backendResponse); err != nil { return nil, err } return &backendResponse, nil } +// Authentication handlers func (repo *Repository) PerformLogin(username, password string) (*entities.UniformResponse, error) { - requestData := map[string]string{ - "username": username, - "password": password, - } - - return repo.uniformResponseRefactored(requestData, constants.BackendAuthEndpoint, http.MethodPost, nil) + return repo.uniformResponseRefactored( + map[string]string{"username": username, "password": password}, + constants.BackendAuthEndpoint, + http.MethodPost, + nil, + ) } func (repo *Repository) PerformLogout(token string) (*entities.UniformResponse, error) { - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - return repo.uniformResponseRefactored(nil, constants.BackendLogoutEndpoint, http.MethodGet, headers) + return repo.uniformResponseRefactored( + nil, + constants.BackendLogoutEndpoint, + http.MethodGet, + map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)}, + ) } func (repo *Repository) PerformRegister(username, password, confirmation string) (*entities.UniformResponse, error) { - requestData := map[string]string{ - "username": username, - "password": password, - "confirmation": confirmation, - } - - return repo.uniformResponseRefactored(requestData, constants.BackendRegisterEndpoint, http.MethodPost, nil) + return repo.uniformResponseRefactored( + map[string]string{"username": username, "password": password, "confirmation": confirmation}, + constants.BackendRegisterEndpoint, + http.MethodPost, + nil, + ) } -func (repo *Repository) GetUserHandshakes(token string, page int) (*entities.GetHandshakeResponse, error) { - var handshakes *entities.GetHandshakeResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodGet, fmt.Sprintf("%s?page=%s", constants.BackendGetHandshakes, strconv.Itoa(page)), headers, nil) +// Data retrieval handlers with pagination +func (repo *Repository) getPaginatedResource(token, endpoint string, page int, target interface{}) error { + headers := map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)} + endpointWithPage := fmt.Sprintf("%s?page=%d", endpoint, page) + responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodGet, endpointWithPage, headers, nil) if err != nil { - return nil, err + return err } - if err := json.Unmarshal(responseBytes, &handshakes); err != nil { - return nil, err + if err := repo.checkUniformError(responseBytes); err != nil { + return err } - return handshakes, nil + return json.Unmarshal(responseBytes, target) } -func (repo *Repository) GetUserClients(token string, page int) (*entities.ReturnClientsInstalledResponse, error) { - var clients *entities.ReturnClientsInstalledResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodGet, fmt.Sprintf("%s?page=%s", constants.BackendGetClients, strconv.Itoa(page)), headers, nil) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &clients); err != nil { - return nil, err - } +func (repo *Repository) GetUserHandshakes(token string, page int) (*entities.GetHandshakeResponse, error) { + var response entities.GetHandshakeResponse + err := repo.getPaginatedResource(token, constants.BackendGetHandshakes, page, &response) + return &response, err +} - return clients, nil +func (repo *Repository) GetUserClients(token string, page int) (*entities.ReturnClientsInstalledResponse, error) { + var response entities.ReturnClientsInstalledResponse + err := repo.getPaginatedResource(token, constants.BackendGetClients, page, &response) + return &response, err } func (repo *Repository) GetUserDevices(token string, page int) (*entities.ReturnRaspberryPiDevicesResponse, error) { - var clients *entities.ReturnRaspberryPiDevicesResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodGet, fmt.Sprintf("%s?page=%s", constants.BackendGetRaspberryPi, strconv.Itoa(page)), headers, nil) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &clients); err != nil { - return nil, err - } - - return clients, nil + var response entities.ReturnRaspberryPiDevicesResponse + err := repo.getPaginatedResource(token, constants.BackendGetRaspberryPi, page, &response) + return &response, err } -func (repo *Repository) SendCrackingRequest(token string, request *entities.UpdateHandshakeTaskViaAPIRequest) (*entities.UpdateHandshakeTaskViaAPIResponse, error) { - var update *entities.UpdateHandshakeTaskViaAPIResponse +// Common CRUD operation handler +func (repo *Repository) executeAuthorizedRequest(method, endpoint string, token string, request, response interface{}) error { + headers := map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)} - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON jsonData, err := json.Marshal(request) - if err != nil { - return nil, err + return err } - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodPost, constants.BackendUpdateClientTask, headers, jsonData) - + responseBytes, err := repo.GenericHTTPRequestToBackend(method, endpoint, headers, jsonData) if err != nil { - return nil, err + return err } - if err := json.Unmarshal(responseBytes, &update); err != nil { - return nil, err + if err := repo.checkUniformError(responseBytes); err != nil { + return err } - return update, nil + return json.Unmarshal(responseBytes, response) } -func (repo *Repository) DeleteClient(token string, request *entities.DeleteClientRequest) (*entities.DeleteClientResponse, error) { - var dd *entities.DeleteClientResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON - jsonData, err := json.Marshal(request) - - if err != nil { - return nil, err - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodDelete, constants.BackendDeleteClient, headers, jsonData) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &dd); err != nil { - return nil, err - } +// Cracking operations +func (repo *Repository) SendCrackingRequest(token string, request *entities.UpdateHandshakeTaskViaAPIRequest) (*entities.UpdateHandshakeTaskViaAPIResponse, error) { + var response entities.UpdateHandshakeTaskViaAPIResponse + err := repo.executeAuthorizedRequest(http.MethodPost, constants.BackendUpdateClientTask, token, request, &response) + return &response, err +} - return dd, nil +// Deletion operations +func (repo *Repository) DeleteClient(token string, request *entities.DeleteClientRequest) (*entities.DeleteClientResponse, error) { + var response entities.DeleteClientResponse + err := repo.executeAuthorizedRequest(http.MethodDelete, constants.BackendDeleteClient, token, request, &response) + return &response, err } func (repo *Repository) DeleteRaspberryPI(token string, request *entities.DeleteRaspberryPIRequest) (*entities.DeleteRaspberryPIResponse, error) { - var dd *entities.DeleteRaspberryPIResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON - jsonData, err := json.Marshal(request) - - if err != nil { - return nil, err - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodDelete, constants.BackendDeleteRaspberryPI, headers, jsonData) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &dd); err != nil { - return nil, err - } - - return dd, nil + var response entities.DeleteRaspberryPIResponse + err := repo.executeAuthorizedRequest(http.MethodDelete, constants.BackendDeleteRaspberryPI, token, request, &response) + return &response, err } func (repo *Repository) DeleteHandshake(token string, request *entities.DeleteHandshakesRequest) (*entities.DeleteHandshakesResponse, error) { - var dd *entities.DeleteHandshakesResponse - - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON - jsonData, err := json.Marshal(request) - - if err != nil { - return nil, err - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodDelete, constants.BackendHandshake, headers, jsonData) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &dd); err != nil { - return nil, err - } - - return dd, nil + var response entities.DeleteHandshakesResponse + err := repo.executeAuthorizedRequest(http.MethodDelete, constants.BackendHandshake, token, request, &response) + return &response, err } +// Creation operations func (repo *Repository) CreateHandshake(token string, request *entities.CreateHandshakeRequest) (*entities.CreateHandshakeResponse, error) { - - var dd *entities.CreateHandshakeResponse - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON - jsonData, err := json.Marshal(request) - - if err != nil { - return nil, err - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodPut, constants.BackendHandshake, headers, jsonData) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &dd); err != nil { - return nil, err - } - - return dd, nil + var response entities.CreateHandshakeResponse + err := repo.executeAuthorizedRequest(http.MethodPut, constants.BackendHandshake, token, request, &response) + return &response, err } +// Update operations func (repo *Repository) UpdateClientEncryptionStatus(token string, request *entities.UpdateEncryptionClientStatusRequest) (*entities.UpdateEncryptionClientStatusResponse, error) { + var response entities.UpdateEncryptionClientStatusResponse + err := repo.executeAuthorizedRequest(http.MethodPost, constants.UpdateClientEncryption, token, request, &response) + return &response, err +} - var dd *entities.UpdateEncryptionClientStatusResponse - headers := map[string]string{ - "Authorization": fmt.Sprintf("Bearer %s", token), - } - - // Marshal the data into JSON - jsonData, err := json.Marshal(request) - - if err != nil { - return nil, err - } - - responseBytes, err := repo.GenericHTTPRequestToBackend(http.MethodPost, constants.UpdateClientEncryption, headers, jsonData) - - if err != nil { - return nil, err - } - - if err := json.Unmarshal(responseBytes, &dd); err != nil { - return nil, err - } - - return dd, nil +func (repo *Repository) UpdateUserPassword(token string, request *entities.UpdateUserPasswordRequest) (*entities.UpdateUserPasswordResponse, error) { + var response entities.UpdateUserPasswordResponse + err := repo.executeAuthorizedRequest(http.MethodPost, constants.UpdateUserPassword, token, request, &response) + return &response, err } diff --git a/server/frontend/internal/usecase/usecase.go b/server/frontend/internal/usecase/usecase.go index fc3e13e..9fc6725 100644 --- a/server/frontend/internal/usecase/usecase.go +++ b/server/frontend/internal/usecase/usecase.go @@ -139,6 +139,10 @@ func (uc Usecase) UpdateClientEncryptionStatus(token string, request *entities.U return uc.repo.UpdateClientEncryptionStatus(token, request) } +func (uc Usecase) UpdateUserPassword(token string, request *entities.UpdateUserPasswordRequest) (*entities.UpdateUserPasswordResponse, error) { + return uc.repo.UpdateUserPassword(token, request) +} + func (uc Usecase) SendCrackingRequest(token string, request *entities.UpdateHandshakeTaskViaAPIRequest) (*entities.UpdateHandshakeTaskViaAPIResponse, error) { return uc.repo.SendCrackingRequest(token, request) } diff --git a/server/frontend/static/scripts/dashboard.js b/server/frontend/static/scripts/dashboard.js index 66eeb5b..81bf0f7 100644 --- a/server/frontend/static/scripts/dashboard.js +++ b/server/frontend/static/scripts/dashboard.js @@ -599,3 +599,30 @@ $(function () { this.form.submit(); }); }); + +document.getElementById("settingsLink").addEventListener("click", (e) => { + e.preventDefault() + $("#settingsModal").modal("show") +}) + +// Show change password modal when change password button is clicked +document.getElementById("changePasswordBtn").addEventListener("click", () => { + $("#settingsModal").modal("hide") + $("#changePasswordModal").modal("show") +}) + +// Handle change password form submission +document.getElementById("changePasswordForm").addEventListener("submit", (e) => { + e.preventDefault() + + const newPassword = document.getElementById("new_password").value + const confirmPassword = document.getElementById("confirm_password").value + + if (newPassword !== confirmPassword) { + alert("New password and confirmation do not match") + return + } + + // If passwords match, submit the form + e.target.submit(); +}) diff --git a/server/frontend/views/handshake.html b/server/frontend/views/handshake.html index 222cf16..6e64d0b 100644 --- a/server/frontend/views/handshake.html +++ b/server/frontend/views/handshake.html @@ -34,7 +34,7 @@ RaspberryPi - + Settings @@ -366,6 +366,55 @@ + + + +