implement and test forget and reset nkode

This commit is contained in:
2025-01-31 10:26:30 -06:00
parent 6dd84e4ca3
commit 9ee27f14cf
7 changed files with 114 additions and 17 deletions

View File

@@ -258,7 +258,7 @@ func (n *NKodeAPI) ForgotNKode(userEmail entities.UserEmail, customerId entities
return nil return nil
} }
nkodeResetJwt, err := security.ResetNKodeToken(string(userEmail), uuid.UUID(customerId)) nkodeResetJwt, err := security.ResetNKodeToken(string(userEmail), uuid.UUID(customerId).String())
if err != nil { if err != nil {
return err return err
} }

View File

@@ -39,11 +39,13 @@ func (h *NkodeHandler) RegisterRoutes(r *gin.Engine) {
r.POST("/refresh-token", h.RefreshTokenHandler) r.POST("/refresh-token", h.RefreshTokenHandler)
r.POST("/forgot-nkode", h.ForgotNKodeHandler) r.POST("/forgot-nkode", h.ForgotNKodeHandler)
r.POST("/signout", h.SignoutHandler) r.POST("/signout", h.SignoutHandler)
r.POST("/reset", h.ResetHandler) r.POST("/reset-nkode", h.ResetHandler)
} }
} }
func (h *NkodeHandler) CreateNewCustomerHandler(c *gin.Context) { func (h *NkodeHandler) CreateNewCustomerHandler(c *gin.Context) {
h.Logger.Println("create new customer")
var newCustomerPost entities.NKodePolicy var newCustomerPost entities.NKodePolicy
if err := c.ShouldBind(&newCustomerPost); err != nil { if err := c.ShouldBind(&newCustomerPost); err != nil {
handleError(c, err) handleError(c, err)
@@ -217,7 +219,7 @@ func (h *NkodeHandler) RenewAttributesHandler(c *gin.Context) {
return return
} }
if err := h.API.RenewAttributes(entities.CustomerId(customerId)); err != nil { if err = h.API.RenewAttributes(entities.CustomerId(customerId)); err != nil {
handleError(c, err) handleError(c, err)
return return
} }

View File

@@ -20,7 +20,7 @@ import (
"testing" "testing"
) )
func TestNkodeAPI(t *testing.T) { func TestNKodeAPI(t *testing.T) {
tr := NewTestRouter() tr := NewTestRouter()
tr.Start() tr.Start()
defer func(tr *TestRouter) { defer func(tr *TestRouter) {
@@ -34,10 +34,9 @@ func TestNkodeAPI(t *testing.T) {
attrPerKey := 9 attrPerKey := 9
numKeys := 6 numKeys := 6
userEmail := "test_username" + security.GenerateRandomString(12) + "@example.com" userEmail := "test_username" + security.GenerateRandomString(12) + "@example.com"
reset := false
// *** Signup *** // *** Signup ***
resp, status, err := tr.Signup(customerID, attrPerKey, numKeys, userEmail, reset) resp, status, err := tr.Signup(customerID, attrPerKey, numKeys, userEmail)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 200, status) assert.Equal(t, 200, status)
@@ -82,7 +81,54 @@ func TestNkodeAPI(t *testing.T) {
assert.NotEmpty(t, tokens.RefreshToken) assert.NotEmpty(t, tokens.RefreshToken)
// *** Renew Attributes *** // *** Renew Attributes ***
status, err = tr.RenewAttributes(customerID)
assert.NoError(t, err)
assert.Equal(t, 200, status)
loginInterface, status, err = tr.GetLoginInterface(userEmail, customerID)
assert.NoError(t, err)
loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
tokens, status, err = tr.Login(customerID, userEmail, loginKeySelection)
assert.NoError(t, err)
// *** Test Forgot nKode ***
status, err = tr.ForgotNKode(customerID, userEmail)
assert.NoError(t, err)
assert.Equal(t, 200, status)
// *** Test Reset nKode ***
nkodeResetJwt, err := security.ResetNKodeToken(userEmail, customerID)
assert.NoError(t, err)
resetResp, status, err := tr.Reset(customerID, attrPerKey, numKeys, userEmail, nkodeResetJwt)
assert.NoError(t, err)
assert.Equal(t, 200, status)
assert.NotEmpty(t, resetResp.SessionId)
userPasscode = resetResp.UserIdxInterface[:passcodeLen]
setKeySelection, err = entities.SelectKeyByAttrIdx(resetResp.UserIdxInterface, userPasscode, kpSet)
assert.NoError(t, err)
confirmInterface, status, err = tr.SetNKode(customerID, setKeySelection, resetResp.SessionId)
assert.NoError(t, err)
assert.Equal(t, 200, status)
confirmKeySelection, err = entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, kpSet)
assert.NoError(t, err)
status, err = tr.ConfirmNKode(customerID, confirmKeySelection, resetResp.SessionId)
assert.NoError(t, err)
assert.Equal(t, 200, status)
loginInterface, status, err = tr.GetLoginInterface(userEmail, customerID)
assert.NoError(t, err)
assert.Equal(t, 200, status)
loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
tokens, status, err = tr.Login(customerID, userEmail, loginKeySelection)
assert.NoError(t, err)
assert.Equal(t, 200, status)
assert.NotEmpty(t, tokens.AccessToken)
assert.NotEmpty(t, tokens.RefreshToken)
// *** Test Reset nKode with invalid token ***
_, status, err = tr.Reset(customerID, attrPerKey, numKeys, userEmail, "invalid token")
assert.Error(t, err)
assert.Equal(t, 403, status)
} }
type TestRouter struct { type TestRouter struct {
@@ -102,8 +148,8 @@ func NewTestRouter() *TestRouter {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
sesClient := email.NewSESClient() emailClient := email.TestEmailClient{}
emailQueue := email.NewEmailQueue(email.EmailQueueBufferSize, email.MaxEmailsPerSecond, &sesClient) emailQueue := email.NewEmailQueue(email.EmailQueueBufferSize, email.MaxEmailsPerSecond, &emailClient)
nkodeAPI := api.NewNKodeAPI(repo, emailQueue) nkodeAPI := api.NewNKodeAPI(repo, emailQueue)
h := NkodeHandler{ h := NkodeHandler{
API: nkodeAPI, API: nkodeAPI,
@@ -157,15 +203,13 @@ func (r *TestRouter) Signup(
attrsPerKey int, attrsPerKey int,
numberOfKeys int, numberOfKeys int,
userEmail string, userEmail string,
reset bool,
) (*entities.SignupResetInterface, int, error) { ) (*entities.SignupResetInterface, int, error) {
body := bytes.NewBufferString(fmt.Sprintf( body := bytes.NewBufferString(fmt.Sprintf(
"customer_id=%s&attrs_per_key=%d&numb_of_keys=%d&email=%s&reset=%t", "customer_id=%s&attrs_per_key=%d&numb_of_keys=%d&email=%s",
customerID, customerID,
attrsPerKey, attrsPerKey,
numberOfKeys, numberOfKeys,
userEmail, userEmail,
reset,
)) ))
req := httptest.NewRequest(http.MethodPost, "/signup", body) req := httptest.NewRequest(http.MethodPost, "/signup", body)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@@ -290,3 +334,48 @@ func (r *TestRouter) RenewAttributes(
r.Router.ServeHTTP(rec, req) r.Router.ServeHTTP(rec, req)
return rec.Code, nil return rec.Code, nil
} }
func (r *TestRouter) ForgotNKode(
customerID string,
userEmail string,
) (int, error) {
data := models.ForgotNKodePost{
CustomerId: customerID,
UserEmail: userEmail,
}
body, err := json.Marshal(data)
if err != nil {
return 0, err
}
req := httptest.NewRequest(http.MethodPost, "/forgot-nkode", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
r.Router.ServeHTTP(rec, req)
return rec.Code, nil
}
func (r *TestRouter) Reset(
customerID string,
attrsPerKey int,
numberOfKeys int,
userEmail string,
resetAuthToken string,
) (*entities.SignupResetInterface, int, error) {
body := bytes.NewBufferString(fmt.Sprintf(
"customer_id=%s&attrs_per_key=%d&numb_of_keys=%d&email=%s",
customerID,
attrsPerKey,
numberOfKeys,
userEmail,
))
req := httptest.NewRequest(http.MethodPost, "/reset-nkode", body)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "Bearer "+resetAuthToken)
rec := httptest.NewRecorder()
r.Router.ServeHTTP(rec, req)
var resp entities.SignupResetInterface
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
return nil, rec.Code, err
}
return &resp, rec.Code, nil
}

View File

@@ -40,9 +40,9 @@ type LoginInterfacePost struct {
} }
type LoginPost struct { type LoginPost struct {
CustomerId string `json:"customer_id" binding:"required"` CustomerId string `form:"customer_id" binding:"required"`
UserEmail string `json:"email" binding:"required"` UserEmail string `form:"email" binding:"required"`
KeySelection entities.KeySelection `json:"key_selection" binding:"required"` KeySelection entities.KeySelection `form:"key_selection" binding:"required"`
} }
type RenewAttributesPost struct { type RenewAttributesPost struct {

View File

@@ -115,12 +115,12 @@ func ClaimExpired(claims jwt.RegisteredClaims) error {
return config.ErrClaimExpOrNil return config.ErrClaimExpOrNil
} }
func ResetNKodeToken(userEmail string, customerId uuid.UUID) (string, error) { func ResetNKodeToken(userEmail string, customerId string) (string, error) {
resetClaims := ResetNKodeClaims{ resetClaims := ResetNKodeClaims{
true, true,
jwt.RegisteredClaims{ jwt.RegisteredClaims{
Subject: userEmail, Subject: userEmail,
Issuer: customerId.String(), Issuer: customerId,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(resetNKodeTokenExp)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(resetNKodeTokenExp)),
}, },
} }

View File

@@ -19,7 +19,7 @@ func TestJwtClaims(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, refreshToken.Subject, email) assert.Equal(t, refreshToken.Subject, email)
assert.NoError(t, ClaimExpired(*refreshToken)) assert.NoError(t, ClaimExpired(*refreshToken))
resetNKode, err := ResetNKodeToken(email, customerId) resetNKode, err := ResetNKodeToken(email, customerId.String())
assert.NoError(t, err) assert.NoError(t, err)
resetToken, err := ParseRestNKodeToken(resetNKode) resetToken, err := ParseRestNKodeToken(resetNKode)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -48,3 +48,9 @@ type User struct {
LastLogin interface{} LastLogin interface{}
CreatedAt sql.NullString CreatedAt sql.NullString
} }
type UserPermission struct {
ID int64
UserID string
Permission string
}