Skip to content

Commit

Permalink
Merge pull request #12 from obenkenobi/feature/no-reactive
Browse files Browse the repository at this point in the history
Feature/no reactive
  • Loading branch information
obenkenobi authored Jan 9, 2023
2 parents 0fbc4f9 + 956a64b commit b182c4d
Show file tree
Hide file tree
Showing 45 changed files with 1,368 additions and 1,832 deletions.
134 changes: 60 additions & 74 deletions microservices/go/cmd/keyservice/businessrules/userkeybr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,54 @@ import (
"github.com/obenkenobi/cypher-log/microservices/go/pkg/apperrors"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/apperrors/validationutils"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/logger"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/reactive/single"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/sharedservices"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/utils"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/utils/cipherutils"
)

type UserKeyBr interface {
ValidateSessionTokenHash(session models.UserKeySession, tokenBytes []byte) single.Single[any]
ValidateKeyFromSession(userKeyGen models.UserKeyGenerator, key []byte) single.Single[any]
ValidateKeyFromPassword(userKeyGen models.UserKeyGenerator, key []byte) single.Single[any]
ValidateSessionTokenHash(session models.UserKeySession, tokenBytes []byte) error
ValidateKeyFromSession(userKeyGen models.UserKeyGenerator, key []byte) error
ValidateKeyFromPassword(userKeyGen models.UserKeyGenerator, key []byte) error
ValidateProxyKeyCiphersFromSession(
ctx context.Context,
proxyKey []byte,
userId string,
keyVersion int64,
session models.UserKeySession,
) single.Single[any]
) error
}

type UserKeyBrImpl struct {
errorService sharedservices.ErrorService
userService sharedservices.UserService
}

func (u UserKeyBrImpl) ValidateSessionTokenHash(session models.UserKeySession, tokenBytes []byte) single.Single[any] {
hashCheckSrc := single.FromSupplierCached(func() (bool, error) {
return cipherutils.VerifyHashWithSaltSHA256(session.TokenHash, tokenBytes)
})
tokenHashValidate := single.Map(hashCheckSrc, func(verified bool) []apperrors.RuleError {
var ruleErrs []apperrors.RuleError
if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}
return ruleErrs
})
return validationutils.PassRuleErrorsIfEmptyElsePassBadReqError(tokenHashValidate)
func (u UserKeyBrImpl) ValidateSessionTokenHash(session models.UserKeySession, tokenBytes []byte) error {
var ruleErrs []apperrors.RuleError
verified, err := cipherutils.VerifyHashWithSaltSHA256(session.TokenHash, tokenBytes)
if err != nil {
return err
}
if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}
return validationutils.MergeRuleErrors(ruleErrs)

}

func (u UserKeyBrImpl) ValidateKeyFromSession(userKeyGen models.UserKeyGenerator, key []byte) single.Single[any] {
verifiedKeyHashSrc := single.FromSupplierCached(func() (bool, error) {
return cipherutils.VerifyKeyHashBcrypt(userKeyGen.KeyHash, key)
})
keyHashValidationSrc := single.Map(verifiedKeyHashSrc, func(verified bool) []apperrors.RuleError {
var ruleErrs []apperrors.RuleError
if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}
return ruleErrs
})
return validationutils.PassRuleErrorsIfEmptyElsePassBadReqError(keyHashValidationSrc)
func (u UserKeyBrImpl) ValidateKeyFromSession(userKeyGen models.UserKeyGenerator, key []byte) error {
var ruleErrs []apperrors.RuleError

verified, err := cipherutils.VerifyKeyHashBcrypt(userKeyGen.KeyHash, key)
if err != nil {
return err
}
if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}

return validationutils.MergeRuleErrors(ruleErrs)
}

