refactor db accessor

This commit is contained in:
2024-08-26 13:10:34 -05:00
parent 3bf2b4d71f
commit e6947e714d
19 changed files with 516 additions and 302 deletions

View File

@@ -1,5 +1,9 @@
package m package m
import (
"errors"
)
type NKodePolicy struct { type NKodePolicy struct {
MaxNkodeLen int `json:"max_nkode_len"` MaxNkodeLen int `json:"max_nkode_len"`
MinNkodeLen int `json:"min_nkode_len"` MinNkodeLen int `json:"min_nkode_len"`
@@ -19,3 +23,13 @@ func NewDefaultNKodePolicy() NKodePolicy {
Expiration: -1, Expiration: -1,
} }
} }
var InvalidNKodeLen = errors.New("invalid nkode length")
func (p *NKodePolicy) ValidLength(nkodeLen int) error {
if nkodeLen < p.MinNkodeLen || nkodeLen > p.MaxNkodeLen {
return InvalidNKodeLen
}
return nil
}

View File

@@ -60,6 +60,8 @@ type GetLoginInterfaceResp struct {
type KeySelection []int type KeySelection []int
type CustomerId uuid.UUID type CustomerId uuid.UUID
type SessionId uuid.UUID type SessionId uuid.UUID
type UserId uuid.UUID
type Username string type Username string
type IdxInterface []int type IdxInterface []int

89
core/nkode/common.go Normal file
View File

@@ -0,0 +1,89 @@
package nkode
import (
"errors"
"github.com/google/uuid"
m "go-nkode/core/model"
py "go-nkode/py-builtin"
)
var KeyIndexOutOfRange error = errors.New("one or more keys is out of range")
func ValidKeyEntry(user User, customer Customer, selectedKeys []int) ([]int, error) {
validKeys := py.All[int](selectedKeys, func(idx int) bool {
return 0 <= idx && idx < user.Kp.NumbOfKeys
})
if !validKeys {
panic(KeyIndexOutOfRange)
}
var err error
passcodeLen := len(selectedKeys)
err = customer.NKodePolicy.ValidLength(passcodeLen)
if err != nil {
return nil, err
}
setVals, err := customer.Attributes.SetVals(user.Kp)
if err != nil {
return nil, err
}
passcodeSetVals, err := user.DecipherMask(setVals, passcodeLen)
if err != nil {
return nil, err
}
presumedAttrIdxVals := make([]int, passcodeLen)
for idx := range presumedAttrIdxVals {
keyNumb := selectedKeys[idx]
setIdx, err := customer.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
}
err = customer.IsValidNKode(user.Kp, presumedAttrIdxVals)
if err != nil {
panic(err)
}
attrVals, err := customer.Attributes.AttrVals(user.Kp)
if err != nil {
panic(err)
}
err = user.UserKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, attrVals)
if err != nil {
return nil, err
}
return presumedAttrIdxVals, nil
}
func NewUser(customer Customer, username m.Username, passcodeIdx []int, ui UserInterface, kp m.KeypadDimension) (*User, error) {
setVals, err := customer.Attributes.SetVals(kp)
if err != nil {
return nil, err
}
newKeys, err := NewUserCipherKeys(&kp, setVals, customer.NKodePolicy.MaxNkodeLen)
if err != nil {
return nil, err
}
encipheredNKode, err := newKeys.EncipherNKode(passcodeIdx, customer.Attributes)
if err != nil {
return nil, err
}
newUser := User{
Id: m.UserId(uuid.New()),
Username: username,
EncipheredPasscode: *encipheredNKode,
UserKeys: *newKeys,
Interface: ui,
Kp: kp,
CustomerId: customer.Id,
}
return &newUser, nil
}

View File

