refactor code to fewer files; remove unused code

This commit is contained in:
2024-09-21 11:04:09 -05:00
parent b7a4a5cf4c
commit 2b3abb8fb2
29 changed files with 486 additions and 557 deletions

View File

@@ -1,12 +0,0 @@
package api
const (
CreateNewCustomer = "/create-new-customer"
GenerateSignupInterface = "/generate-signup-interface"
SetNKode = "/set-nkode"
ConfirmNKode = "/confirm-nkode"
GetLoginInterface = "/get-login-interface"
Login = "/login"
RenewAttributes = "/renew-attributes"
RandomSvgInterface = "/random-svg-interface"
)

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"errors"

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"errors"

View File

@@ -1,8 +1,7 @@
package nkode
package core
import (
"github.com/stretchr/testify/assert"
"go-nkode/core/model"
"testing"
)
@@ -13,26 +12,25 @@ func TestCustomer(t *testing.T) {
}
func testNewCustomerAttributes(t *testing.T) {
// keypad := m.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 5}
_, nil := model.NewCustomerAttributes()
_, nil := NewCustomerAttributes()
assert.NoError(t, nil)
}
func testCustomerValidKeyEntry(t *testing.T) {
kp := model.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 9}
nkodePolicy := model.NewDefaultNKodePolicy()
customer, err := model.NewCustomer(nkodePolicy)
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 9}
nkodePolicy := NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err)
mockSvgInterface := make(model.SvgIdInterface, kp.TotalAttrs())
userInterface, err := model.NewUserInterface(&kp, mockSvgInterface)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
username := model.Username("testing123")
username := Username("testing123")
passcodeIdx := []int{0, 1, 2, 3}
user, err := NewUser(*customer, username, passcodeIdx, *userInterface, kp)
assert.NoError(t, err)
userLoginInterface, err := user.GetLoginInterface()
assert.NoError(t, err)
selectedKeys, err := model.SelectKeyByAttrIdx(userLoginInterface, passcodeIdx, kp)
selectedKeys, err := SelectKeyByAttrIdx(userLoginInterface, passcodeIdx, kp)
assert.NoError(t, err)
validatedPasscode, err := ValidKeyEntry(*user, *customer, selectedKeys)
assert.NoError(t, err)
@@ -43,14 +41,14 @@ func testCustomerValidKeyEntry(t *testing.T) {
}
func testCustomerIsValidNKode(t *testing.T) {
kp := model.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := model.NewDefaultNKodePolicy()
customer, err := model.NewCustomer(nkodePolicy)
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err)
mockSvgInterface := make(model.SvgIdInterface, kp.TotalAttrs())
userInterface, err := model.NewUserInterface(&kp, mockSvgInterface)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
username := model.Username("testing123")
username := Username("testing123")
passcodeIdx := []int{0, 1, 2, 3}
user, err := NewUser(*customer, username, passcodeIdx, *userInterface, kp)
assert.NoError(t, err)

View File

