add password reset model ; create entry in database; send email

This commit is contained in:
GotPPay
2018-05-30 16:52:57 +02:00
parent 69853b026b
commit 06ea1cb44d
18 changed files with 596 additions and 61 deletions

View File

@@ -0,0 +1,123 @@
package passwordresetroute
import (
"crypto/sha256"
"fmt"
"math/rand"
"sync"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"github.com/labstack/echo"
)
const (
tokenExpirationTime = 90 // in minutes
randomStringLength = 15
baseURL = "http://localhost:5000"
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/"
passwordResetEmailFooter = "\nThis link expires in " + string(tokenExpirationTime) + " minutes"
)
var (
instance *controller
once sync.Once
)
type controller struct {
svc *applicationservice.Service
cfg *config.Config
}
func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller {
once.Do(func() {
instance = &controller{
svc: svc,
cfg: cfg,
}
rand.Seed(time.Now().UTC().UnixNano())
})
return instance
}
func (c *controller) handleResetRequest(ctx echo.Context) error {
fmt.Println("\n\nRequest...")
userEmail, err := routeutils.GetAndValidateStringParam(ctx, "email", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
fmt.Println("\nEmail : ", userEmail)
//find if user with email exists
user, err := c.svc.Users.GetByEmail(userEmail)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
//create and store reset token
timeNow := time.Now()
expirationTime := timeNow.Add(time.Hour * tokenExpirationTime)
randomArray := make([]byte, randomStringLength)
rand.Read(randomArray)
h := sha256.New()
h.Write(randomArray)
token := string(h.Sum(nil))
passwordResetEntry := viewmodel.PasswordReset{
User: user,
Token: token,
Expires: expirationTime,
Opened: false,
Used: false,
}
_, err = c.svc.PasswordReset.CreatePasswordResetEntry(passwordResetEntry)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
//Send email with reset link
notification := viewmodel.Notification{
Type: applicationservice.NotificationTypeEmail,
From: c.cfg.Email.Sender,
To: *user.Email,
Subject: passwordResetEmailSubject,
Message: passwordResetEmailMainBody + token + passwordResetEmailFooter,
}
notification, err = c.svc.Notification.SendNotificationWithoutWritingToDatabase(notification)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, nil)
}
func (c *controller) handleResetComplete(ctx echo.Context) error {
/*
userEmail, err := routeutils.GetAndValidateStringParam(ctx, "email", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
//find if user with email exists
user, err := c.svc.Users.GetByEmail(userEmail)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
//create and store reset token
//send email with reset link
*/
return routeutils.ResponseAPIOK(ctx, nil)
}

View File

@@ -0,0 +1,19 @@
package passwordresetroute
import (
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"github.com/labstack/echo"
)
const (
resetRequest = "/request/:email"
resetComplete = "/complete"
)
func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service) {
ctrl := controllerInstance(svc, cfg)
r.POST(resetRequest, ctrl.handleResetRequest)
r.POST(resetComplete, ctrl.handleResetComplete)
}

View File

@@ -13,6 +13,7 @@ import (
"bitbucket.org/nemt/nemt-portal-api/server/router/lyfthookroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/notificationroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/organizationroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/passwordresetroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/placesroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/profileroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/providerroute"
@@ -39,6 +40,7 @@ func Register(e *echo.Echo, cfg *config.Config, svc *applicationservice.Service,
externalroute.Register(prefixGroup.Group("/ext"), cfg, svc, tnc, notification)
authenticateroute.Register(prefixGroup.Group("/authenticate"), cfg, svc)
selfregisterroute.Register(prefixGroup.Group("/selfregister"), cfg, svc)
passwordresetroute.Register(prefixGroup.Group("/passwordreset"), cfg, svc)
appGroup := prefixGroup.Group("/" + cfg.App.Name)
usersroute.Register(appGroup.Group("/users"), cfg, svc)