@@ -11,10 +11,9 @@ import (
) )
type Customer struct { type Customer struct {
CustomerId m.CustomerId Id m.CustomerId
NKodePolicy m.NKodePolicy NKodePolicy m.NKodePolicy
Attributes CustomerAttributes Attributes CustomerAttributes
Users map[m.Username]User
} }
func NewCustomer(nkodePolicy m.NKodePolicy) (*Customer, error) { func NewCustomer(nkodePolicy m.NKodePolicy) (*Customer, error) {
@@ -23,106 +22,106 @@ func NewCustomer(nkodePolicy m.NKodePolicy) (*Customer, error) {
return nil, err return nil, err
} }
customer := Customer{ customer := Customer{
CustomerId: m.CustomerId(uuid.New()), Id: m.CustomerId(uuid.New()),
NKodePolicy: nkodePolicy, NKodePolicy: nkodePolicy,
Attributes: *customerAttrs, Attributes: *customerAttrs,
Users: make(map[m.Username]User),
} }
return &customer, nil return &customer, nil
} }
func (c *Customer) AddNewUser(username m.Username, passcodeIdx []int, ui UserInterface, kp m.KeypadDimension) error { //func (c *Customer) AddNewUser(username m.Username, passcodeIdx []int, ui UserInterface, kp m.KeypadDimension) error {
_, exists := c.Users[username] // _, exists := c.Users[username]
if exists { // if exists {
return errors.New(fmt.Sprintf("User %s already exists for customer %+v exists", username, c.CustomerId)) // return errors.New(fmt.Sprintf("User %s already exists for customer %+v exists", username, c.Id))
} // }
setVals, err := c.Attributes.SetVals(kp) // setVals, err := c.Attributes.SetVals(kp)
if err != nil { // if err != nil {
return err // return err
} // }
newKeys, err := NewUserCipherKeys(&kp, setVals, c.NKodePolicy.MaxNkodeLen) // newKeys, err := NewUserCipherKeys(&kp, setVals, c.NKodePolicy.MaxNkodeLen)
if err != nil { // if err != nil {
return err // return err
} // }
encipheredNKode, err := newKeys.EncipherNKode(passcodeIdx, c.Attributes) // encipheredNKode, err := newKeys.EncipherNKode(passcodeIdx, c.Attributes)
if err != nil { // if err != nil {
return err // return err
} // }
newUser := User{ // newUser := User{
Username: username, // Id: m.UserId(uuid.New()),
EncipheredPasscode: *encipheredNKode, // Username: username,
UserKeys: *newKeys, // EncipheredPasscode: *encipheredNKode,
Interface: ui, // UserKeys: *newKeys,
Kp: kp, // Interface: ui,
} // Kp: kp,
c.Users[username] = newUser // }
return nil // c.Users[username] = newUser
} // return nil
//}
func (c *Customer) ValidKeyEntry(username m.Username, selectedKeys []int) ([]int, error) { //func (c *Customer) ValidKeyEntry(username m.Username, selectedKeys []int) ([]int, error) {
user, exists := c.Users[username] // user, exists := c.Users[username]
if !exists { // if !exists {
return nil, errors.New(fmt.Sprintf("user %s does not exist for customer %+v", username, c.CustomerId)) // return nil, errors.New(fmt.Sprintf("user %s does not exist for customer %+v", username, c.Id))
} // }
//
// validKeys := py.All[int](selectedKeys, func(idx int) bool {
// return 0 <= idx && idx < user.Kp.NumbOfKeys
// })
// if !validKeys {
// return nil, errors.New(fmt.Sprintf("one or more keys not in range 0-%d", user.Kp.NumbOfKeys-1))
// }
// presumedAttrIdxVals, err := c.getPresumedAttributeIdxVals(user, selectedKeys)
// if err != nil {
// return nil, err
// }
// err = c.IsValidNKode(user.Kp, presumedAttrIdxVals)
// if err != nil {
// return nil, err
// }
// attrVals, err := c.Attributes.AttrVals(user.Kp)
// if err != nil {
// return nil, err
// }
// err = user.UserKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, attrVals)
// if err != nil {
// return nil, err
// }
//
// return presumedAttrIdxVals, nil
//}
validKeys := py.All[int](selectedKeys, func(idx int) bool { //func (c *Customer) getPresumedAttributeIdxVals(user User, selectedKeys []int) ([]int, error) {
return 0 <= idx && idx < user.Kp.NumbOfKeys //
}) // passcodeLen := len(selectedKeys)
if !validKeys { // if passcodeLen < c.NKodePolicy.MinNkodeLen || passcodeLen > c.NKodePolicy.MaxNkodeLen {
return nil, errors.New(fmt.Sprintf("one or more keys not in range 0-%d", user.Kp.NumbOfKeys-1)) // 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))
} // }
presumedAttrIdxVals, err := c.getPresumedAttributeIdxVals(user, selectedKeys) //
if err != nil { // setVals, err := c.Attributes.SetVals(user.Kp)
return nil, err // if err != nil {
} // return nil, err
err = c.IsValidNKode(user.Kp, presumedAttrIdxVals) // }
if err != nil { // passcodeSetVals, err := user.DecipherMask(setVals, passcodeLen)
return nil, err // if err != nil {
} // return nil, err
attrVals, err := c.Attributes.AttrVals(user.Kp) // }
if err != nil { // presumedAttrIdxVals := make([]int, passcodeLen)
return nil, err //
} // for idx := range presumedAttrIdxVals {
err = user.UserKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, attrVals) // keyNumb := selectedKeys[idx]
if err != nil { // setIdx, err := c.Attributes.IndexOfSet(passcodeSetVals[idx])
return nil, err // if err != nil {
} // return nil, err
// }
return presumedAttrIdxVals, nil // selectedAttrIdx, err := user.Interface.GetAttrIdxByKeyNumbSetIdx(setIdx, keyNumb)
} // if err != nil {
// return nil, err
func (c *Customer) getPresumedAttributeIdxVals(user User, selectedKeys []int) ([]int, error) { // }
// presumedAttrIdxVals[idx] = selectedAttrIdx
passcodeLen := len(selectedKeys) // }
if passcodeLen < c.NKodePolicy.MinNkodeLen || passcodeLen > c.NKodePolicy.MaxNkodeLen { // return presumedAttrIdxVals, nil
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)) //}
}
setVals, err := c.Attributes.SetVals(user.Kp)
if err != nil {
return nil, err
}
passcodeSetVals, err := user.DecipherMask(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(kp m.KeypadDimension, passcodeAttrIdx []int) error { func (c *Customer) IsValidNKode(kp m.KeypadDimension, passcodeAttrIdx []int) error {
nkodeLen := len(passcodeAttrIdx) nkodeLen := len(passcodeAttrIdx)
@@ -163,59 +162,39 @@ func (c *Customer) IsValidNKode(kp m.KeypadDimension, passcodeAttrIdx []int) err
return nil return nil
} }
func (c *Customer) GetLoginInterface(username m.Username) ([]int, error) { func (c *Customer) RenewKeys() ([]uint64, []uint64) {
user, exists := c.Users[username]
if !exists {
return nil, errors.New(fmt.Sprintf("can't get login interface for non-existant user %s in customer %s", username, c.CustomerId))
}
err := user.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
c.Users[username] = user
return user.Interface.IdxInterface, nil
}
func (c *Customer) RenewKeys() error {
oldAttrs := make([]uint64, m.KeypadMax.TotalAttrs()) oldAttrs := make([]uint64, m.KeypadMax.TotalAttrs())
oldSets := make([]uint64, m.KeypadMax.AttrsPerKey) oldSets := make([]uint64, m.KeypadMax.AttrsPerKey)
allAttrVals, err := c.Attributes.AttrVals(m.KeypadMax) allAttrVals, err := c.Attributes.AttrVals(m.KeypadMax)
if err != nil { if err != nil {
return nil panic(err)
} }
allSetVals, err := c.Attributes.AttrVals(m.KeypadMax) allSetVals, err := c.Attributes.AttrVals(m.KeypadMax)
if err != nil { if err != nil {
return nil panic(err)
} }
copy(oldAttrs, allAttrVals) copy(oldAttrs, allAttrVals)
copy(oldSets, allSetVals) copy(oldSets, allSetVals)
err = c.Attributes.Renew() err = c.Attributes.Renew()
if err != nil { if err != nil {
return nil panic(err)
} }
allAttrVals, err = c.Attributes.AttrVals(m.KeypadMax) allAttrVals, err = c.Attributes.AttrVals(m.KeypadMax)
if err != nil { if err != nil {
return nil panic(err)
} }
allSetVals, err = c.Attributes.AttrVals(m.KeypadMax) allSetVals, err = c.Attributes.SetVals(m.KeypadMax)
if err != nil { if err != nil {
return nil panic(err)
} }
attrsXor, err := util.XorLists(oldAttrs, allAttrVals) attrsXor, err := util.XorLists(oldAttrs, allAttrVals)
if err != nil { if err != nil {
return nil panic(err)
} }
setXor, err := util.XorLists(oldSets, allSetVals) setXor, err := util.XorLists(oldSets, allSetVals)
if err != nil { if err != nil {
return nil panic(err)
} }
for _, user := range c.Users { return setXor, attrsXor
err = user.RenewKeys(setXor, attrsXor)
if err != nil {
return nil
}
}
return nil
} }

View File

@@ -7,8 +7,6 @@ import (
"go-nkode/util" "go-nkode/util"
) )
var NotDispersableError = errors.New("number of keys must be less than the number of attributes per key to be dispersion resistant")
type CustomerAttributes struct { type CustomerAttributes struct {
attrVals []uint64 attrVals []uint64
setVals []uint64 setVals []uint64

View File

@@ -27,13 +27,13 @@ func testCustomerValidKeyEntry(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
username := m.Username("testing123") username := m.Username("testing123")
passcodeIdx := []int{0, 1, 2, 3} passcodeIdx := []int{0, 1, 2, 3}
err = customer.AddNewUser(username, passcodeIdx, *newUserInterface, kp) user, err := NewUser(*customer, username, passcodeIdx, *newUserInterface, kp)
assert.NoError(t, err) assert.NoError(t, err)
userLoginInterface, err := customer.GetLoginInterface(username) userLoginInterface, err := user.GetLoginInterface()
assert.NoError(t, err) assert.NoError(t, err)
selectedKeys, err := SelectKeyByAttrIdx(userLoginInterface, passcodeIdx, kp) selectedKeys, err := SelectKeyByAttrIdx(userLoginInterface, passcodeIdx, kp)
assert.NoError(t, err) assert.NoError(t, err)
validatedPasscode, err := customer.ValidKeyEntry(username, selectedKeys) validatedPasscode, err := ValidKeyEntry(*user, *customer, selectedKeys)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, len(validatedPasscode), len(passcodeIdx)) assert.Equal(t, len(validatedPasscode), len(passcodeIdx))
for idx := range validatedPasscode { for idx := range validatedPasscode {
@@ -50,8 +50,8 @@ func testCustomerIsValidNKode(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
username := m.Username("testing123") username := m.Username("testing123")
passcodeIdx := []int{0, 1, 2, 3} passcodeIdx := []int{0, 1, 2, 3}
err = customer.AddNewUser(username, passcodeIdx, *newUserInterface, kp) user, err := NewUser(*customer, username, passcodeIdx, *newUserInterface, kp)
assert.NoError(t, err) assert.NoError(t, err)
err = customer.IsValidNKode(kp, passcodeIdx) err = customer.IsValidNKode(user.Kp, passcodeIdx)
assert.NoError(t, err) assert.NoError(t, err)
} }

14
core/nkode/db_accessor.go Normal file
View File

@@ -0,0 +1,14 @@
package nkode
import (
"go-nkode/core/model"
)
type DbAccessor interface {
GetCustomer(m.CustomerId) (*Customer, error)
GetUser(m.Username, m.CustomerId) (*User, error)
WriteNewCustomer(Customer) error
WriteNewUser(User) error
UpdateUserInterface(m.UserId, UserInterface) error
Renew(m.CustomerId) error
}

100
core/nkode/in_memory_db.go Normal file
View File

@@ -0,0 +1,100 @@
package nkode
import (
"errors"
"fmt"
m "go-nkode/core/model"
)
type InMemoryDb struct {
Customers map[m.CustomerId]Customer
Users map[m.UserId]User
userIdMap map[string]m.UserId
}
func NewInMemoryDb() InMemoryDb {
return InMemoryDb{
Customers: make(map[m.CustomerId]Customer),
Users: make(map[m.UserId]User),
userIdMap: make(map[string]m.UserId),
}
}
func (db *InMemoryDb) GetCustomer(id m.CustomerId) (*Customer, error) {
customer, exists := db.Customers[id]
if !exists {
return nil, errors.New(fmt.Sprintf("customer %s dne", customer.Id))
}
return &customer, nil
}
func (db *InMemoryDb) GetUser(username m.Username, customerId m.CustomerId) (*User, error) {
key := userIdKey(customerId, username)
userId, exists := db.userIdMap[key]
if !exists {
return nil, errors.New(fmt.Sprintf("customer %s with username %s dne", customerId, username))
}
user, exists := db.Users[userId]
if !exists {
panic(fmt.Sprintf("userId %s with customerId %s and username %s with no user", userId, customerId, username))
}
return &user, nil
}
func (db *InMemoryDb) WriteNewCustomer(customer Customer) error {
_, exists := db.Customers[customer.Id]
if exists {
return errors.New(fmt.Sprintf("can write customer %s; already exists", customer.Id))
}
db.Customers[customer.Id] = customer
return nil
}
func (db *InMemoryDb) WriteNewUser(user User) error {
_, exists := db.Customers[user.CustomerId]
if !exists {
return errors.New(fmt.Sprintf("can't add user %s to customer %s: customer dne", user.Username, user.CustomerId))
}
userExists, _ := db.GetUser(user.Username, user.CustomerId)
if userExists != nil {
return errors.New(fmt.Sprintf("can't write new user %s, alread exists", user.Username))
}
key := userIdKey(user.CustomerId, user.Username)
db.userIdMap[key] = user.Id
db.Users[user.Id] = user
return nil
}
func (db *InMemoryDb) UpdateUserInterface(userId m.UserId, ui UserInterface) error {
user, exists := db.Users[userId]
if !exists {
return errors.New(fmt.Sprintf("can't update user %s, dne", user.Id))
}
user.Interface = ui
return nil
}
func (db *InMemoryDb) Renew(id m.CustomerId) error {
customer, exists := db.Customers[id]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", id))
}
setXor, attrsXor := customer.RenewKeys()
var err error
for _, user := range db.Users {
if user.CustomerId == id {
err = user.RenewKeys(setXor[:user.Kp.AttrsPerKey], attrsXor[:user.Kp.TotalAttrs()])
if err != nil {
panic(err)
}
}
}
return nil
}
func userIdKey(customerId m.CustomerId, username m.Username) string {
key := fmt.Sprintf("%s:%s", customerId, username)
return key
}

131
core/nkode/nkode_api.go Normal file
View File

@@ -0,0 +1,131 @@
package nkode
import (
"errors"
"fmt"
m "go-nkode/core/model"
)
type NKodeAPI struct {
Db DbAccessor
SignupSessions map[m.SessionId]UserSignSession
}
func NewNKodeAPI(db DbAccessor) NKodeAPI {
return NKodeAPI{
Db: db,
SignupSessions: make(map[m.SessionId]UserSignSession),
}
}
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy m.NKodePolicy) (*m.CustomerId, error) {
newCustomer, err := NewCustomer(nkodePolicy)
if err != nil {
return nil, err
}
err = n.Db.WriteNewCustomer(*newCustomer)
if err != nil {
return nil, err
}
return &newCustomer.Id, nil
}
func (n *NKodeAPI) GenerateSignupInterface(customerId m.CustomerId, kp m.KeypadDimension) (*m.GenerateSignupInterfaceResp, error) {
signupSession, err := NewSignupSession(kp, customerId)
if err != nil {
return nil, err
}
n.SignupSessions[signupSession.Id] = *signupSession
resp := m.GenerateSignupInterfaceResp{
UserInterface: signupSession.SetIdxInterface,
SessionId: signupSession.Id,
}
return &resp, nil
}
func (n *NKodeAPI) SetNKode(username m.Username, customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) (m.IdxInterface, error) {
_, err := n.Db.GetCustomer(customerId)
if err != nil {
return nil, err
}
session, exists := n.SignupSessions[sessionId]
if !exists {
return nil, errors.New(fmt.Sprintf("session id does not exist %s", sessionId))
}
confirmInterface, err := session.SetUserNKode(username, keySelection)
if err != nil {
return nil, err
}
n.SignupSessions[sessionId] = session
return confirmInterface, nil
}
func (n *NKodeAPI) ConfirmNKode(customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) error {
session, exists := n.SignupSessions[sessionId]
if !exists {
return errors.New(fmt.Sprintf("session id does not exist %s", sessionId))
}
customer, err := n.Db.GetCustomer(customerId)
if err != nil {
return err
}
passcode, err := session.DeducePasscode(keySelection)
if err != nil {
return err
}
err = customer.IsValidNKode(session.Kp, passcode)
if err != nil {
return err
}
user, err := NewUser(*customer, session.Username, passcode, session.LoginUserInterface, session.Kp)
if err != nil {
return err
}
delete(n.SignupSessions, session.Id)
err = n.Db.WriteNewUser(*user)
return err
}
func (n *NKodeAPI) GetLoginInterface(username m.Username, customerId m.CustomerId) (m.IdxInterface, error) {
user, err := n.Db.GetUser(username, customerId)
if err != nil {
return nil, err
}
err = user.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
err = n.Db.UpdateUserInterface(user.Id, user.Interface)
if err != nil {
return nil, err
}
return user.Interface.IdxInterface, nil
}
func (n *NKodeAPI) Login(customerId m.CustomerId, username m.Username, keySelection m.KeySelection) error {
customer, err := n.Db.GetCustomer(customerId)
if err != nil {
return err
}
user, err := n.Db.GetUser(username, customerId)
if err != nil {
return errors.New(fmt.Sprintf("user dne %s", username))
}
passcode, err := ValidKeyEntry(*user, *customer, keySelection)
if err != nil {
return err
}
if user.Renew {
err = user.RefreshPasscode(passcode, customer.Attributes)
if err != nil {
return err
}
}
return nil
}
func (n *NKodeAPI) RenewAttributes(customerId m.CustomerId) error {
return n.Db.Renew(customerId)
}

View File

@@ -8,11 +8,12 @@ import (
func TestNKodeAPI(t *testing.T) { func TestNKodeAPI(t *testing.T) {
for idx := 0; idx < 10; idx++ { for idx := 0; idx < 10; idx++ {
db := NewInMemoryDb()
username := m.Username("test_username") username := m.Username("test_username")
passcodeLen := 4 passcodeLen := 4
nkodePolicy := m.NewDefaultNKodePolicy() nkodePolicy := m.NewDefaultNKodePolicy()
keypadSize := m.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 8} keypadSize := m.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 8}
nkodeApi := NewNKodeInMemory() nkodeApi := NewNKodeAPI(&db)
customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy) customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
signupResponse, err := nkodeApi.GenerateSignupInterface(*customerId, keypadSize) signupResponse, err := nkodeApi.GenerateSignupInterface(*customerId, keypadSize)

View File

@@ -1,143 +0,0 @@
package nkode
import (
"errors"
"fmt"
m "go-nkode/core/model"
)
type NKodeInMemory struct {
Customers map[m.CustomerId]Customer
SignupSessions map[m.SessionId]UserSignSession
}
func NewNKodeInMemory() NKodeInMemory {
return NKodeInMemory{
Customers: make(map[m.CustomerId]Customer),
SignupSessions: make(map[m.SessionId]UserSignSession),
}
}
func (n *NKodeInMemory) CreateNewCustomer(nkodePolicy m.NKodePolicy) (*m.CustomerId, error) {
newCustomer, err := NewCustomer(nkodePolicy)
if err != nil {
return nil, err
}
n.Customers[newCustomer.CustomerId] = *newCustomer
return &newCustomer.CustomerId, nil
}
func (n *NKodeInMemory) GenerateSignupInterface(customerId m.CustomerId, kp m.KeypadDimension) (*m.GenerateSignupInterfaceResp, error) {
customer, exists := n.Customers[customerId]
if !exists {
return nil, errors.New(fmt.Sprintf("customer doesnt exists: %s", customerId))
}
signupSession, err := NewSignupSession(kp, customer.CustomerId)
if err != nil {
return nil, err
}
n.SignupSessions[signupSession.SessionId] = *signupSession
resp := m.GenerateSignupInterfaceResp{
UserInterface: signupSession.SetIdxInterface,
SessionId: signupSession.SessionId,
}
return &resp, nil
}
func (n *NKodeInMemory) SetNKode(username m.Username, customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) (m.IdxInterface, error) {
_, exists := n.Customers[customerId]
if !exists {
return nil, errors.New(fmt.Sprintf("set nkode customer id does not exist %s", customerId))
}
session, exists := n.SignupSessions[sessionId]
if !exists {
return nil, errors.New(fmt.Sprintf("session id does not exist %s", sessionId))
}
confirmInterface, err := session.SetUserNKode(username, keySelection)
if err != nil {
return nil, err
}
n.SignupSessions[sessionId] = session
return confirmInterface, nil
}
func (n *NKodeInMemory) ConfirmNKode(customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) error {
session, exists := n.SignupSessions[sessionId]
if !exists {
return errors.New(fmt.Sprintf("session id does not exist %s", sessionId))
}
customer, exists := n.Customers[customerId]
passcode, err := session.DeducePasscode(keySelection)
if err != nil {
return err
}
err = customer.IsValidNKode(session.Kp, passcode)
if err != nil {
return err
}
err = customer.AddNewUser(session.Username, passcode, session.LoginUserInterface, session.Kp)
if err != nil {
return err
}
delete(n.SignupSessions, session.SessionId)
n.Customers[customerId] = customer
return nil
}
func (n *NKodeInMemory) GetLoginInterface(username m.Username, customerId m.CustomerId) (m.IdxInterface, error) {
err := n.customerUserExists(username, customerId)
if err != nil {
return nil, err
}
user := n.Customers[customerId].Users[username]
err = user.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
n.Customers[customerId].Users[username] = user
return user.Interface.IdxInterface, nil
}
func (n *NKodeInMemory) Login(customerId m.CustomerId, username m.Username, keySelection m.KeySelection) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId))
}
user, exists := customer.Users[username]
if !exists {
return errors.New(fmt.Sprintf("user dne %s", username))
}
passcode, err := customer.ValidKeyEntry(username, keySelection)
if err != nil {
return err
}
if user.Renew {
err = user.RefreshPasscode(passcode, customer.Attributes)
if err != nil {
return err
}
}
return nil
}
func (n *NKodeInMemory) customerUserExists(username m.Username, customerId m.CustomerId) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId))
}
_, exists = customer.Users[username]
if !exists {
return errors.New(fmt.Sprintf("user dne %s", username))
}
return nil
}
func (n *NKodeInMemory) RenewAttributes(customerId m.CustomerId) error {
customer, exists := n.Customers[customerId]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", customerId))
}
return customer.RenewKeys()
}