@@ -1,26 +1,25 @@
package nkode
package core
import (
"errors"
"fmt"
m "go-nkode/core/model"
)
type InMemoryDb struct {
Customers map[m.CustomerId]m.Customer
Users map[m.UserId]m.User
userIdMap map[string]m.UserId
Customers map[CustomerId]Customer
Users map[UserId]User
userIdMap map[string]UserId
}
func NewInMemoryDb() InMemoryDb {
return InMemoryDb{
Customers: make(map[m.CustomerId]m.Customer),
Users: make(map[m.UserId]m.User),
userIdMap: make(map[string]m.UserId),
Customers: make(map[CustomerId]Customer),
Users: make(map[UserId]User),
userIdMap: make(map[string]UserId),
}
}
func (db *InMemoryDb) GetCustomer(id m.CustomerId) (*m.Customer, error) {
func (db *InMemoryDb) GetCustomer(id CustomerId) (*Customer, error) {
customer, exists := db.Customers[id]
if !exists {
return nil, errors.New(fmt.Sprintf("customer %s dne", customer.Id))
@@ -28,7 +27,7 @@ func (db *InMemoryDb) GetCustomer(id m.CustomerId) (*m.Customer, error) {
return &customer, nil
}
func (db *InMemoryDb) GetUser(username m.Username, customerId m.CustomerId) (*m.User, error) {
func (db *InMemoryDb) GetUser(username Username, customerId CustomerId) (*User, error) {
key := userIdKey(customerId, username)
userId, exists := db.userIdMap[key]
if !exists {
@@ -41,7 +40,7 @@ func (db *InMemoryDb) GetUser(username m.Username, customerId m.CustomerId) (*m.
return &user, nil
}
func (db *InMemoryDb) WriteNewCustomer(customer m.Customer) error {
func (db *InMemoryDb) WriteNewCustomer(customer Customer) error {
_, exists := db.Customers[customer.Id]
if exists {
@@ -51,7 +50,7 @@ func (db *InMemoryDb) WriteNewCustomer(customer m.Customer) error {
return nil
}
func (db *InMemoryDb) WriteNewUser(user m.User) error {
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))
@@ -67,16 +66,17 @@ func (db *InMemoryDb) WriteNewUser(user m.User) error {
return nil
}
func (db *InMemoryDb) UpdateUserInterface(userId m.UserId, ui m.UserInterface) error {
func (db *InMemoryDb) UpdateUserInterface(userId 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
db.Users[userId] = user
return nil
}
func (db *InMemoryDb) Renew(id m.CustomerId) error {
func (db *InMemoryDb) Renew(id CustomerId) error {
customer, exists := db.Customers[id]
if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", id))
@@ -88,7 +88,7 @@ func (db *InMemoryDb) Renew(id m.CustomerId) error {
if user.CustomerId == id {
err = user.RenewKeys(setXor, attrsXor)
if err != nil {
panic(err)
return err
}
db.Users[user.Id] = user
}
@@ -96,7 +96,7 @@ func (db *InMemoryDb) Renew(id m.CustomerId) error {
return nil
}
func (db *InMemoryDb) RefreshUser(user m.User, passocode []int, customerAttr m.CustomerAttributes) error {
func (db *InMemoryDb) RefreshUser(user User, passocode []int, customerAttr CustomerAttributes) error {
err := user.RefreshPasscode(passocode, customerAttr)
if err != nil {
return err
@@ -105,19 +105,23 @@ func (db *InMemoryDb) RefreshUser(user m.User, passocode []int, customerAttr m.C
return nil
}
func (db *InMemoryDb) RandomSvgInterface(kp m.KeypadDimension) ([]string, error) {
return nil, errors.ErrUnsupported
func (db *InMemoryDb) RandomSvgInterface(kp KeypadDimension) ([]string, error) {
return make([]string, kp.TotalAttrs()), nil
}
func (db *InMemoryDb) RandomSvgIdxInterface(kp m.KeypadDimension) (m.SvgIdInterface, error) {
return nil, errors.ErrUnsupported
func (db *InMemoryDb) RandomSvgIdxInterface(kp KeypadDimension) (SvgIdInterface, error) {
svgs := make(SvgIdInterface, kp.TotalAttrs())
for idx := range svgs {
svgs[idx] = idx
}
return svgs, nil
}
func (db InMemoryDb) GetSvgStringInterface(idxs m.SvgIdInterface) ([]string, error) {
return nil, errors.ErrUnsupported
func (db InMemoryDb) GetSvgStringInterface(idxs SvgIdInterface) ([]string, error) {
return make([]string, len(idxs)), nil
}
func userIdKey(customerId m.CustomerId, username m.Username) string {
func userIdKey(customerId CustomerId, username Username) string {
key := fmt.Sprintf("%s:%s", customerId, username)
return key
}

View File

@@ -1,4 +1,4 @@
package model
package core
import "errors"
@@ -29,8 +29,8 @@ var (
}
KeypadMin = KeypadDimension{
AttrsPerKey: 6,
NumbOfKeys: 5,
AttrsPerKey: 5,
NumbOfKeys: 4,
}
KeypadDefault = KeypadDimension{

View File

@@ -1,58 +0,0 @@
package model
import (
"go-nkode/util"
)
type User struct {
Id UserId
CustomerId CustomerId
Username Username
EncipheredPasscode EncipheredNKode
Kp KeypadDimension
CipherKeys UserCipherKeys
Interface UserInterface
Renew bool
}
func (u *User) DecipherMask(setVals []uint64, passcodeLen int) ([]uint64, error) {
return u.CipherKeys.DecipherMask(u.EncipheredPasscode.Mask, setVals, passcodeLen)
}
func (u *User) RenewKeys(setXor []uint64, attrXor []uint64) error {
u.Renew = true
var err error
u.CipherKeys.SetKey, err = util.XorLists(setXor[:u.Kp.AttrsPerKey], u.CipherKeys.SetKey)
if err != nil {
panic(err)
}
u.CipherKeys.AlphaKey, err = util.XorLists(attrXor[:u.Kp.TotalAttrs()], u.CipherKeys.AlphaKey)
return err
}
func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes CustomerAttributes) error {
setVals, err := customerAttributes.SetValsForKp(u.Kp)
newKeys, err := NewUserCipherKeys(&u.Kp, setVals, u.CipherKeys.MaxNKodeLen)
if err != nil {
return err
}
encipheredPasscode, err := newKeys.EncipherNKode(passcodeAttrIdx, customerAttributes)
if err != nil {
return err
}
u.CipherKeys = *newKeys
u.EncipheredPasscode = *encipheredPasscode
u.Renew = false
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

@@ -1,89 +0,0 @@
package nkode
import (
"errors"
"github.com/google/uuid"
m "go-nkode/core/model"
py "go-nkode/py-builtin"
)
var KeyIndexOutOfRange = errors.New("one or more keys is out of range")
func ValidKeyEntry(user m.User, customer m.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.SetValsForKp(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.AttrValsForKp(user.Kp)
if err != nil {
panic(err)
}
err = user.CipherKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, attrVals)
if err != nil {
return nil, err
}
return presumedAttrIdxVals, nil
}
func NewUser(customer m.Customer, username m.Username, passcodeIdx []int, ui m.UserInterface, kp m.KeypadDimension) (*m.User, error) {
setVals, err := customer.Attributes.SetValsForKp(kp)
if err != nil {
return nil, err
}
newKeys, err := m.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 := m.User{
Id: m.UserId(uuid.New()),
Username: username,
EncipheredPasscode: *encipheredNKode,
CipherKeys: *newKeys,
Interface: ui,
Kp: kp,
CustomerId: customer.Id,
}
return &newUser, nil
}

View File

@@ -1,18 +0,0 @@
package nkode
import (
"go-nkode/core/model"
)
type DbAccessor interface {
GetCustomer(model.CustomerId) (*model.Customer, error)
GetUser(model.Username, model.CustomerId) (*model.User, error)
WriteNewCustomer(model.Customer) error
WriteNewUser(model.User) error
UpdateUserInterface(model.UserId, model.UserInterface) error
Renew(model.CustomerId) error
RefreshUser(model.User, []int, model.CustomerAttributes) error
RandomSvgInterface(model.KeypadDimension) ([]string, error)
RandomSvgIdxInterface(model.KeypadDimension) (model.SvgIdInterface, error)
GetSvgStringInterface(model.SvgIdInterface) ([]string, error)
}

View File

@@ -1,26 +1,25 @@
package nkode
package core
import (
"errors"
"fmt"
"github.com/google/uuid"
m "go-nkode/core/model"
)
type NKodeAPI struct {
Db DbAccessor
SignupSessions map[m.SessionId]UserSignSession
SignupSessions map[SessionId]UserSignSession
}
func NewNKodeAPI(db DbAccessor) NKodeAPI {
return NKodeAPI{
Db: db,
SignupSessions: make(map[m.SessionId]UserSignSession),
SignupSessions: make(map[SessionId]UserSignSession),
}
}
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy m.NKodePolicy, id *m.CustomerId) (*m.CustomerId, error) {
newCustomer, err := m.NewCustomer(nkodePolicy)
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy NKodePolicy, id *CustomerId) (*CustomerId, error) {
newCustomer, err := NewCustomer(nkodePolicy)
if id != nil {
newCustomer.Id = *id
}
@@ -35,7 +34,7 @@ func (n *NKodeAPI) CreateNewCustomer(nkodePolicy m.NKodePolicy, id *m.CustomerId
return &newCustomer.Id, nil
}
func (n *NKodeAPI) GenerateSignupInterface(username m.Username, customerId m.CustomerId, kp m.KeypadDimension) (*m.GenerateSignupInterfaceResp, error) {
func (n *NKodeAPI) GenerateSignupInterface(username Username, customerId CustomerId, kp KeypadDimension) (*GenerateSignupInterfaceResp, error) {
svgIdxInterface, err := n.Db.RandomSvgIdxInterface(kp)
if err != nil {
return nil, err
@@ -49,7 +48,7 @@ func (n *NKodeAPI) GenerateSignupInterface(username m.Username, customerId m.Cus
if err != nil {
return nil, err
}
resp := m.GenerateSignupInterfaceResp{
resp := GenerateSignupInterfaceResp{
UserIdxInterface: signupSession.SetIdxInterface,
SvgInterface: svgInterface,
SessionId: uuid.UUID(signupSession.Id).String(),
@@ -57,7 +56,7 @@ func (n *NKodeAPI) GenerateSignupInterface(username m.Username, customerId m.Cus
return &resp, nil
}
func (n *NKodeAPI) SetNKode(customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) (m.IdxInterface, error) {
func (n *NKodeAPI) SetNKode(customerId CustomerId, sessionId SessionId, keySelection KeySelection) (IdxInterface, error) {
_, err := n.Db.GetCustomer(customerId)
if err != nil {
@@ -75,7 +74,7 @@ func (n *NKodeAPI) SetNKode(customerId m.CustomerId, sessionId m.SessionId, keyS
return confirmInterface, nil
}
func (n *NKodeAPI) ConfirmNKode(customerId m.CustomerId, sessionId m.SessionId, keySelection m.KeySelection) error {
func (n *NKodeAPI) ConfirmNKode(customerId CustomerId, sessionId SessionId, keySelection KeySelection) error {
session, exists := n.SignupSessions[sessionId]
if !exists {
return errors.New(fmt.Sprintf("session id does not exist %s", sessionId))
@@ -101,7 +100,7 @@ func (n *NKodeAPI) ConfirmNKode(customerId m.CustomerId, sessionId m.SessionId,
return err
}
func (n *NKodeAPI) GetLoginInterface(username m.Username, customerId m.CustomerId) (*m.GetLoginInterfaceResp, error) {
func (n *NKodeAPI) GetLoginInterface(username Username, customerId CustomerId) (*GetLoginInterfaceResp, error) {
user, err := n.Db.GetUser(username, customerId)
if err != nil {
return nil, err
@@ -118,43 +117,50 @@ func (n *NKodeAPI) GetLoginInterface(username m.Username, customerId m.CustomerI
if err != nil {
return nil, err
}
resp := m.GetLoginInterfaceResp{
resp := GetLoginInterfaceResp{
UserIdxInterface: user.Interface.IdxInterface,
SvgInterface: svgInterface,
NumbOfKeys: user.Kp.NumbOfKeys,
AttrsPerKey: user.Kp.AttrsPerKey,
}
return &resp, nil
}
func (n *NKodeAPI) Login(customerId m.CustomerId, username m.Username, keySelection m.KeySelection) error {
func (n *NKodeAPI) Login(customerId CustomerId, username Username, keySelection KeySelection) (string, error) {
customer, err := n.Db.GetCustomer(customerId)
if err != nil {
return err
return "", err
}
user, err := n.Db.GetUser(username, customerId)
if err != nil {
return errors.New(fmt.Sprintf("user dne %s", username))
return "", errors.New(fmt.Sprintf("user dne %s", username))
}
passcode, err := ValidKeyEntry(*user, *customer, keySelection)
if err != nil {
return err
return "", err
}
if user.Renew {
err = n.Db.RefreshUser(*user, passcode, customer.Attributes)
if err != nil {
return err
return "", err
}
}
return nil
return "", nil
}
func (n *NKodeAPI) RenewAttributes(customerId m.CustomerId) error {
func (n *NKodeAPI) RenewAttributes(customerId CustomerId) error {
return n.Db.Renew(customerId)
}
func (n *NKodeAPI) RandomSvgInterface() ([]string, error) {
return n.Db.RandomSvgInterface(m.KeypadMax)
return n.Db.RandomSvgInterface(KeypadMax)
}
func (n *NKodeAPI) GetSvgStringInterface(svgId m.SvgIdInterface) ([]string, error) {
func (n *NKodeAPI) GetSvgStringInterface(svgId SvgIdInterface) ([]string, error) {
return n.Db.GetSvgStringInterface(svgId)
}
func (n *NKodeAPI) RefreshToken(jwt string) (string, error) {
return "", nil
}

View File

@@ -1,22 +1,20 @@
package nkode
package core
import (
"github.com/stretchr/testify/assert"
m "go-nkode/core/model"
"go-nkode/util"
"testing"
)
func TestNKodeAPI(t *testing.T) {
//db1 := NewInMemoryDb()
//1testNKodeAPI(t, &db1)
db1 := NewInMemoryDb()
testNKodeAPI(t, &db1)
dbFile := "../../test.db"
//dbFile := "../../test.db"
// sql_driver.MakeTables(dbFile)
db2 := NewSqliteDB(dbFile)
defer db2.CloseDb()
testNKodeAPI(t, db2)
//db2 := NewSqliteDB(dbFile)
//defer db2.CloseDb()
//testNKodeAPI(t, db2)
// if _, err := os.Stat(dbFile); err == nil {
// err = os.Remove(dbFile)
@@ -27,35 +25,38 @@ func TestNKodeAPI(t *testing.T) {
}
func testNKodeAPI(t *testing.T, db DbAccessor) {
attrsPerKey := 5
numbOfKeys := 4
for idx := 0; idx < 1; idx++ {
username := m.Username("test_username" + util.GenerateRandomString(12))
username := Username("test_username" + util.GenerateRandomString(12))
passcodeLen := 4
nkodePolicy := m.NewDefaultNKodePolicy()
keypadSize := m.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 8}
nkodePolicy := NewDefaultNKodePolicy()
keypadSize := KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
nkodeApi := NewNKodeAPI(db)
customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy, nil)
assert.NoError(t, err)
signupResponse, err := nkodeApi.GenerateSignupInterface(username, *customerId, keypadSize)
assert.NoError(t, err)
setInterface := signupResponse.UserIdxInterface
sessionId := signupResponse.SessionId
keypadSize = m.KeypadDimension{AttrsPerKey: 8, NumbOfKeys: 8}
sessionIdStr := signupResponse.SessionId
sessionId, err := SessionIdFromString(sessionIdStr)
assert.NoError(t, err)
keypadSize = KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
userPasscode := setInterface[:passcodeLen]
setKeySelect, err := m.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
setKeySelect, err := SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
assert.NoError(t, err)
confirmInterface, err := nkodeApi.SetNKode(*customerId, sessionId, setKeySelect)
assert.NoError(t, err)
confirmKeySelect, err := m.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
confirmKeySelect, err := SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
err = nkodeApi.ConfirmNKode(*customerId, sessionId, confirmKeySelect)
assert.NoError(t, err)
keypadSize = m.KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 8}
keypadSize = KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
loginInterface, err := nkodeApi.GetLoginInterface(username, *customerId)
assert.NoError(t, err)
loginKeySelection, err := m.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
loginKeySelection, err := SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
assert.NoError(t, err)
err = nkodeApi.Login(*customerId, username, loginKeySelection)
_, err = nkodeApi.Login(*customerId, username, loginKeySelection)
assert.NoError(t, err)
err = nkodeApi.RenewAttributes(*customerId)
@@ -63,9 +64,9 @@ func testNKodeAPI(t *testing.T, db DbAccessor) {
loginInterface, err = nkodeApi.GetLoginInterface(username, *customerId)
assert.NoError(t, err)
loginKeySelection, err = m.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
loginKeySelection, err = SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
assert.NoError(t, err)
err = nkodeApi.Login(*customerId, username, loginKeySelection)
_, err = nkodeApi.Login(*customerId, username, loginKeySelection)
assert.NoError(t, err)
}

View File

@@ -1,36 +1,49 @@
package model
package core
import (
"encoding/json"
"errors"
"github.com/google/uuid"
"go-nkode/core/api"
"log"
"net/http"
)
type NKodeHandler struct {
Api NKodeAPIInterface
Api NKodeAPI
}
const (
CreateNewCustomer = "/create-new-customer"
GenerateSignupInterface = "/generate-signup-interface"
SetNKode = "/set-nkode"
ConfirmNKode = "/confirm-nkode"
GetLoginInterface = "/get-login-interface"
Login = "/login"
RenewAttributes = "/renew-attributes"
RandomSvgInterface = "/random-svg-interface"
RefreshToken = "refresh-token"
)
func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case api.CreateNewCustomer:
case CreateNewCustomer:
h.CreateNewCustomerHandler(w, r)
case api.GenerateSignupInterface:
case GenerateSignupInterface:
h.GenerateSignupInterfaceHandler(w, r)
case api.SetNKode:
case SetNKode:
h.SetNKodeHandler(w, r)
case api.ConfirmNKode:
case ConfirmNKode:
h.ConfirmNKodeHandler(w, r)
case api.GetLoginInterface:
case GetLoginInterface:
h.GetLoginInterfaceHandler(w, r)
case api.Login:
case Login:
h.LoginHandler(w, r)
case api.RenewAttributes:
case RenewAttributes:
h.RenewAttributesHandler(w, r)
case api.RandomSvgInterface:
case RandomSvgInterface:
h.RandomSvgInterfaceHandler(w, r)
case RefreshToken:
h.RefreshTokenHandler(w, r)
default:
w.WriteHeader(http.StatusNotFound)
_, err := w.Write([]byte("404 not found"))
@@ -273,7 +286,7 @@ func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
log.Println(err)
return
}
err = h.Api.Login(CustomerId(customerId), loginPost.Username, loginPost.KeySelection)
_, err = h.Api.Login(CustomerId(customerId), loginPost.Username, loginPost.KeySelection)
if err != nil {
internalServerErrorHandler(w)
log.Println(err)
@@ -340,6 +353,10 @@ func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.
w.WriteHeader(http.StatusOK)
}
func (h *NKodeHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Request) {
}
func decodeJson(w http.ResponseWriter, r *http.Request, post any) error {
if r.Body == nil {
invalidJson(w)

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"errors"

View File

@@ -1,4 +1,4 @@
package nkode
package core
import (
"database/sql"
@@ -6,7 +6,6 @@ import (
"fmt"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
m "go-nkode/core/model"
"go-nkode/util"
"log"
)
@@ -32,7 +31,7 @@ func (d *SqliteDB) CloseDb() {
}
}
func (d *SqliteDB) WriteNewCustomer(c m.Customer) error {
func (d *SqliteDB) WriteNewCustomer(c Customer) error {
tx, err := d.db.Begin()
if err != nil {
return err
@@ -60,7 +59,7 @@ VALUES (?,?,?,?,?,?,?,?,?)
return nil
}
func (d *SqliteDB) WriteNewUser(u m.User) error {
func (d *SqliteDB) WriteNewUser(u User) error {
tx, err := d.db.Begin()
if err != nil {
return err
@@ -95,7 +94,7 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
return nil
}
func (d *SqliteDB) GetCustomer(id m.CustomerId) (*m.Customer, error) {
func (d *SqliteDB) GetCustomer(id CustomerId) (*Customer, error) {
selectCustomer := `SELECT max_nkode_len, min_nkode_len, distinct_sets, distinct_attributes, lock_out, expiration, attribute_values, set_values FROM customer WHERE id = ?`
rows, err := d.db.Query(selectCustomer, uuid.UUID(id))
@@ -119,9 +118,9 @@ func (d *SqliteDB) GetCustomer(id m.CustomerId) (*m.Customer, error) {
if rows.Next() {
return nil, errors.New(fmt.Sprintf("too many rows for customer %s", id))
}
customer := m.Customer{
customer := Customer{
Id: id,
NKodePolicy: m.NKodePolicy{
NKodePolicy: NKodePolicy{
MaxNkodeLen: maxNKodeLen,
MinNkodeLen: minNKodeLen,
DistinctSets: distinctSets,
@@ -129,13 +128,13 @@ func (d *SqliteDB) GetCustomer(id m.CustomerId) (*m.Customer, error) {
LockOut: lockOut,
Expiration: expiration,
},
Attributes: m.NewCustomerAttributesFromBytes(attributeValues, setValues),
Attributes: NewCustomerAttributesFromBytes(attributeValues, setValues),
}
return &customer, nil
}
func (d *SqliteDB) GetUser(username m.Username, customerId m.CustomerId) (*m.User, error) {
func (d *SqliteDB) GetUser(username Username, customerId CustomerId) (*User, error) {
userSelect := `
SELECT id, renew, code, mask, attributes_per_key, number_of_keys, alpha_key, set_key, pass_key, mask_key, salt, max_nkode_len, idx_interface, svg_id_interface FROM user
WHERE user.username = ? AND user.customer_id = ?
@@ -175,19 +174,19 @@ WHERE user.username = ? AND user.customer_id = ?
renew = true
}
user := m.User{
Id: m.UserId(userId),
user := User{
Id: UserId(userId),
CustomerId: customerId,
Username: username,
EncipheredPasscode: m.EncipheredNKode{
EncipheredPasscode: EncipheredNKode{
Code: code,
Mask: mask,
},
Kp: m.KeypadDimension{
Kp: KeypadDimension{
AttrsPerKey: attrsPerKey,
NumbOfKeys: numbOfKeys,
},
CipherKeys: m.UserCipherKeys{
CipherKeys: UserCipherKeys{
AlphaKey: util.ByteArrToUint64Arr(alphaKey),
SetKey: util.ByteArrToUint64Arr(setKey),
PassKey: util.ByteArrToUint64Arr(passKey),
@@ -196,7 +195,7 @@ WHERE user.username = ? AND user.customer_id = ?
MaxNKodeLen: maxNKodeLen,
Kp: nil,
},
Interface: m.UserInterface{
Interface: UserInterface{
IdxInterface: util.ByteArrToIntArr(idxInterface),
SvgId: util.ByteArrToIntArr(svgIdInterface),
Kp: nil,
@@ -209,7 +208,7 @@ WHERE user.username = ? AND user.customer_id = ?
return &user, nil
}
func (d *SqliteDB) UpdateUserInterface(id m.UserId, ui m.UserInterface) error {
func (d *SqliteDB) UpdateUserInterface(id UserId, ui UserInterface) error {
updateUserInterface := `
UPDATE user SET idx_interface = ? WHERE id = ?
`
@@ -218,7 +217,7 @@ UPDATE user SET idx_interface = ? WHERE id = ?
return err
}
func (d *SqliteDB) Renew(id m.CustomerId) error {
func (d *SqliteDB) Renew(id CustomerId) error {
customer, err := d.GetCustomer(id)
if err != nil {
return err
@@ -246,20 +245,20 @@ SELECT id, alpha_key, set_key, attributes_per_key, number_of_keys FROM user WHER
if err != nil {
return err
}
user := m.User{
Id: m.UserId{},
CustomerId: m.CustomerId{},
user := User{
Id: UserId{},
CustomerId: CustomerId{},
Username: "",
EncipheredPasscode: m.EncipheredNKode{},
Kp: m.KeypadDimension{
EncipheredPasscode: EncipheredNKode{},
Kp: KeypadDimension{
AttrsPerKey: attrsPerKey,
NumbOfKeys: numbOfKeys,
},
CipherKeys: m.UserCipherKeys{
CipherKeys: UserCipherKeys{
AlphaKey: util.ByteArrToUint64Arr(alphaBytes),
SetKey: util.ByteArrToUint64Arr(setBytes),
},
Interface: m.UserInterface{},
Interface: UserInterface{},
Renew: false,
}
err = user.RenewKeys(setXor, attrXor)
@@ -277,7 +276,7 @@ COMMIT;
return err
}
func (d *SqliteDB) RefreshUser(user m.User, passcodeIdx []int, customerAttr m.CustomerAttributes) error {
func (d *SqliteDB) RefreshUser(user User, passcodeIdx []int, customerAttr CustomerAttributes) error {
err := user.RefreshPasscode(passcodeIdx, customerAttr)
if err != nil {
return err
@@ -289,7 +288,7 @@ UPDATE user SET renew = ?, code = ?, mask = ?, alpha_key = ?, set_key = ?, pass_
return err
}
func (d *SqliteDB) RandomSvgInterface(kp m.KeypadDimension) ([]string, error) {
func (d *SqliteDB) RandomSvgInterface(kp KeypadDimension) ([]string, error) {
ids, err := d.getRandomIds(kp.TotalAttrs())
if err != nil {
return nil, err
@@ -297,11 +296,11 @@ func (d *SqliteDB) RandomSvgInterface(kp m.KeypadDimension) ([]string, error) {
return d.getSvgsById(ids)
}
func (d *SqliteDB) RandomSvgIdxInterface(kp m.KeypadDimension) (m.SvgIdInterface, error) {
func (d *SqliteDB) RandomSvgIdxInterface(kp KeypadDimension) (SvgIdInterface, error) {
return d.getRandomIds(kp.TotalAttrs())
}
func (d *SqliteDB) GetSvgStringInterface(idxs m.SvgIdInterface) ([]string, error) {
func (d *SqliteDB) GetSvgStringInterface(idxs SvgIdInterface) ([]string, error) {
return d.getSvgsById(idxs)
}

View File

@@ -1,13 +1,12 @@
package nkode
package core
import (
"github.com/stretchr/testify/assert"
m "go-nkode/core/model"
"testing"
)
func TestNewSqliteDB(t *testing.T) {
dbFile := "../../test.db"
dbFile := "../test.db"
// sql_driver.MakeTables(dbFile)
db := NewSqliteDB(dbFile)
defer db.CloseDb()
@@ -23,19 +22,19 @@ func TestNewSqliteDB(t *testing.T) {
}
func testSignupLoginRenew(t *testing.T, db DbAccessor) {
nkode_policy := m.NewDefaultNKodePolicy()
customerOrig, err := m.NewCustomer(nkode_policy)
nkode_policy := NewDefaultNKodePolicy()
customerOrig, err := NewCustomer(nkode_policy)
assert.NoError(t, err)
err = db.WriteNewCustomer(*customerOrig)
assert.NoError(t, err)
customer, err := db.GetCustomer(customerOrig.Id)
assert.NoError(t, err)
assert.Equal(t, customerOrig, customer)
username := m.Username("test_user")
kp := m.KeypadDefault
username := Username("test_user")
kp := KeypadDefault
passcodeIdx := []int{0, 1, 2, 3}
mockSvgInterface := make(m.SvgIdInterface, kp.TotalAttrs())
ui, err := m.NewUserInterface(&kp, mockSvgInterface)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
ui, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
userOrig, err := NewUser(*customer, username, passcodeIdx, *ui, kp)
assert.NoError(t, err)
@@ -51,7 +50,7 @@ func testSignupLoginRenew(t *testing.T, db DbAccessor) {
}
func testSqliteDBRandomSvgInterface(t *testing.T, db DbAccessor) {
kp := m.KeypadMax
kp := KeypadMax
svgs, err := db.RandomSvgInterface(kp)
assert.NoError(t, err)
assert.Len(t, svgs, kp.TotalAttrs())

View File

@@ -1,58 +0,0 @@
package svg_icon
import (
"database/sql"
"go-nkode/util"
)
type SvgIcon struct {
Id int
Svg string
}
type SvgIconDb struct {
path string
}
func (d *SvgIconDb) GetSvgsById(ids []int) ([]string, error) {
db, err := sql.Open("sqlite3", d.path)
if err != nil {
return nil, err
}
defer db.Close()
selectId := "SELECT svg FROM svg_icon where id = ?"
svgs := make([]string, len(ids))
for idx, id := range ids {
rows, err := db.Query(selectId, id)
if err != nil {
return nil, err
}
err = rows.Scan(&svgs[idx])
if err != nil {
return nil, err
}
}
return svgs, nil
}
func (d *SvgIconDb) GetRandomIds(count int) ([]int, error) {
db, err := sql.Open("sqlite3", d.path)
if err != nil {
return nil, err
}
defer db.Close()
rows, err := db.Query("SELECT COUNT(*) FROM svg_icon;")
if err != nil {
return nil, err
}
var tableLen int
err = rows.Scan(&tableLen)
if err != nil {
return nil, err
}
perm, err := util.RandomPermutation(tableLen)
if err != nil {
return nil, err
}
return perm[:count], nil
}

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"errors"

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"github.com/google/uuid"
@@ -63,6 +63,8 @@ type GenerateSignupInterfaceResp struct {
type GetLoginInterfaceResp struct {
UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"`
AttrsPerKey int `json:"attrs_per_key"`
NumbOfKeys int `json:"numb_of_keys"`
}
type KeySelection []int
@@ -74,19 +76,29 @@ type Username string
type IdxInterface []int
type SvgIdInterface []int
type NKodeAPIInterface interface {
CreateNewCustomer(NKodePolicy, *CustomerId) (*CustomerId, error)
GenerateSignupInterface(Username, CustomerId, KeypadDimension) (*GenerateSignupInterfaceResp, error)
SetNKode(CustomerId, SessionId, KeySelection) (IdxInterface, error)
ConfirmNKode(CustomerId, SessionId, KeySelection) error
GetLoginInterface(Username, CustomerId) (*GetLoginInterfaceResp, error)
Login(CustomerId, Username, KeySelection) error
RenewAttributes(CustomerId) error
RandomSvgInterface() ([]string, error)
GetSvgStringInterface(idInterface SvgIdInterface) ([]string, error)
func SessionIdFromString(sessionId string) (SessionId, error) {
id, err := uuid.Parse(sessionId)
if err != nil {
return SessionId{}, err
}
return SessionId(id), nil
}
type EncipheredNKode struct {
Code string
Mask string
}
type DbAccessor interface {
GetCustomer(CustomerId) (*Customer, error)
GetUser(Username, CustomerId) (*User, error)
WriteNewCustomer(Customer) error
WriteNewUser(User) error
UpdateUserInterface(UserId, UserInterface) error
Renew(CustomerId) error
RefreshUser(User, []int, CustomerAttributes) error
RandomSvgInterface(KeypadDimension) ([]string, error)
RandomSvgIdxInterface(KeypadDimension) (SvgIdInterface, error)
GetSvgStringInterface(SvgIdInterface) ([]string, error)
}

142
core/user.go Normal file
View File

@@ -0,0 +1,142 @@
package core
import (
"errors"
"github.com/google/uuid"
"go-nkode/py-builtin"
"go-nkode/util"
)
type User struct {
Id UserId
CustomerId CustomerId
Username Username
EncipheredPasscode EncipheredNKode
Kp KeypadDimension
CipherKeys UserCipherKeys
Interface UserInterface
Renew bool
}
func (u *User) DecipherMask(setVals []uint64, passcodeLen int) ([]uint64, error) {
return u.CipherKeys.DecipherMask(u.EncipheredPasscode.Mask, setVals, passcodeLen)
}
func (u *User) RenewKeys(setXor []uint64, attrXor []uint64) error {
u.Renew = true
var err error
u.CipherKeys.SetKey, err = util.XorLists(setXor[:u.Kp.AttrsPerKey], u.CipherKeys.SetKey)
if err != nil {
return err
}
u.CipherKeys.AlphaKey, err = util.XorLists(attrXor[:u.Kp.TotalAttrs()], u.CipherKeys.AlphaKey)
return err
}
func (u *User) RefreshPasscode(passcodeAttrIdx []int, customerAttributes CustomerAttributes) error {
setVals, err := customerAttributes.SetValsForKp(u.Kp)
newKeys, err := NewUserCipherKeys(&u.Kp, setVals, u.CipherKeys.MaxNKodeLen)
if err != nil {
return err
}
encipheredPasscode, err := newKeys.EncipherNKode(passcodeAttrIdx, customerAttributes)
if err != nil {
return err
}
u.CipherKeys = *newKeys
u.EncipheredPasscode = *encipheredPasscode
u.Renew = false
return nil
}
func (u *User) GetLoginInterface() ([]int, error) {
err := u.Interface.PartialInterfaceShuffle()
if err != nil {
return nil, err
}
return u.Interface.IdxInterface, nil
}
var KeyIndexOutOfRange = errors.New("one or more keys is out of range")
func ValidKeyEntry(user User, customer Customer, selectedKeys []int) ([]int, error) {
validKeys := py_builtin.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.SetValsForKp(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 {
return nil, err
}
attrVals, err := customer.Attributes.AttrValsForKp(user.Kp)
if err != nil {
return nil, err
}
err = user.CipherKeys.ValidPassword(user.EncipheredPasscode.Code, presumedAttrIdxVals, attrVals)
if err != nil {
return nil, err
}
return presumedAttrIdxVals, nil
}
func NewUser(customer Customer, username Username, passcodeIdx []int, ui UserInterface, kp KeypadDimension) (*User, error) {
setVals, err := customer.Attributes.SetValsForKp(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: UserId(uuid.New()),
Username: username,
EncipheredPasscode: *encipheredNKode,
CipherKeys: *newKeys,
Interface: ui,
Kp: kp,
CustomerId: customer.Id,
}
return &newUser, nil
}

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"crypto/sha256"
@@ -31,12 +31,12 @@ func NewUserCipherKeys(kp *KeypadDimension, setVals []uint64, maxNKodeLen int) (
return nil, err
}
alphakey, _ := util.GenerateRandomNonRepeatingUint64(kp.TotalAttrs())
alphaKey, _ := util.GenerateRandomNonRepeatingUint64(kp.TotalAttrs())
passKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
maskKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
salt, _ := util.RandomBytes(10)
userCipherKeys := UserCipherKeys{
AlphaKey: alphakey,
AlphaKey: alphaKey,
PassKey: passKey,
MaskKey: maskKey,
SetKey: setKey,
@@ -62,11 +62,8 @@ func (u *UserCipherKeys) PadUserMask(userMask []uint64, setVals []uint64) ([]uin
func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []int, attrVals []uint64) error {
hashBytes := []byte(hashedPassword)
passcodeCipher := u.encipherCode(passcodeAttrIdx, attrVals)
passwordDigest, err := u.saltAndDigest(passcodeCipher)
if err != nil {
return err
}
err = bcrypt.CompareHashAndPassword(hashBytes, passwordDigest)
passwordDigest := u.saltAndDigest(passcodeCipher)
err := bcrypt.CompareHashAndPassword(hashBytes, passwordDigest)
if err != nil {
return err
}
@@ -76,10 +73,7 @@ func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []
func (u *UserCipherKeys) EncipherSaltHashCode(passcodeAttrIdx []int, attrVals []uint64) (string, error) {
passcodeCipher := u.encipherCode(passcodeAttrIdx, attrVals)
passcodeDigest, err := u.saltAndDigest(passcodeCipher)
if err != nil {
return "", err
}
passcodeDigest := u.saltAndDigest(passcodeCipher)
passcodeBytes, err := u.hashPasscode(passcodeDigest)
if err != nil {
return "", err
@@ -91,37 +85,33 @@ func (u *UserCipherKeys) encipherCode(passcodeAttrIdx []int, attrVals []uint64)
passcodeLen := len(passcodeAttrIdx)
passcodeCipher := make([]uint64, u.MaxNKodeLen)
for idx := 0; idx < passcodeLen; idx++ {
attrIdx := passcodeAttrIdx[idx]
alpha := u.AlphaKey[attrIdx]
attrVal := attrVals[idx]
attrVal := attrVals[attrIdx]
pass := u.PassKey[idx]
passcodeCipher[idx] = alpha ^ pass ^ attrVal
}
return passcodeCipher
}
func (u *UserCipherKeys) saltAndDigest(passcode []uint64) ([]byte, error) {
func (u *UserCipherKeys) saltAndDigest(passcode []uint64) []byte {
passcodeBytes := util.Uint64ArrToByteArr(passcode)
passcodeBytes = append(passcodeBytes, u.Salt...)
h := sha256.New()
passcodeSha, err := h.Write(passcodeBytes)
if err != nil {
return nil, err
}
passcodeDigest := uint64(passcodeSha)
return util.Uint64ArrToByteArr([]uint64{passcodeDigest}), nil
h.Write(passcodeBytes)
return h.Sum(nil)
}
func (u *UserCipherKeys) hashPasscode(passcodeDigest []byte) ([]byte, error) {
hashedPassword, err := bcrypt.GenerateFromPassword(passcodeDigest, bcrypt.DefaultCost)
if err != nil {
return nil, err
}
return hashedPassword, nil
}
func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs CustomerAttributes, userKp KeypadDimension) (string, error) {
setVals, err := customerAttrs.SetValsForKp(userKp)
if err != nil {

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"errors"

View File

@@ -1,29 +1,28 @@
package nkode
package core
import (
"errors"
"fmt"
"github.com/google/uuid"
m "go-nkode/core/model"
"go-nkode/hashset"
py "go-nkode/py-builtin"
"go-nkode/util"
)
type UserSignSession struct {
Id m.SessionId
CustomerId m.CustomerId
LoginUserInterface m.UserInterface
Kp m.KeypadDimension
SetIdxInterface m.IdxInterface
ConfirmIdxInterface m.IdxInterface
SetKeySelection m.KeySelection
Username m.Username
Id SessionId
CustomerId CustomerId
LoginUserInterface UserInterface
Kp KeypadDimension
SetIdxInterface IdxInterface
ConfirmIdxInterface IdxInterface
SetKeySelection KeySelection
Username Username
Expire int
}
func NewSignupSession(username m.Username, kp m.KeypadDimension, customerId m.CustomerId, svgInterface m.SvgIdInterface) (*UserSignSession, error) {
loginInterface, err := m.NewUserInterface(&kp, svgInterface)
func NewSignupSession(username Username, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(&kp, svgInterface)
if err != nil {
return nil, err
}
@@ -32,7 +31,7 @@ func NewSignupSession(username m.Username, kp m.KeypadDimension, customerId m.Cu
return nil, err
}
session := UserSignSession{
Id: m.SessionId(uuid.New()),
Id: SessionId(uuid.New()),
CustomerId: customerId,
LoginUserInterface: *loginInterface,
SetIdxInterface: signupInterface.IdxInterface,
@@ -45,7 +44,7 @@ func NewSignupSession(username m.Username, kp m.KeypadDimension, customerId m.Cu
return &session, nil
}
func (s *UserSignSession) DeducePasscode(confirmKeyEntry m.KeySelection) ([]int, error) {
func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) {
validEntry := py.All[int](confirmKeyEntry, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
@@ -98,7 +97,7 @@ func (s *UserSignSession) DeducePasscode(confirmKeyEntry m.KeySelection) ([]int,
return passcode, nil
}
func (s *UserSignSession) SetUserNKode(keySelection m.KeySelection) (m.IdxInterface, error) {
func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) {
validKeySelection := py.All[int](keySelection, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
@@ -108,7 +107,7 @@ func (s *UserSignSession) SetUserNKode(keySelection m.KeySelection) (m.IdxInterf
s.SetKeySelection = keySelection
setKp := s.SignupKeypad()
setInterface := m.UserInterface{IdxInterface: s.SetIdxInterface, Kp: &setKp}
setInterface := UserInterface{IdxInterface: s.SetIdxInterface, Kp: &setKp}
err := setInterface.DisperseInterface()
if err != nil {
return nil, err
@@ -117,7 +116,7 @@ func (s *UserSignSession) SetUserNKode(keySelection m.KeySelection) (m.IdxInterf
return s.ConfirmIdxInterface, nil
}
func (s *UserSignSession) getSelectedKeyVals(keySelections m.KeySelection, userInterface []int) ([][]int, error) {
func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInterface []int) ([][]int, error) {
signupKp := s.SignupKeypad()
keypadInterface, err := util.ListToMatrix(userInterface, signupKp.AttrsPerKey)
if err != nil {
@@ -131,7 +130,7 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections m.KeySelection, userI
return keyVals, nil
}
func signupInterface(baseUserInterface m.UserInterface, kp m.KeypadDimension) (*m.UserInterface, error) {
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, error) {
if kp.IsDispersable() {
return nil, errors.New("keypad is dispersable, can't use signupInterface")
}
@@ -157,9 +156,9 @@ func signupInterface(baseUserInterface m.UserInterface, kp m.KeypadDimension) (*
if err != nil {
return nil, err
}
signupUserInterface := m.UserInterface{
signupUserInterface := UserInterface{
IdxInterface: util.MatrixToList(attrSetView),
Kp: &m.KeypadDimension{
Kp: &KeypadDimension{
AttrsPerKey: numbOfKeys,
NumbOfKeys: numbOfKeys,
},
@@ -167,8 +166,8 @@ func signupInterface(baseUserInterface m.UserInterface, kp m.KeypadDimension) (*
return &signupUserInterface, nil
}
func (s *UserSignSession) SignupKeypad() m.KeypadDimension {
return m.KeypadDimension{
func (s *UserSignSession) SignupKeypad() KeypadDimension {
return KeypadDimension{
AttrsPerKey: s.Kp.NumbOfKeys,
NumbOfKeys: s.Kp.NumbOfKeys,
}

View File

@@ -1,4 +1,4 @@
package model
package core
import (
"github.com/stretchr/testify/assert"
@@ -22,6 +22,11 @@ func TestUserCipherKeys_EncipherSaltHashCode(t *testing.T) {
assert.NoError(t, err)
err = newUser.ValidPassword(encipher0, passcodeIdx, attrVals)
assert.NoError(t, err)
passcodeIdxInvalid := []int{1, 0, 3, 2}
assert.NoError(t, err)
err = newUser.ValidPassword(encipher0, passcodeIdxInvalid, attrVals)
assert.Error(t, err)
}
func TestUserCipherKeys_EncipherDecipherMask(t *testing.T) {

1
go.mod
View File

@@ -14,6 +14,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

2
go.sum
View File

@@ -1,5 +1,7 @@
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/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
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/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=

32
main.go
View File

@@ -3,29 +3,27 @@ package main
import (
"fmt"
"github.com/google/uuid"
"go-nkode/core/api"
"go-nkode/core/model"
"go-nkode/core/nkode"
"go-nkode/core"
"log"
"net/http"
)
func main() {
//db := nkode.NewInMemoryDb()
db := nkode.NewSqliteDB("nkode.db")
db := core.NewSqliteDB("nkode.db")
defer db.CloseDb()
nkodeApi := nkode.NewNKodeAPI(db)
nkodeApi := core.NewNKodeAPI(db)
AddDefaultCustomer(nkodeApi)
handler := model.NKodeHandler{Api: &nkodeApi}
handler := core.NKodeHandler{Api: nkodeApi}
mux := http.NewServeMux()
mux.Handle(api.CreateNewCustomer, &handler)
mux.Handle(api.GenerateSignupInterface, &handler)
mux.Handle(api.SetNKode, &handler)
mux.Handle(api.ConfirmNKode, &handler)
mux.Handle(api.GetLoginInterface, &handler)
mux.Handle(api.Login, &handler)
mux.Handle(api.RenewAttributes, &handler)
mux.Handle(api.RandomSvgInterface, &handler)
mux.Handle(core.CreateNewCustomer, &handler)
mux.Handle(core.GenerateSignupInterface, &handler)
mux.Handle(core.SetNKode, &handler)
mux.Handle(core.ConfirmNKode, &handler)
mux.Handle(core.GetLoginInterface, &handler)
mux.Handle(core.Login, &handler)
mux.Handle(core.RenewAttributes, &handler)
mux.Handle(core.RandomSvgInterface, &handler)
fmt.Println("Running on localhost:8080...")
log.Fatal(http.ListenAndServe("localhost:8080", corsMiddleware(mux)))
}
@@ -48,13 +46,13 @@ func corsMiddleware(next http.Handler) http.Handler {
})
}
func AddDefaultCustomer(api nkode.NKodeAPI) {
func AddDefaultCustomer(api core.NKodeAPI) {
newId, err := uuid.Parse("ed9ed6e0-082c-4b57-8d8c-f00ed6493457")
if err != nil {
log.Fatal(err)
}
customerId := model.CustomerId(newId)
nkode_policy := model.NewDefaultNKodePolicy()
customerId := core.CustomerId(newId)
nkode_policy := core.NewDefaultNKodePolicy()
_, err = api.CreateNewCustomer(nkode_policy, &customerId)
if err != nil {
log.Print(err)

View File

@@ -4,8 +4,7 @@ import (
"bytes"
"encoding/json"
"github.com/stretchr/testify/assert"
"go-nkode/core/api"
m "go-nkode/core/model"
"go-nkode/core"
"io"
"net/http"
"testing"
@@ -13,84 +12,84 @@ import (
func TestApi(t *testing.T) {
base := "http://localhost:8080"
newCustomerBody := m.NewCustomerPost{
NKodePolicy: m.NewDefaultNKodePolicy(),
newCustomerBody := core.NewCustomerPost{
NKodePolicy: core.NewDefaultNKodePolicy(),
}
kp := m.KeypadDimension{
kp := core.KeypadDimension{
AttrsPerKey: 14,
NumbOfKeys: 10,
}
var customerResp m.CreateNewCustomerResp
testApiPost(t, base+api.CreateNewCustomer, newCustomerBody, &customerResp)
var customerResp core.CreateNewCustomerResp
testApiPost(t, base+core.CreateNewCustomer, newCustomerBody, &customerResp)
username := m.Username("test_username")
signupInterfaceBody := m.GenerateSignupInterfacePost{
username := core.Username("test_username")
signupInterfaceBody := core.GenerateSignupInterfacePost{
CustomerId: customerResp.CustomerId,
AttrsPerKey: kp.AttrsPerKey,
NumbOfKeys: kp.NumbOfKeys,
Username: username,
}
var signupInterfaceResp m.GenerateSignupInterfaceResp
testApiPost(t, base+api.GenerateSignupInterface, signupInterfaceBody, &signupInterfaceResp)
var signupInterfaceResp core.GenerateSignupInterfaceResp
testApiPost(t, base+core.GenerateSignupInterface, signupInterfaceBody, &signupInterfaceResp)
assert.Len(t, signupInterfaceResp.SvgInterface, kp.TotalAttrs())
passcodeLen := 4
setInterface := signupInterfaceResp.UserIdxInterface
userPasscode := setInterface[:passcodeLen]
kp_set := m.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys}
setKeySelection, err := m.SelectKeyByAttrIdx(setInterface, userPasscode, kp_set)
kp_set := core.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys}
setKeySelection, err := core.SelectKeyByAttrIdx(setInterface, userPasscode, kp_set)
assert.NoError(t, err)
setNKodeBody := m.SetNKodePost{
setNKodeBody := core.SetNKodePost{
CustomerId: customerResp.CustomerId,
SessionId: signupInterfaceResp.SessionId,
KeySelection: setKeySelection,
}
var setNKodeResp m.SetNKodeResp
testApiPost(t, base+api.SetNKode, setNKodeBody, &setNKodeResp)
var setNKodeResp core.SetNKodeResp
testApiPost(t, base+core.SetNKode, setNKodeBody, &setNKodeResp)
confirmInterface := setNKodeResp.UserInterface
confirmKeySelection, err := m.SelectKeyByAttrIdx(confirmInterface, userPasscode, kp_set)
confirmKeySelection, err := core.SelectKeyByAttrIdx(confirmInterface, userPasscode, kp_set)
assert.NoError(t, err)
confirmNKodeBody := m.ConfirmNKodePost{
confirmNKodeBody := core.ConfirmNKodePost{
CustomerId: customerResp.CustomerId,
KeySelection: confirmKeySelection,
SessionId: signupInterfaceResp.SessionId,
}
testApiPost(t, base+api.ConfirmNKode, confirmNKodeBody, nil)
testApiPost(t, base+core.ConfirmNKode, confirmNKodeBody, nil)
loginInterfaceBody := m.GetLoginInterfacePost{
loginInterfaceBody := core.GetLoginInterfacePost{
CustomerId: customerResp.CustomerId,
Username: username,
}
var loginInterfaceResp m.GetLoginInterfaceResp
testApiPost(t, base+api.GetLoginInterface, loginInterfaceBody, &loginInterfaceResp)
loginKeySelection, err := m.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
var loginInterfaceResp core.GetLoginInterfaceResp
testApiPost(t, base+core.GetLoginInterface, loginInterfaceBody, &loginInterfaceResp)
assert.Equal(t, loginInterfaceResp.AttrsPerKey, kp.AttrsPerKey)
assert.Equal(t, loginInterfaceResp.NumbOfKeys, kp.NumbOfKeys)
loginKeySelection, err := core.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
loginBody := m.LoginPost{
loginBody := core.LoginPost{
CustomerId: customerResp.CustomerId,
Username: username,
KeySelection: loginKeySelection,
}
testApiPost(t, base+api.Login, loginBody, nil)
testApiPost(t, base+core.Login, loginBody, nil)
renewBody := m.RenewAttributesPost{CustomerId: customerResp.CustomerId}
testApiPost(t, base+api.RenewAttributes, renewBody, nil)
renewBody := core.RenewAttributesPost{CustomerId: customerResp.CustomerId}
testApiPost(t, base+core.RenewAttributes, renewBody, nil)
loginKeySelection, err = m.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
loginKeySelection, err = core.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
loginBody = m.LoginPost{
loginBody = core.LoginPost{
CustomerId: customerResp.CustomerId,
Username: username,
KeySelection: loginKeySelection,
}
testApiPost(t, base+api.Login, loginBody, nil)
var randomSvgInterfaceResp m.RandomSvgInterfaceResp
testApiGet(t, base+api.RandomSvgInterface, &randomSvgInterfaceResp)
assert.Equal(t, m.KeypadMax.TotalAttrs(), len(randomSvgInterfaceResp.Svgs))
testApiPost(t, base+core.Login, loginBody, nil)
var randomSvgInterfaceResp core.RandomSvgInterfaceResp
testApiGet(t, base+core.RandomSvgInterface, &randomSvgInterfaceResp)
assert.Equal(t, core.KeypadMax.TotalAttrs(), len(randomSvgInterfaceResp.Svgs))
}
func Unmarshal(t *testing.T, resp *http.Response, data any) {

View File

@@ -1,71 +0,0 @@
package sql_driver
import (
"database/sql"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
"log"
)
func MakeTables(dbPath string) {
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
log.Fatal(err)
}
defer db.Close()
createTable := `
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS customer (
id TEXT NOT NULL PRIMARY KEY,
max_nkode_len INTEGER NOT NULL,
min_nkode_len INTEGER NOT NULL,
distinct_sets INTEGER NOT NULL,
distinct_attributes INTEGER NOT NULL,
lock_out INTEGER NOT NULL,
expiration INTEGER NOT NULL,
attribute_values BLOB NOT NULL,
set_values BLOB NOT NULL
);
CREATE TABLE IF NOT EXISTS user (
id TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
renew INT NOT NULL,
customer_id TEXT NOT NULL,
-- Enciphered Passcode
code TEXT NOT NULL,
mask TEXT NOT NULL,
-- Keypad Dimensions
attributes_per_key INT NOT NULL,
number_of_keys INT NOT NULL,
-- User Keys
alpha_key BLOB NOT NULL,
set_key BLOB NOT NULL,
pass_key BLOB NOT NULL,
mask_key BLOB NOT NULL,
salt BLOB NOT NULL,
max_nkode_len INT NOT NULL,
-- User Interface
idx_interface BLOB NOT NULL,
svg_id_interface BLOB NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id),
UNIQUE(customer_id, username)
);
CREATE TABLE IF NOT EXISTS svg_icon (
id INTEGER PRIMARY KEY AUTOINCREMENT,
svg TEXT NOT NULL
);
`
_, err = db.Exec(createTable)
if err != nil {
log.Fatal(err)
}
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
"go-nkode/sql-driver"
"io/ioutil"
"log"
"path/filepath"
@@ -28,7 +27,7 @@ func main() {
dbPaths := []string{"test.db", "nkode.db"}
outputStr := MakeSvgFiles()
for _, path := range dbPaths {
sql_driver.MakeTables(path)
MakeTables(path)
SaveToSqlite(path, outputStr)
}
}
@@ -136,3 +135,67 @@ func LoadJson(filename string) (*Root, error) {
return &root, nil
}
func MakeTables(dbPath string) {
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
log.Fatal(err)
}
defer db.Close()
createTable := `
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS customer (
id TEXT NOT NULL PRIMARY KEY,
max_nkode_len INTEGER NOT NULL,
min_nkode_len INTEGER NOT NULL,
distinct_sets INTEGER NOT NULL,
distinct_attributes INTEGER NOT NULL,
lock_out INTEGER NOT NULL,
expiration INTEGER NOT NULL,
attribute_values BLOB NOT NULL,
set_values BLOB NOT NULL
);
CREATE TABLE IF NOT EXISTS user (
id TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
renew INT NOT NULL,
customer_id TEXT NOT NULL,
-- Enciphered Passcode
code TEXT NOT NULL,
mask TEXT NOT NULL,
-- Keypad Dimensions
attributes_per_key INT NOT NULL,
number_of_keys INT NOT NULL,
-- User Keys
alpha_key BLOB NOT NULL,
set_key BLOB NOT NULL,
pass_key BLOB NOT NULL,
mask_key BLOB NOT NULL,
salt BLOB NOT NULL,
max_nkode_len INT NOT NULL,
-- User Interface
idx_interface BLOB NOT NULL,
svg_id_interface BLOB NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(id),
UNIQUE(customer_id, username)
);
CREATE TABLE IF NOT EXISTS svg_icon (
id INTEGER PRIMARY KEY AUTOINCREMENT,
svg TEXT NOT NULL
);
`
_, err = db.Exec(createTable)
if err != nil {
log.Fatal(err)
}
}