func (u UserKeyBrImpl) ValidateProxyKeyCiphersFromSession(
Expand All @@ -65,56 +62,45 @@ func (u UserKeyBrImpl) ValidateProxyKeyCiphersFromSession(
userId string,
keyVersion int64,
session models.UserKeySession,
) single.Single[any] {
validateProxyKeyCiphersSrc := single.FromSupplierCached(func() ([]apperrors.RuleError, error) {
var ruleErrs []apperrors.RuleError
) error {
var ruleErrs []apperrors.RuleError

// Validate Proxy Key Ciphers
savedUserIdBytes, err := cipherutils.DecryptAES(proxyKey, session.UserIdCipher)
if err != nil {
logger.Log.WithError(err).Debug()
return err
}
userIdInvalid := string(savedUserIdBytes) != userId
savedKeyVersionBytes, err := cipherutils.DecryptAES(proxyKey, session.KeyVersionCipher)
if err != nil {
logger.Log.WithError(err).Debug()
return err
}
keyInvalid := string(savedKeyVersionBytes) != utils.Int64ToStr(keyVersion)

savedUserIdBytes, err := cipherutils.DecryptAES(proxyKey, session.UserIdCipher)
if err != nil {
logger.Log.WithError(err).Debug()
return ruleErrs, err
}
userIdInvalid := string(savedUserIdBytes) != userId
if userIdInvalid || keyInvalid {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}

savedKeyVersionBytes, err := cipherutils.DecryptAES(proxyKey, session.KeyVersionCipher)
if err != nil {
logger.Log.WithError(err).Debug()
return ruleErrs, err
}
keyInvalid := string(savedKeyVersionBytes) != utils.Int64ToStr(keyVersion)
// Validate User Exists
userExists, err := u.userService.UserExistsWithId(ctx, userId)
if !userExists {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}

if userIdInvalid || keyInvalid {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}
return ruleErrs, nil
})
validateUserExists := single.MapWithError(u.userService.UserExistsWithId(ctx, userId),
func(exists bool) ([]apperrors.RuleError, error) {
var ruleErrs []apperrors.RuleError
if !exists {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeInvalidSession))
}
return ruleErrs, nil
})
ruleErrs := validationutils.ConcatSinglesOfRuleErrs(validateProxyKeyCiphersSrc, validateUserExists)
return validationutils.PassRuleErrorsIfEmptyElsePassBadReqError(ruleErrs)
return validationutils.MergeRuleErrors(ruleErrs)
}

func (u UserKeyBrImpl) ValidateKeyFromPassword(
userKeyGen models.UserKeyGenerator,
key []byte,
) single.Single[any] {
verifiedKeyHashSrc := single.FromSupplierCached(func() (bool, error) {
return cipherutils.VerifyKeyHashBcrypt(userKeyGen.KeyHash, key)
})
keyHashValidationSrc := single.Map(verifiedKeyHashSrc, func(verified bool) []apperrors.RuleError {
var ruleErrs []apperrors.RuleError
if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeIncorrectPasscode))
}
return ruleErrs
})
return validationutils.PassRuleErrorsIfEmptyElsePassBadReqError(keyHashValidationSrc)
func (u UserKeyBrImpl) ValidateKeyFromPassword(userKeyGen models.UserKeyGenerator, key []byte) error {
var ruleErrs []apperrors.RuleError
verified, err := cipherutils.VerifyKeyHashBcrypt(userKeyGen.KeyHash, key)
if err != nil {
return err
} else if !verified {
ruleErrs = append(ruleErrs, u.errorService.RuleErrorFromCode(apperrors.ErrCodeIncorrectPasscode))
}
return validationutils.MergeRuleErrors(ruleErrs)
}