1
core/nkode/sqlite_db.go Normal file
View File

@@ -0,0 +1 @@
package nkode

View File

@@ -6,6 +6,8 @@ import (
) )
type User struct { type User struct {
Id m.UserId
CustomerId m.CustomerId
Username m.Username Username m.Username
EncipheredPasscode m.EncipheredNKode EncipheredPasscode m.EncipheredNKode
Kp m.KeypadDimension Kp m.KeypadDimension
@@ -23,10 +25,13 @@ func (u *User) RenewKeys(setXor []uint64, attrXor []uint64) error {
var err error var err error
u.UserKeys.SetKey, err = util.XorLists(setXor, u.UserKeys.SetKey) u.UserKeys.SetKey, err = util.XorLists(setXor, u.UserKeys.SetKey)
if err != nil { if err != nil {
return err panic(err)
} }
u.UserKeys.AlphaKey, err = util.XorLists(attrXor, u.UserKeys.AlphaKey) u.UserKeys.AlphaKey, err = util.XorLists(attrXor, u.UserKeys.AlphaKey)
return err if err != nil {
panic(err)
}
return nil
} }
func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes CustomerAttributes) error { func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes CustomerAttributes) error {
@@ -46,3 +51,12 @@ func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes Custome
u.Renew = false u.Renew = false
return nil return nil
} }
func (u *User) GetLoginInterface() ([]int, error) {
err := u.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
return u.Interface.IdxInterface, nil
}

