Skip to content

Commit

Permalink
adding update password + some refactor
Browse files Browse the repository at this point in the history
TODO: manage 404 on UniformResponse on Get operations
  • Loading branch information
Virgula0 committed Feb 12, 2025
1 parent 52b74eb commit 875bec1
Show file tree
Hide file tree
Showing 14 changed files with 356 additions and 227 deletions.
3 changes: 2 additions & 1 deletion server/backend/internal/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")
Expand Down
25 changes: 25 additions & 0 deletions server/backend/internal/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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()
Expand Down
80 changes: 79 additions & 1 deletion server/backend/internal/restapi/authenticate/handler_user.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,97 @@
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"
)

// 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{
StatusCode: http.StatusOK,
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",
})
}
7 changes: 7 additions & 0 deletions server/backend/internal/restapi/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand All @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions server/backend/internal/usecase/usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
10 changes: 10 additions & 0 deletions server/entities/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
2 changes: 2 additions & 0 deletions server/frontend/internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (
DeleteHandshake = "/delete-handshake"
CreateHandshake = "/create-handshake"
UpdateEncryption = "/update-encryption"
UpdatePassword = "/update-password"
)

// Endpoints BE
Expand All @@ -63,4 +64,5 @@ const (
BackendHandshake = "manage/handshake"
BackendDeleteRaspberryPI = "delete/raspberrypi"
UpdateClientEncryption = "encryption-status"
UpdateUserPassword = "user/password"
)
4 changes: 2 additions & 2 deletions server/frontend/internal/pages/handshakes/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 38 additions & 2 deletions server/frontend/internal/pages/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
}
Expand All @@ -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)
}
8 changes: 8 additions & 0 deletions server/frontend/internal/pages/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand All @@ -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).
Expand Down
Loading

0 comments on commit 875bec1

Please sign in to comment.