func NewUserKeyBrImpl(errorService sharedservices.ErrorService, userService sharedservices.UserService) *UserKeyBrImpl {
Expand Down
99 changes: 61 additions & 38 deletions microservices/go/cmd/keyservice/controllers/userkeycontroller.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package controllers

import (
"github.com/barweiss/go-tuple"
"github.com/gin-gonic/gin"
"github.com/obenkenobi/cypher-log/microservices/go/cmd/keyservice/services"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/middlewares"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/businessobjects/userbos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/dtos/commondtos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/dtos/keydtos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/reactive/single"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/security"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/sharedservices"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/sharedservices/ginservices"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/web/controller"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/web/routing"
"net/http"
)

type UserKeyController interface {
Expand All @@ -33,57 +32,81 @@ func (u UserKeyControllerImpl) AddRoutes(r *gin.Engine) {
userKeyGroupV1.GET("/exists",
u.authMiddleware.Authorization(middlewares.AuthorizerSettings{VerifyIsUser: true}),
func(c *gin.Context) {
reqUserSrc := u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
businessLogicSrc := single.FlatMap(reqUserSrc,
func(userBos userbos.UserBo) single.Single[commondtos.ExistsDto] {
return u.userKeyService.UserKeyExists(c, userBos)
},
)
resBody, err := single.RetrieveValue(c, businessLogicSrc)
u.ginCtxService.RespondJsonOkOrError(c, resBody, err)
var userBo userbos.UserBo
var resBody commondtos.ExistsDto

u.ginCtxService.StartCtxPipeline(c).Next(func() (err error) {
userBo, err = u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
return
}).Next(func() (err error) {
resBody, err = u.userKeyService.UserKeyExists(c, userBo)
return
}).Next(func() (err error) {
c.JSON(http.StatusOK, resBody)
return
})
})

userKeyGroupV1.POST("/passcode",
u.authMiddleware.Authorization(middlewares.AuthorizerSettings{VerifyIsUser: true}),
func(c *gin.Context) {
reqUserSrc := u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
bodySrc := ginservices.ReadValueFromBody[keydtos.PasscodeCreateDto](u.ginCtxService, c)
businessLogicSrc := single.FlatMap(single.Zip2(reqUserSrc, bodySrc),
func(t tuple.T2[userbos.UserBo, keydtos.PasscodeCreateDto]) single.Single[commondtos.SuccessDto] {
userBos, passcodeDto := t.V1, t.V2
return u.userKeyService.CreateUserKey(c, userBos, passcodeDto)
},
)
resBody, err := single.RetrieveValue(c, businessLogicSrc)
u.ginCtxService.RespondJsonOkOrError(c, resBody, err)
var userBo userbos.UserBo
var reqBody keydtos.PasscodeCreateDto
var resBody commondtos.SuccessDto

u.ginCtxService.StartCtxPipeline(c).Next(func() (err error) {
userBo, err = u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
return
}).Next(func() (err error) {
reqBody, err = ginservices.ReadValueFromBody[keydtos.PasscodeCreateDto](u.ginCtxService, c)
return
}).Next(func() (err error) {
resBody, err = u.userKeyService.CreateUserKey(c, userBo, reqBody)
return
}).Next(func() (err error) {
c.JSON(http.StatusOK, resBody)
return
})
})

userKeyGroupV1.POST("/newSession",
u.authMiddleware.Authorization(middlewares.AuthorizerSettings{VerifyIsUser: true}),
func(c *gin.Context) {
reqUserSrc := u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
bodySrc := ginservices.ReadValueFromBody[keydtos.PasscodeDto](u.ginCtxService, c)
businessLogicSrc := single.FlatMap(single.Zip2(reqUserSrc, bodySrc),
func(t tuple.T2[userbos.UserBo, keydtos.PasscodeDto]) single.Single[commondtos.UKeySessionDto] {
userBos, passcodeDto := t.V1, t.V2
return u.userKeyService.NewKeySession(c, userBos, passcodeDto)
},
)
resBody, err := single.RetrieveValue(c, businessLogicSrc)
u.ginCtxService.RespondJsonOkOrError(c, resBody, err)
var userBo userbos.UserBo
var reqBody keydtos.PasscodeDto
var resBody commondtos.UKeySessionDto

u.ginCtxService.StartCtxPipeline(c).Next(func() (err error) {
userBo, err = u.userService.RequireUser(c, security.GetIdentityFromGinContext(c))
return
}).Next(func() (err error) {
reqBody, err = ginservices.ReadValueFromBody[keydtos.PasscodeDto](u.ginCtxService, c)
return
}).Next(func() (err error) {
resBody, err = u.userKeyService.NewKeySession(c, userBo, reqBody)
return
}).Next(func() (err error) {
c.JSON(http.StatusOK, resBody)
return
})
})

userKeyGroupV1.POST("/getKeyFromSession",
u.authMiddleware.Authorization(middlewares.AuthorizerSettings{VerifyIsSystemClient: true}),
func(c *gin.Context) {
bodySrc := ginservices.ReadValueFromBody[commondtos.UKeySessionDto](u.ginCtxService, c)
businessLogicSrc := single.FlatMap(bodySrc,
func(sessionDto commondtos.UKeySessionDto) single.Single[keydtos.UserKeyDto] {
return u.userKeyService.GetKeyFromSession(c, sessionDto)
},
)
resBody, err := single.RetrieveValue(c, businessLogicSrc)
u.ginCtxService.RespondJsonOkOrError(c, resBody, err)
var reqBody commondtos.UKeySessionDto
var resBody keydtos.UserKeyDto

u.ginCtxService.StartCtxPipeline(c).Next(func() (err error) {
reqBody, err = ginservices.ReadValueFromBody[commondtos.UKeySessionDto](u.ginCtxService, c)
return
}).Next(func() (err error) {
resBody, err = u.userKeyService.GetKeyFromSession(c, reqBody)
return
}).Next(func() (err error) {
c.JSON(http.StatusOK, resBody)
return
})
})
}

Expand Down
17 changes: 7 additions & 10 deletions microservices/go/cmd/keyservice/grpcapis/userkeyservice-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"github.com/obenkenobi/cypher-log/microservices/go/pkg/grpc/gtools"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/grpc/userkeypb"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/dtos/commondtos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/dtos/keydtos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/reactive/single"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/sharedmappers/grpcmappers"
)

Expand All @@ -22,14 +20,13 @@ func (u UserKeyServiceServerImpl) GetKeyFromSession(
) (*userkeypb.UserKey, error) {
userKeySessionDto := commondtos.UKeySessionDto{}
grpcmappers.UserKeySessionToUserKeySessionDto(userKeySession, &userKeySessionDto)
keySrc := u.userKeyService.GetKeyFromSession(ctx, userKeySessionDto)
replySrc := single.Map(keySrc, func(keyDto keydtos.UserKeyDto) *userkeypb.UserKey {
userKey := &userkeypb.UserKey{}
grpcmappers.UserKeyDtoToUserKey(&keyDto, userKey)
return userKey
})
res, err := single.RetrieveValue(ctx, replySrc)
return res, gtools.ProcessErrorToGrpcStatusError(gtools.ReadAction, err)
keyDto, err := u.userKeyService.GetKeyFromSession(ctx, userKeySessionDto)
if err != nil {
return nil, gtools.ProcessErrorToGrpcStatusError(gtools.ReadAction, err)
}
userKey := &userkeypb.UserKey{}
grpcmappers.UserKeyDtoToUserKey(&keyDto, userKey)
return userKey, nil
}

func NewUserKeyServiceServerImpl(userKeyService services.UserKeyService) *UserKeyServiceServerImpl {
Expand Down
4 changes: 1 addition & 3 deletions microservices/go/cmd/keyservice/listeners/rmqlistener.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/obenkenobi/cypher-log/microservices/go/pkg/messaging/rmq"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/messaging/rmq/exchanges"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/objects/dtos/userdtos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/reactive/single"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/sharedservices/rmqservices"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/taskrunner"
"github.com/wagslane/go-rabbitmq"
Expand Down Expand Up @@ -36,8 +35,7 @@ func (r RmqListenerImpl) ListenUserChange() {
rabbitmq.WithConsumeOptionsQuorum,
)
userCreateReceiver.Listen(func(d msg.Delivery[userdtos.UserChangeEventDto]) msg.ReceiverAction {
resSrc := r.userChangeEventService.HandleUserChangeEventTransaction(r.ctx, d.Body())
res, err := single.RetrieveValue(r.ctx, resSrc)
res, err := r.userChangeEventService.HandleUserChangeEventTransaction(r.ctx, d.Body())
if err != nil {
return d.Resend()
} else if res.Discarded {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"github.com/obenkenobi/cypher-log/microservices/go/cmd/keyservice/models"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/datasource/baserepos"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/datasource/dshandlers"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/reactive/single"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/utils/kvstoreutils"
"github.com/obenkenobi/cypher-log/microservices/go/pkg/wrappers/option"
"time"
Expand All @@ -20,7 +19,7 @@ type AppSecretRepositoryImpl struct {
baseRepo baserepos.KeyValueTimedRepository[models.AppSecret]
}

func (a AppSecretRepositoryImpl) Get(ctx context.Context, key string) single.Single[option.Maybe[models.AppSecret]] {
func (a AppSecretRepositoryImpl) Get(ctx context.Context, key string) (option.Maybe[models.AppSecret], error) {
return a.baseRepo.Get(ctx, kvstoreutils.CombineKeySections(a.prefix, key))
}

Expand All @@ -29,7 +28,7 @@ func (a AppSecretRepositoryImpl) Set(
key string,
value models.AppSecret,
expiration time.Duration,
) single.Single[models.AppSecret] {
) (models.AppSecret, error) {
return a.baseRepo.Set(ctx, kvstoreutils.CombineKeySections(a.prefix, key), value, expiration)
}

Expand Down
Loading

0 comments on commit b182c4d

Please sign in to comment.