View File

@@ -3,12 +3,15 @@ package nkode
import ( import (
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"github.com/google/uuid"
m "go-nkode/core/model" m "go-nkode/core/model"
"go-nkode/util" "go-nkode/util"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
type UserCipherKeys struct { type UserCipherKeys struct {
Id uuid.UUID
UserId m.UserId
AlphaKey []uint64 AlphaKey []uint64
SetKey []uint64 SetKey []uint64
PassKey []uint64 PassKey []uint64
@@ -37,6 +40,7 @@ func NewUserCipherKeys(kp *m.KeypadDimension, setVals []uint64, maxNKodeLen int)
maskKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen) maskKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
salt, _ := util.RandomBytes(10) salt, _ := util.RandomBytes(10)
userCipherKeys := UserCipherKeys{ userCipherKeys := UserCipherKeys{
Id: uuid.New(),
AlphaKey: alphakey, AlphaKey: alphakey,
PassKey: passKey, PassKey: passKey,
MaskKey: maskKey, MaskKey: maskKey,

View File

@@ -10,14 +10,14 @@ import (
type UserInterface struct { type UserInterface struct {
IdxInterface m.IdxInterface IdxInterface m.IdxInterface
kp *m.KeypadDimension Kp *m.KeypadDimension
} }
func NewUserInterface(kp *m.KeypadDimension) (*UserInterface, error) { func NewUserInterface(kp *m.KeypadDimension) (*UserInterface, error) {
idxInterface := util.IdentityArray(kp.TotalAttrs()) idxInterface := util.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{ userInterface := UserInterface{
IdxInterface: idxInterface, IdxInterface: idxInterface,
kp: kp, Kp: kp,
} }
err := userInterface.RandomShuffle() err := userInterface.RandomShuffle()
if err != nil { if err != nil {
@@ -55,7 +55,7 @@ func (u *UserInterface) RandomShuffle() error {
} }
func (u *UserInterface) InterfaceMatrix() ([][]int, error) { func (u *UserInterface) InterfaceMatrix() ([][]int, error) {
return util.ListToMatrix(u.IdxInterface, u.kp.AttrsPerKey) return util.ListToMatrix(u.IdxInterface, u.Kp.AttrsPerKey)
} }
func (u *UserInterface) SetViewMatrix() ([][]int, error) { func (u *UserInterface) SetViewMatrix() ([][]int, error) {
@@ -67,7 +67,7 @@ func (u *UserInterface) SetViewMatrix() ([][]int, error) {
} }
func (u *UserInterface) DisperseInterface() error { func (u *UserInterface) DisperseInterface() error {
if !u.kp.IsDispersable() { if !u.Kp.IsDispersable() {
panic("interface is not dispersable") panic("interface is not dispersable")
} }
@@ -84,7 +84,7 @@ func (u *UserInterface) DisperseInterface() error {
} }
func (u *UserInterface) shuffleKeys() error { func (u *UserInterface) shuffleKeys() error {
userInterfaceMatrix, err := util.ListToMatrix(u.IdxInterface, u.kp.AttrsPerKey) userInterfaceMatrix, err := util.ListToMatrix(u.IdxInterface, u.Kp.AttrsPerKey)
if err != nil { if err != nil {
return err return err
} }
@@ -144,11 +144,11 @@ func (u *UserInterface) PartialInterfaceShuffle() error {
if err != nil { if err != nil {
return err return err
} }
numbOfSelectedSets := u.kp.AttrsPerKey / 2 numbOfSelectedSets := u.Kp.AttrsPerKey / 2
if u.kp.AttrsPerKey&1 == 1 { if u.Kp.AttrsPerKey&1 == 1 {
numbOfSelectedSets += util.Choice[int]([]int{0, 1}) numbOfSelectedSets += util.Choice[int]([]int{0, 1})
} }
setIdxs, err := util.RandomPermutation(u.kp.AttrsPerKey) setIdxs, err := util.RandomPermutation(u.Kp.AttrsPerKey)
if err != nil { if err != nil {
return err return err
} }
@@ -158,7 +158,7 @@ func (u *UserInterface) PartialInterfaceShuffle() error {
if err != nil { if err != nil {
return err return err
} }
interfaceBySet := make([][]int, u.kp.AttrsPerKey) interfaceBySet := make([][]int, u.Kp.AttrsPerKey)
for idx, attrs := range keypadSetView { for idx, attrs := range keypadSetView {
if selectedSets.Contains(idx) { if selectedSets.Contains(idx) {
err = util.FisherYatesShuffle[int](&attrs) err = util.FisherYatesShuffle[int](&attrs)
@@ -177,12 +177,12 @@ func (u *UserInterface) PartialInterfaceShuffle() error {
} }
func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) { func (u *UserInterface) GetAttrIdxByKeyNumbSetIdx(setIdx int, keyNumb int) (int, error) {
if keyNumb < 0 || u.kp.NumbOfKeys <= keyNumb { if keyNumb < 0 || u.Kp.NumbOfKeys <= keyNumb {
return -1, errors.New(fmt.Sprintf("keyNumb %d is out of range 0-%d", keyNumb, u.kp.NumbOfKeys)) return -1, errors.New(fmt.Sprintf("keyNumb %d is out of range 0-%d", keyNumb, u.Kp.NumbOfKeys))
} }
if setIdx < 0 || u.kp.AttrsPerKey <= setIdx { if setIdx < 0 || u.Kp.AttrsPerKey <= setIdx {
return -1, errors.New(fmt.Sprintf("setIdx %d is out of range 0-%d", setIdx, u.kp.AttrsPerKey)) return -1, errors.New(fmt.Sprintf("setIdx %d is out of range 0-%d", setIdx, u.Kp.AttrsPerKey))
} }
keypadView, err := u.InterfaceMatrix() keypadView, err := u.InterfaceMatrix()
if err != nil { if err != nil {

View File

@@ -11,7 +11,7 @@ import (
) )
type UserSignSession struct { type UserSignSession struct {
SessionId m.SessionId Id m.SessionId
CustomerId m.CustomerId CustomerId m.CustomerId
LoginUserInterface UserInterface LoginUserInterface UserInterface
Kp m.KeypadDimension Kp m.KeypadDimension
@@ -19,6 +19,7 @@ type UserSignSession struct {
ConfirmIdxInterface m.IdxInterface ConfirmIdxInterface m.IdxInterface
SetKeySelection m.KeySelection SetKeySelection m.KeySelection
Username m.Username Username m.Username
Expire int
} }
func NewSignupSession(kp m.KeypadDimension, customerId m.CustomerId) (*UserSignSession, error) { func NewSignupSession(kp m.KeypadDimension, customerId m.CustomerId) (*UserSignSession, error) {
@@ -31,7 +32,7 @@ func NewSignupSession(kp m.KeypadDimension, customerId m.CustomerId) (*UserSignS
return nil, err return nil, err
} }
session := UserSignSession{ session := UserSignSession{
SessionId: m.SessionId(uuid.New()), Id: m.SessionId(uuid.New()),
CustomerId: customerId, CustomerId: customerId,
LoginUserInterface: *loginInterface, LoginUserInterface: *loginInterface,
SetIdxInterface: signupInterface.IdxInterface, SetIdxInterface: signupInterface.IdxInterface,
@@ -108,7 +109,7 @@ func (s *UserSignSession) SetUserNKode(username m.Username, keySelection m.KeySe
s.SetKeySelection = keySelection s.SetKeySelection = keySelection
s.Username = username s.Username = username
setKp := s.SignupKeypad() setKp := s.SignupKeypad()
setInterface := UserInterface{IdxInterface: s.SetIdxInterface, kp: &setKp} setInterface := UserInterface{IdxInterface: s.SetIdxInterface, Kp: &setKp}
err := setInterface.DisperseInterface() err := setInterface.DisperseInterface()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -159,7 +160,7 @@ func signupInterface(baseUserInterface UserInterface, kp m.KeypadDimension) (*Us
} }
signupUserInterface := UserInterface{ signupUserInterface := UserInterface{
IdxInterface: util.MatrixToList(attrSetView), IdxInterface: util.MatrixToList(attrSetView),
kp: &m.KeypadDimension{ Kp: &m.KeypadDimension{
AttrsPerKey: numbOfKeys, AttrsPerKey: numbOfKeys,
NumbOfKeys: numbOfKeys, NumbOfKeys: numbOfKeys,
}, },

View File

@@ -9,7 +9,8 @@ import (
) )
func main() { func main() {
nkodeApi := nkode.NewNKodeInMemory() db := nkode.NewInMemoryDb()
nkodeApi := nkode.NewNKodeAPI(&db)
handler := api.NKodeHandler{Api: &nkodeApi} handler := api.NKodeHandler{Api: &nkodeApi}
mux := http.NewServeMux() mux := http.NewServeMux()
mux.Handle(api.CreateNewCustomer, &handler) mux.Handle(api.CreateNewCustomer, &handler)

View File

@@ -3,6 +3,7 @@ package sql_driver
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver _ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
"log" "log"
) )
@@ -17,7 +18,7 @@ func InitTables() {
// Create a table // Create a table
createTableSQL := ` createTableSQL := `
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id TEXT NOT NULL PRIMARY KEY,
name TEXT, name TEXT,
age INTEGER age INTEGER
); );
@@ -28,13 +29,13 @@ func InitTables() {
} }
// Insert data into the table // Insert data into the table
insertUserSQL := `INSERT INTO users (name, age) VALUES (?, ?)` insertUserSQL := `INSERT INTO users (id, name, age) VALUES (?, ?, ?)`
_, err = db.Exec(insertUserSQL, "Alice", 30) _, err = db.Exec(insertUserSQL, uuid.New(), "Alice", 30)
if err != nil { if err != nil {
log.Fatalf("Error inserting data: %s", err) log.Fatalf("Error inserting data: %s", err)
} }
_, err = db.Exec(insertUserSQL, "Bob", 25) _, err = db.Exec(insertUserSQL, uuid.New(), "Bob", 25)
if err != nil { if err != nil {
log.Fatalf("Error inserting data: %s", err) log.Fatalf("Error inserting data: %s", err)
} }
@@ -48,14 +49,14 @@ func InitTables() {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var id int var id string
var name string var name string
var age int var age int
err = rows.Scan(&id, &name, &age) err = rows.Scan(&id, &name, &age)
if err != nil { if err != nil {
log.Fatalf("Error scanning data: %s", err) log.Fatalf("Error scanning data: %s", err)
} }
fmt.Printf("User: ID=%d, Name=%s, Age=%d\n", id, name, age) fmt.Printf("User: ID=%s, Name=%s, Age=%d\n", id, name, age)
} }
// Update data // Update data
@@ -74,13 +75,13 @@ func InitTables() {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var id int var id string
var name string var name string
var age int var age int
err = rows.Scan(&id, &name, &age) err = rows.Scan(&id, &name, &age)
if err != nil { if err != nil {
log.Fatalf("Error scanning data: %s", err) log.Fatalf("Error scanning data: %s", err)
} }
fmt.Printf("User: ID=%d, Name=%s, Age=%d\n", id, name, age) fmt.Printf("User: ID=%s, Name=%s, Age=%d\n", id, name, age)
} }
} }

View File

@@ -0,0 +1,7 @@
package sql_driver
import "testing"
func TestInitTables(t *testing.T) {
InitTables()
}