add custom error for password reset
This commit is contained in:
@@ -2,6 +2,7 @@ package datamysql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
|
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
||||||
@@ -29,7 +30,7 @@ func (c *passwordResetRepo) getQuery() string {
|
|||||||
a.token,
|
a.token,
|
||||||
a.create_date,
|
a.create_date,
|
||||||
a.expire_date,
|
a.expire_date,
|
||||||
(IFNULL(a.used, b'0') = b'1') used
|
(IFNULL(a.used, b'0') = b'1') used,
|
||||||
(IFNULL(a.opened, b'0') = b'1') opened
|
(IFNULL(a.opened, b'0') = b'1') opened
|
||||||
FROM
|
FROM
|
||||||
tab_password_reset a
|
tab_password_reset a
|
||||||
@@ -68,20 +69,26 @@ func (c *passwordResetRepo) GetAll() ([]entity.PasswordReset, error) {
|
|||||||
return c.parseSet(c.conn.Query(c.getQuery()))
|
return c.parseSet(c.conn.Query(c.getQuery()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (c *zipcodeRepo) GetByParticipatingZipcode(zipcode string) (entity.Zipcode, error) {
|
|
||||||
return c.parseEntity(c.conn.QueryRow(c.getQuery()+"WHERE a.participating = 1 AND a.zipcode = ?", zipcode))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func (c *passwordResetRepo) CreatePasswordResetEntry(passwordResetEntry entity.PasswordReset) (entity.PasswordReset, error) {
|
func (c *passwordResetRepo) CreatePasswordResetEntry(passwordResetEntry entity.PasswordReset) (entity.PasswordReset, error) {
|
||||||
const (
|
const (
|
||||||
query = `INSERT INTO tab_password_reset(password_reset_uuid, user_id, token, expire_date, used, opened) VALUES(?, ?, ?, ?, ?, 0, 0);`
|
insertQuery = `INSERT INTO tab_password_reset(password_reset_uuid, user_id, token, expire_date, used, opened) VALUES(?, ?, ?, ?, 0, 0);`
|
||||||
)
|
)
|
||||||
|
|
||||||
retVal := passwordResetEntry
|
retVal := passwordResetEntry
|
||||||
guid, _ := uuid.NewV4()
|
guid, _ := uuid.NewV4()
|
||||||
|
|
||||||
results, err := c.conn.Exec(query, guid, passwordResetEntry.User.ID, passwordResetEntry.Token, passwordResetEntry.Expires)
|
userRepo := newUserRepo(c.conn)
|
||||||
|
|
||||||
|
fullUser, err := userRepo.GetByEmail(passwordResetEntry.User.Email)
|
||||||
|
if err != nil {
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fullUser.Email != passwordResetEntry.User.Email {
|
||||||
|
return retVal, fmt.Errorf("User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := c.conn.Exec(insertQuery, guid, fullUser.ID, passwordResetEntry.Token, passwordResetEntry.Expires)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return retVal, err
|
return retVal, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const (
|
|||||||
baseURL = "http://localhost:5000"
|
baseURL = "http://localhost:5000"
|
||||||
passwordResetEmailSubject = "Reset Your Password"
|
passwordResetEmailSubject = "Reset Your Password"
|
||||||
passwordResetEmailMainBody = "To reset your password click here or copy the following link and paste it into your browser: \n\n " + baseURL + "/#/reset-password/"
|
passwordResetEmailMainBody = "To reset your password click here or copy the following link and paste it into your browser: \n\n " + baseURL + "/#/reset-password/"
|
||||||
passwordResetEmailFooter = "\nThis link expires in " + string(tokenExpirationTime) + " minutes"
|
passwordResetEmailFooter = "\nThis link expires in 90 minutes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -46,30 +46,29 @@ func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) handleResetRequest(ctx echo.Context) error {
|
func (c *controller) handleResetRequest(ctx echo.Context) error {
|
||||||
fmt.Println("\n\nRequest...")
|
|
||||||
userEmail, err := routeutils.GetAndValidateStringParam(ctx, "email", "mandatory field")
|
userEmail, err := routeutils.GetAndValidateStringParam(ctx, "email", "mandatory field")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("\nEmail : ", userEmail)
|
|
||||||
|
|
||||||
//find if user with email exists
|
//find if user with email exists
|
||||||
user, err := c.svc.Users.GetByEmail(userEmail)
|
user, err := c.svc.Users.GetByEmail(userEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.Email == nil || (*user.Email != userEmail) {
|
||||||
|
return routeutils.ResponseAPIOK(ctx, nil) //more secure, don't inform user (attacker) that email doesn't exists
|
||||||
|
}
|
||||||
|
|
||||||
//create and store reset token
|
//create and store reset token
|
||||||
|
|
||||||
timeNow := time.Now()
|
timeNow := time.Now()
|
||||||
expirationTime := timeNow.Add(time.Hour * tokenExpirationTime)
|
expirationTime := timeNow.Add(time.Minute * tokenExpirationTime)
|
||||||
|
|
||||||
randomArray := make([]byte, randomStringLength)
|
randomArray := make([]byte, randomStringLength)
|
||||||
rand.Read(randomArray)
|
rand.Read(randomArray)
|
||||||
h := sha256.New()
|
token := fmt.Sprintf("%x", sha256.Sum256(randomArray))
|
||||||
h.Write(randomArray)
|
|
||||||
token := string(h.Sum(nil))
|
|
||||||
|
|
||||||
passwordResetEntry := viewmodel.PasswordReset{
|
passwordResetEntry := viewmodel.PasswordReset{
|
||||||
User: user,
|
User: user,
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ func ResponseAPINotEligibleWithMessageError(c echo.Context, message string) erro
|
|||||||
return ResponseAPIError(c, http.StatusForbidden, message, false)
|
return ResponseAPIError(c, http.StatusForbidden, message, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ResponseAPIPasswordResetFailed returns a standard API error when password reset fails
|
||||||
|
func ResponseAPIPasswordResetFailed(c echo.Context, message string) error {
|
||||||
|
return ResponseAPIError(c, http.StatusForbidden, message, false)
|
||||||
|
}
|
||||||
|
|
||||||
func ignoreDefaultWrappedErrors(c echo.Context, errorToHandle *errors.WrappedError, handler func(echo.Context, error) error) error {
|
func ignoreDefaultWrappedErrors(c echo.Context, errorToHandle *errors.WrappedError, handler func(echo.Context, error) error) error {
|
||||||
err := errorToHandle.GetOriginalError()
|
err := errorToHandle.GetOriginalError()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user