From 8673eb9869f35cc037db969d27b771b6183aa4a7 Mon Sep 17 00:00:00 2001 From: Donovan Date: Sat, 17 Aug 2024 21:40:04 -0500 Subject: [PATCH] move user and customer files --- customer.go | 111 ++++++++++++++++++ customer/customer.go | 1 - ...er_attributes.go => customer_attributes.go | 10 +- ...mer_attributes_test.go => customer_test.go | 2 +- go.mod | 1 + go.sum | 2 + user.go | 17 +++ ...user_cipher_keys.go => user_cipher_keys.go | 31 +++-- users/user_interface.go => user_interface.go | 18 ++- users/user_test.go => user_test.go | 7 +- users/user.go | 1 - 11 files changed, 178 insertions(+), 23 deletions(-) create mode 100644 customer.go delete mode 100644 customer/customer.go rename customer/customer_attributes.go => customer_attributes.go (87%) rename customer/customer_attributes_test.go => customer_test.go (93%) create mode 100644 user.go rename users/user_cipher_keys.go => user_cipher_keys.go (86%) rename users/user_interface.go => user_interface.go (87%) rename users/user_test.go => user_test.go (95%) delete mode 100644 users/user.go diff --git a/customer.go b/customer.go new file mode 100644 index 0000000..f0b2733 --- /dev/null +++ b/customer.go @@ -0,0 +1,111 @@ +package main + +import ( + "errors" + "fmt" + "github.com/google/uuid" + m "go-nkode/models" + py "go-nkode/py-builtin" +) + +type Customer struct { + CustomerId uuid.UUID + NKodePolicy m.NKodePolicy + Attributes CustomerAttributes + Users map[string]User +} + +func NewCustomer(keypadSize m.KeypadSize, nkodePolicy m.NKodePolicy) (*Customer, error) { + if keypadSize.TotalAttrs() < nkodePolicy.DistinctAttributes { + return nil, errors.New(fmt.Sprintf("incompadible nkode policy and keypad size TotalAttrs: %d < DistinctAttributes: %d", keypadSize.TotalAttrs(), nkodePolicy.DistinctAttributes)) + } + + if keypadSize.AttrsPerKey < nkodePolicy.DistinctSets { + return nil, errors.New(fmt.Sprintf("incompadible nkode policy and keypad size AttrPerKey: %d < DistinctSets: %d", keypadSize.AttrsPerKey, nkodePolicy.DistinctSets)) + } + customerAttrs, err := NewCustomerAttributes(keypadSize) + if err != nil { + return nil, err + } + customer := Customer{ + CustomerId: uuid.New(), + NKodePolicy: nkodePolicy, + Attributes: *customerAttrs, + Users: make(map[string]User), + } + + return &customer, nil +} + +func (c *Customer) AddNewUser(user User) error { + _, exists := c.Users[user.Username] + if exists { + return errors.New(fmt.Sprintf("user: %s exists", user.Username)) + } + c.Users[user.Username] = user + return nil +} + +func (c *Customer) ValidKeyEntryAndRenew(username string, selectedKeys []int) error { + user, exists := c.Users[username] + if !exists { + return errors.New(fmt.Sprintf("user %s does not exist for customer %s", username, c.CustomerId.String())) + } + + validKeys := py.All[int](selectedKeys, func(idx int) bool { + return 0 <= idx && idx < c.Attributes.keypadSize.NumbOfKeys + }) + if !validKeys { + return errors.New(fmt.Sprintf("one or more keys not in range 0-%d", c.Attributes.keypadSize.NumbOfKeys-1)) + } + presumedAttrIdxVals, err := c.getPresumedAttributeIdxVals(user, selectedKeys) + if err != nil { + return err + } + + err = user.UserKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, c.Attributes) + if err != nil { + return err + } + + if user.Renew { + // renew + } + return nil + +} + +func (c *Customer) getPresumedAttributeIdxVals(user User, selectedKeys []int) ([]int, error) { + + passcodeLen := len(selectedKeys) + if passcodeLen < c.NKodePolicy.MinNkodeLen || passcodeLen > c.NKodePolicy.MaxNkodeLen { + return nil, errors.New(fmt.Sprintf("Invalid passcode length of %d. Passcode length must be in range %d-%d", passcodeLen, c.NKodePolicy.MinNkodeLen, c.NKodePolicy.MaxNkodeLen)) + } + passcodeSetVals, err := user.DecipherMask(c.Attributes.SetVals, passcodeLen) + if err != nil { + return nil, err + } + presumedAttrIdxVals := make([]int, passcodeLen) + + for idx := range presumedAttrIdxVals { + keyNumb := selectedKeys[idx] + setIdx, err := c.Attributes.IndexOfSet(passcodeSetVals[idx]) + if err != nil { + return nil, err + } + selectedAttrIdx, err := user.Interface.GetAttrIdxByKeyNumbSetIdx(setIdx, keyNumb) + if err != nil { + return nil, err + } + presumedAttrIdxVals[idx] = selectedAttrIdx + } + return presumedAttrIdxVals, nil +} + +func (c *Customer) IsValidNKode(passcodeAttrIdx []int) error { + nkodeLen := len(passcodeAttrIdx) + if nkodeLen < c.NKodePolicy.MinNkodeLen { + return errors.New(fmt.Sprintf("NKode length %d is too short. Minimum nKode length is %d", nkodeLen, c.NKodePolicy.MinNkodeLen)) + } + return nil +} diff --git a/customer/customer.go b/customer/customer.go deleted file mode 100644 index 943abb2..0000000 --- a/customer/customer.go +++ /dev/null @@ -1 +0,0 @@ -package customer diff --git a/customer/customer_attributes.go b/customer_attributes.go similarity index 87% rename from customer/customer_attributes.go rename to customer_attributes.go index 52f2037..d04bdfe 100644 --- a/customer/customer_attributes.go +++ b/customer_attributes.go @@ -1,4 +1,4 @@ -package customer +package main import ( "errors" @@ -55,9 +55,13 @@ func (c *CustomerAttributes) IndexOfAttr(attrVal uint64) int { return util.IndexOf[uint64](c.AttrVals, attrVal) } -func (c *CustomerAttributes) IndexOfSet(setVal uint64) int { +func (c *CustomerAttributes) IndexOfSet(setVal uint64) (int, error) { // TODO: should this be mapped instead? - return util.IndexOf[uint64](c.SetVals, setVal) + idx := util.IndexOf[uint64](c.SetVals, setVal) + if idx == -1 { + return -1, errors.New(fmt.Sprintf("Set Val %d is invalid", setVal)) + } + return idx, nil } func (c *CustomerAttributes) GetAttrSetVal(attrVal uint64) (uint64, error) { diff --git a/customer/customer_attributes_test.go b/customer_test.go similarity index 93% rename from customer/customer_attributes_test.go rename to customer_test.go index e30874c..1b0ca85 100644 --- a/customer/customer_attributes_test.go +++ b/customer_test.go @@ -1,4 +1,4 @@ -package customer +package main import ( "github.com/stretchr/testify/assert" diff --git a/go.mod b/go.mod index 19e9492..8f6a6eb 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index fc8de62..eb14d14 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= diff --git a/user.go b/user.go new file mode 100644 index 0000000..6fe5e0d --- /dev/null +++ b/user.go @@ -0,0 +1,17 @@ +package main + +import ( + m "go-nkode/models" +) + +type User struct { + Username string + EncipheredPasscode m.EncipheredNKode + UserKeys UserCipherKeys + Interface UserInterface + Renew bool +} + +func (u *User) DecipherMask(setVals []uint64, passcodeLen int) ([]uint64, error) { + return u.UserKeys.DecipherMask(u.EncipheredPasscode.Mask, setVals, passcodeLen) +} diff --git a/users/user_cipher_keys.go b/user_cipher_keys.go similarity index 86% rename from users/user_cipher_keys.go rename to user_cipher_keys.go index 45d2b23..cdb9502 100644 --- a/users/user_cipher_keys.go +++ b/user_cipher_keys.go @@ -1,10 +1,9 @@ -package users +package main import ( "crypto/sha256" "errors" "fmt" - "go-nkode/customer" "go-nkode/models" "go-nkode/util" "golang.org/x/crypto/bcrypt" @@ -60,30 +59,35 @@ func (u *UserCipherKeys) PadUserMask(userMask []uint64, setVals []uint64) ([]uin return paddedUserMask, nil } -func (u *UserCipherKeys) ValidPassword(hashedPassword []byte, passcodeAttrIdx []int, customerAttrs customer.CustomerAttributes) error { +func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []int, customerAttrs CustomerAttributes) error { + hashBytes := []byte(hashedPassword) passcodeCipher := u.encipherCode(passcodeAttrIdx, customerAttrs) passwordDigest, err := u.saltAndDigest(passcodeCipher) if err != nil { return err } - err = bcrypt.CompareHashAndPassword(hashedPassword, passwordDigest) + err = bcrypt.CompareHashAndPassword(hashBytes, passwordDigest) if err != nil { return err } return nil } -func (u *UserCipherKeys) EncipherSaltHashCode(passcodeAttrIdx []int, customerAttrs customer.CustomerAttributes) ([]byte, error) { +func (u *UserCipherKeys) EncipherSaltHashCode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (string, error) { passcodeCipher := u.encipherCode(passcodeAttrIdx, customerAttrs) passcodeDigest, err := u.saltAndDigest(passcodeCipher) if err != nil { - return nil, err + return "", err } - return u.hashPasscode(passcodeDigest) + passcodeBytes, err := u.hashPasscode(passcodeDigest) + if err != nil { + return "", err + } + return string(passcodeBytes), nil } -func (u *UserCipherKeys) encipherCode(passcodeAttrIdx []int, customerAttrs customer.CustomerAttributes) []uint64 { +func (u *UserCipherKeys) encipherCode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) []uint64 { passcodeLen := len(passcodeAttrIdx) passcodeCipher := make([]uint64, u.MaxNKodeLen) @@ -118,7 +122,7 @@ func (u *UserCipherKeys) hashPasscode(passcodeDigest []byte) ([]byte, error) { } return hashedPassword, nil } -func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs customer.CustomerAttributes) (string, error) { +func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs CustomerAttributes) (string, error) { paddedPasscodeSets, err := u.PadUserMask(passcodeSet, customerAttrs.SetVals) if err != nil { return "", err @@ -126,7 +130,10 @@ func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs custom cipheredMask := make([]uint64, len(paddedPasscodeSets)) for idx := range paddedPasscodeSets { - setIdx := customerAttrs.IndexOfSet(paddedPasscodeSets[idx]) + setIdx, err := customerAttrs.IndexOfSet(paddedPasscodeSets[idx]) + if err != nil { + return "", err + } setKeyVal := u.SetKey[setIdx] maskKeyVal := u.MaskKey[idx] setVal := paddedPasscodeSets[idx] @@ -158,7 +165,7 @@ func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen return passcodeSet, nil } -func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs customer.CustomerAttributes) (*models.EncipheredNKode, error) { +func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*models.EncipheredNKode, error) { code, err := u.EncipherSaltHashCode(passcodeAttrIdx, customerAttrs) if err != nil { return nil, err @@ -174,7 +181,7 @@ func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs cust } mask, err := u.EncipherMask(passcodeSet, customerAttrs) encipheredCode := models.EncipheredNKode{ - Code: string(code), + Code: code, Mask: mask, } return &encipheredCode, nil diff --git a/users/user_interface.go b/user_interface.go similarity index 87% rename from users/user_interface.go rename to user_interface.go index 077ab09..1d7c40e 100644 --- a/users/user_interface.go +++ b/user_interface.go @@ -1,7 +1,8 @@ -package users +package main import ( "errors" + "fmt" "go-nkode/hashset" "go-nkode/models" "go-nkode/util" @@ -174,3 +175,18 @@ func (u *UserInterface) PartialInterfaceShuffle() error { u.IdxInterface = util.MatrixToList(keypadView) return nil } + +func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) { + if keyNumb < 0 || u.KeypadSize.NumbOfKeys <= keyNumb { + return -1, errors.New(fmt.Sprintf("keyNumb %d is out of range 0-%d", keyNumb, u.KeypadSize.NumbOfKeys)) + } + + if setIdx < 0 || u.KeypadSize.AttrsPerKey <= setIdx { + return -1, errors.New(fmt.Sprintf("setIdx %d is out of range 0-%d", setIdx, u.KeypadSize.AttrsPerKey)) + } + keypadView, err := u.InterfaceMatrix() + if err != nil { + return -1, err + } + return keypadView[keyNumb][setIdx], nil +} diff --git a/users/user_test.go b/user_test.go similarity index 95% rename from users/user_test.go rename to user_test.go index 57821ef..4a0aa30 100644 --- a/users/user_test.go +++ b/user_test.go @@ -1,8 +1,7 @@ -package users +package main import ( "github.com/stretchr/testify/assert" - "go-nkode/customer" "go-nkode/models" py_builtin "go-nkode/py-builtin" "testing" @@ -11,7 +10,7 @@ import ( func TestUserCipherKeys_EncipherSaltHashCode(t *testing.T) { keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 5} maxNKodeLen := 10 - customerAttrs, err := customer.NewCustomerAttributes(keypadSize) + customerAttrs, err := NewCustomerAttributes(keypadSize) assert.NoError(t, err) newUser, err := NewUserCipherKeys(keypadSize, customerAttrs.SetVals, maxNKodeLen) assert.NoError(t, err) @@ -26,7 +25,7 @@ func TestUserCipherKeys_EncipherDecipherMask(t *testing.T) { keypadSize := models.KeypadSize{AttrsPerKey: 10, NumbOfKeys: 5} maxNKodeLen := 10 - customerAttrs, err := customer.NewCustomerAttributes(keypadSize) + customerAttrs, err := NewCustomerAttributes(keypadSize) assert.NoError(t, err) newUser, err := NewUserCipherKeys(keypadSize, customerAttrs.SetVals, maxNKodeLen) assert.NoError(t, err) diff --git a/users/user.go b/users/user.go deleted file mode 100644 index 82abcb9..0000000 --- a/users/user.go +++ /dev/null @@ -1 +0,0 @@ -package users