more refactoring

This commit is contained in:
2024-11-27 09:41:31 -06:00
parent 35039bf494
commit c0b785ca8d
21 changed files with 167 additions and 151 deletions

1
.env.test.example Normal file
View File

@@ -0,0 +1 @@
TEST_DB=/path/to/test.db

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"github.com/stretchr/testify/assert"
"go-nkode/internal/api"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/security"
"io"
@@ -19,7 +20,7 @@ func TestApi(t *testing.T) {
newCustomerBody := models.NewCustomerPost{
NKodePolicy: models.NewDefaultNKodePolicy(),
}
kp := models.KeypadDimension{
kp := entities.KeypadDimension{
AttrsPerKey: 14,
NumbOfKeys: 10,
}
@@ -40,8 +41,8 @@ func TestApi(t *testing.T) {
passcodeLen := 4
setInterface := signupInterfaceResp.UserIdxInterface
userPasscode := setInterface[:passcodeLen]
kpSet := models.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys}
setKeySelection, err := models.SelectKeyByAttrIdx(setInterface, userPasscode, kpSet)
kpSet := entities.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys}
setKeySelection, err := entities.SelectKeyByAttrIdx(setInterface, userPasscode, kpSet)
assert.NoError(t, err)
setNKodeBody := models.SetNKodePost{
CustomerId: customerResp.CustomerId,
@@ -51,7 +52,7 @@ func TestApi(t *testing.T) {
var setNKodeResp models.SetNKodeResp
testApiPost(t, base+api.SetNKode, setNKodeBody, &setNKodeResp)
confirmInterface := setNKodeResp.UserInterface
confirmKeySelection, err := models.SelectKeyByAttrIdx(confirmInterface, userPasscode, kpSet)
confirmKeySelection, err := entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, kpSet)
assert.NoError(t, err)
confirmNKodeBody := models.ConfirmNKodePost{
CustomerId: customerResp.CustomerId,
@@ -69,7 +70,7 @@ func TestApi(t *testing.T) {
testApiPost(t, base+api.GetLoginInterface, loginInterfaceBody, &loginInterfaceResp)
assert.Equal(t, loginInterfaceResp.AttrsPerKey, kp.AttrsPerKey)
assert.Equal(t, loginInterfaceResp.NumbOfKeys, kp.NumbOfKeys)
loginKeySelection, err := models.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
loginKeySelection, err := entities.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
loginBody := models.LoginPost{
CustomerId: customerResp.CustomerId,
@@ -86,7 +87,7 @@ func TestApi(t *testing.T) {
renewBody := models.RenewAttributesPost{CustomerId: customerResp.CustomerId}
testApiPost(t, base+api.RenewAttributes, renewBody, nil)
loginKeySelection, err = models.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterfaceResp.UserIdxInterface, userPasscode, kp)
assert.NoError(t, err)
loginBody = models.LoginPost{
CustomerId: customerResp.CustomerId,
@@ -98,7 +99,7 @@ func TestApi(t *testing.T) {
var randomSvgInterfaceResp models.RandomSvgInterfaceResp
testApiGet(t, base+api.RandomSvgInterface, &randomSvgInterfaceResp, "")
assert.Equal(t, models.KeypadMax.TotalAttrs(), len(randomSvgInterfaceResp.Svgs))
assert.Equal(t, entities.KeypadMax.TotalAttrs(), len(randomSvgInterfaceResp.Svgs))
var refreshTokenResp models.RefreshTokenResp

View File

@@ -1,20 +0,0 @@
package api
import (
"go-nkode/internal/models"
)
type DbAccessor interface {
GetCustomer(models.CustomerId) (*models.Customer, error)
GetUser(models.UserEmail, models.CustomerId) (*models.User, error)
WriteNewCustomer(models.Customer) error
WriteNewUser(models.User) error
UpdateUserNKode(models.User) error
UpdateUserInterface(models.UserId, models.UserInterface) error
UpdateUserRefreshToken(models.UserId, string) error
Renew(models.CustomerId) error
RefreshUserPasscode(models.User, []int, models.CustomerAttributes) error
RandomSvgInterface(models.KeypadDimension) ([]string, error)
RandomSvgIdxInterface(models.KeypadDimension) (models.SvgIdInterface, error)
GetSvgStringInterface(models.SvgIdInterface) ([]string, error)
}

View File

@@ -5,6 +5,7 @@ import (
"errors"
"github.com/google/uuid"
"go-nkode/config"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/security"
"log"
@@ -108,7 +109,7 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter
return
}
kp := models.KeypadDimension{
kp := entities.KeypadDimension{
AttrsPerKey: signupResetPost.AttrsPerKey,
NumbOfKeys: signupResetPost.NumbOfKeys,
}

View File

@@ -5,7 +5,9 @@ import (
"github.com/google/uuid"
"github.com/patrickmn/go-cache"
"go-nkode/config"
"go-nkode/internal/db"
"go-nkode/internal/email"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/security"
"log"
@@ -19,12 +21,12 @@ const (
)
type NKodeAPI struct {
Db DbAccessor
Db db.CustomerUserRepository
SignupSessionCache *cache.Cache
EmailQueue *email.EmailQueue
EmailQueue *email.Queue
}
func NewNKodeAPI(db DbAccessor, queue *email.EmailQueue) NKodeAPI {
func NewNKodeAPI(db db.CustomerUserRepository, queue *email.Queue) NKodeAPI {
return NKodeAPI{
Db: db,
EmailQueue: queue,
@@ -33,7 +35,7 @@ func NewNKodeAPI(db DbAccessor, queue *email.EmailQueue) NKodeAPI {
}
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy models.NKodePolicy, id *models.CustomerId) (*models.CustomerId, error) {
newCustomer, err := models.NewCustomer(nkodePolicy)
newCustomer, err := entities.NewCustomer(nkodePolicy)
if id != nil {
newCustomer.Id = *id
}
@@ -48,7 +50,7 @@ func (n *NKodeAPI) CreateNewCustomer(nkodePolicy models.NKodePolicy, id *models.
return &newCustomer.Id, nil
}
func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, customerId models.CustomerId, kp models.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, error) {
func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, customerId models.CustomerId, kp entities.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, error) {
user, err := n.Db.GetUser(userEmail, customerId)
if err != nil {
return nil, err
@@ -61,7 +63,7 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, cust
if err != nil {
return nil, err
}
signupSession, err := models.NewSignupResetSession(userEmail, kp, customerId, svgIdxInterface, reset)
signupSession, err := entities.NewSignupResetSession(userEmail, kp, customerId, svgIdxInterface, reset)
if err != nil {
return nil, err
}
@@ -94,7 +96,7 @@ func (n *NKodeAPI) SetNKode(customerId models.CustomerId, sessionId models.Sessi
log.Printf("session id does not exist %s", sessionId)
return nil, config.ErrSignupSessionDNE
}
userSession, ok := session.(models.UserSignSession)
userSession, ok := session.(entities.UserSignSession)
if !ok {
// handle the case where the type assertion fails
return nil, config.ErrSignupSessionDNE
@@ -113,7 +115,7 @@ func (n *NKodeAPI) ConfirmNKode(customerId models.CustomerId, sessionId models.S
log.Printf("session id does not exist %s", sessionId)
return config.ErrSignupSessionDNE
}
userSession, ok := session.(models.UserSignSession)
userSession, ok := session.(entities.UserSignSession)
if !ok {
// handle the case where the type assertion fails
return config.ErrSignupSessionDNE
@@ -129,7 +131,7 @@ func (n *NKodeAPI) ConfirmNKode(customerId models.CustomerId, sessionId models.S
if err = customer.IsValidNKode(userSession.Kp, passcode); err != nil {
return err
}
user, err := models.NewUser(*customer, string(userSession.UserEmail), passcode, userSession.LoginUserInterface, userSession.Kp)
user, err := entities.NewUser(*customer, string(userSession.UserEmail), passcode, userSession.LoginUserInterface, userSession.Kp)
if err != nil {
return err
}
@@ -186,7 +188,7 @@ func (n *NKodeAPI) Login(customerId models.CustomerId, userEmail models.UserEmai
log.Printf("user %s for customer %s dne", userEmail, customerId)
return nil, config.ErrUserForCustomerDNE
}
passcode, err := models.ValidKeyEntry(*user, *customer, keySelection)
passcode, err := entities.ValidKeyEntry(*user, *customer, keySelection)
if err != nil {
return nil, err
}
@@ -213,7 +215,7 @@ func (n *NKodeAPI) RenewAttributes(customerId models.CustomerId) error {
}
func (n *NKodeAPI) RandomSvgInterface() ([]string, error) {
return n.Db.RandomSvgInterface(models.KeypadMax)
return n.Db.RandomSvgInterface(entities.KeypadMax)
}
func (n *NKodeAPI) RefreshToken(userEmail models.UserEmail, customerId models.CustomerId, refreshToken string) (string, error) {

View File

@@ -4,6 +4,7 @@ import (
"github.com/stretchr/testify/assert"
"go-nkode/internal/db"
"go-nkode/internal/email"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/security"
"os"
@@ -28,7 +29,7 @@ func TestNKodeAPI(t *testing.T) {
//}
}
func testNKodeAPI(t *testing.T, db DbAccessor) {
func testNKodeAPI(t *testing.T, db db.CustomerUserRepository) {
bufferSize := 100
emailsPerSec := 14
testClient := email.TestEmailClient{}
@@ -41,7 +42,7 @@ func testNKodeAPI(t *testing.T, db DbAccessor) {
userEmail := models.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com")
passcodeLen := 4
nkodePolicy := models.NewDefaultNKodePolicy()
keypadSize := models.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
keypadSize := entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
nkodeApi := NewNKodeAPI(db, queue)
customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy, nil)
assert.NoError(t, err)
@@ -51,20 +52,20 @@ func testNKodeAPI(t *testing.T, db DbAccessor) {
sessionIdStr := signupResponse.SessionId
sessionId, err := models.SessionIdFromString(sessionIdStr)
assert.NoError(t, err)
keypadSize = models.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
userPasscode := setInterface[:passcodeLen]
setKeySelect, err := models.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
setKeySelect, err := entities.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
assert.NoError(t, err)
confirmInterface, err := nkodeApi.SetNKode(*customerId, sessionId, setKeySelect)
assert.NoError(t, err)
confirmKeySelect, err := models.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
confirmKeySelect, err := entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
err = nkodeApi.ConfirmNKode(*customerId, sessionId, confirmKeySelect)
assert.NoError(t, err)
keypadSize = models.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
loginInterface, err := nkodeApi.GetLoginInterface(userEmail, *customerId)
assert.NoError(t, err)
loginKeySelection, err := models.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
loginKeySelection, err := entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
assert.NoError(t, err)
_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
assert.NoError(t, err)
@@ -74,34 +75,34 @@ func testNKodeAPI(t *testing.T, db DbAccessor) {
loginInterface, err = nkodeApi.GetLoginInterface(userEmail, *customerId)
assert.NoError(t, err)
loginKeySelection, err = models.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
assert.NoError(t, err)
_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
assert.NoError(t, err)
/// Reset nKode
attrsPerKey = 6
keypadSize = models.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
resetResponse, err := nkodeApi.GenerateSignupResetInterface(userEmail, *customerId, keypadSize, true)
assert.NoError(t, err)
setInterface = resetResponse.UserIdxInterface
sessionIdStr = resetResponse.SessionId
sessionId, err = models.SessionIdFromString(sessionIdStr)
assert.NoError(t, err)
keypadSize = models.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
userPasscode = setInterface[:passcodeLen]
setKeySelect, err = models.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
setKeySelect, err = entities.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
assert.NoError(t, err)
confirmInterface, err = nkodeApi.SetNKode(*customerId, sessionId, setKeySelect)
assert.NoError(t, err)
confirmKeySelect, err = models.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
confirmKeySelect, err = entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
err = nkodeApi.ConfirmNKode(*customerId, sessionId, confirmKeySelect)
assert.NoError(t, err)
keypadSize = models.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
loginInterface2, err := nkodeApi.GetLoginInterface(userEmail, *customerId)
assert.NoError(t, err)
loginKeySelection, err = models.SelectKeyByAttrIdx(loginInterface2.UserIdxInterface, userPasscode, keypadSize)
loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface2.UserIdxInterface, userPasscode, keypadSize)
assert.NoError(t, err)
_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
assert.NoError(t, err)

View File

@@ -0,0 +1,21 @@
package db
import (
"go-nkode/internal/entities"
"go-nkode/internal/models"
)
type CustomerUserRepository interface {
GetCustomer(models.CustomerId) (*entities.Customer, error)
GetUser(models.UserEmail, models.CustomerId) (*entities.User, error)
WriteNewCustomer(entities.Customer) error
WriteNewUser(entities.User) error
UpdateUserNKode(entities.User) error
UpdateUserInterface(models.UserId, entities.UserInterface) error
UpdateUserRefreshToken(models.UserId, string) error
Renew(models.CustomerId) error
RefreshUserPasscode(entities.User, []int, entities.CustomerAttributes) error
RandomSvgInterface(entities.KeypadDimension) ([]string, error)
RandomSvgIdxInterface(entities.KeypadDimension) (models.SvgIdInterface, error)
GetSvgStringInterface(models.SvgIdInterface) ([]string, error)
}

View File

@@ -3,24 +3,25 @@ package db
import (
"errors"
"fmt"
"go-nkode/internal/entities"
"go-nkode/internal/models"
)
type InMemoryDb struct {
Customers map[models.CustomerId]models.Customer
Users map[models.UserId]models.User
Customers map[models.CustomerId]entities.Customer
Users map[models.UserId]entities.User
userIdMap map[string]models.UserId
}
func NewInMemoryDb() InMemoryDb {
return InMemoryDb{
Customers: make(map[models.CustomerId]models.Customer),
Users: make(map[models.UserId]models.User),
Customers: make(map[models.CustomerId]entities.Customer),
Users: make(map[models.UserId]entities.User),
userIdMap: make(map[string]models.UserId),
}
}
func (db *InMemoryDb) GetCustomer(id models.CustomerId) (*models.Customer, error) {
func (db *InMemoryDb) GetCustomer(id models.CustomerId) (*entities.Customer, error) {
customer, exists := db.Customers[id]
if !exists {
return nil, errors.New(fmt.Sprintf("customer %s dne", customer.Id))
@@ -28,7 +29,7 @@ func (db *InMemoryDb) GetCustomer(id models.CustomerId) (*models.Customer, error
return &customer, nil
}
func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.CustomerId) (*models.User, error) {
func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.CustomerId) (*entities.User, error) {
key := userIdKey(customerId, username)
userId, exists := db.userIdMap[key]
if !exists {
@@ -41,7 +42,7 @@ func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.Custo
return &user, nil
}
func (db *InMemoryDb) WriteNewCustomer(customer models.Customer) error {
func (db *InMemoryDb) WriteNewCustomer(customer entities.Customer) error {
_, exists := db.Customers[customer.Id]
if exists {
@@ -51,7 +52,7 @@ func (db *InMemoryDb) WriteNewCustomer(customer models.Customer) error {
return nil
}
func (db *InMemoryDb) WriteNewUser(user models.User) error {
func (db *InMemoryDb) WriteNewUser(user entities.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.Email, user.CustomerId))
@@ -67,11 +68,11 @@ func (db *InMemoryDb) WriteNewUser(user models.User) error {
return nil
}
func (db *InMemoryDb) UpdateUserNKode(user models.User) error {
func (db *InMemoryDb) UpdateUserNKode(user entities.User) error {
return errors.ErrUnsupported
}
func (db *InMemoryDb) UpdateUserInterface(userId models.UserId, ui models.UserInterface) error {
func (db *InMemoryDb) UpdateUserInterface(userId models.UserId, ui entities.UserInterface) error {
user, exists := db.Users[userId]
if !exists {
return errors.New(fmt.Sprintf("can't update user %s, dne", user.Id))
@@ -107,7 +108,7 @@ func (db *InMemoryDb) Renew(id models.CustomerId) error {
return nil
}
func (db *InMemoryDb) RefreshUserPasscode(user models.User, passocode []int, customerAttr models.CustomerAttributes) error {
func (db *InMemoryDb) RefreshUserPasscode(user entities.User, passocode []int, customerAttr entities.CustomerAttributes) error {
err := user.RefreshPasscode(passocode, customerAttr)
if err != nil {
return err
@@ -116,11 +117,11 @@ func (db *InMemoryDb) RefreshUserPasscode(user models.User, passocode []int, cus
return nil
}
func (db *InMemoryDb) RandomSvgInterface(kp models.KeypadDimension) ([]string, error) {
func (db *InMemoryDb) RandomSvgInterface(kp entities.KeypadDimension) ([]string, error) {
return make([]string, kp.TotalAttrs()), nil
}
func (db *InMemoryDb) RandomSvgIdxInterface(kp models.KeypadDimension) (models.SvgIdInterface, error) {
func (db *InMemoryDb) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) {
svgs := make(models.SvgIdInterface, kp.TotalAttrs())
for idx := range svgs {
svgs[idx] = idx

View File

@@ -6,6 +6,7 @@ import (
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
"go-nkode/config"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/security"
"log"
@@ -60,7 +61,7 @@ func (d *SqliteDB) CloseDb() {
}
}
func (d *SqliteDB) WriteNewCustomer(c models.Customer) error {
func (d *SqliteDB) WriteNewCustomer(c entities.Customer) error {
query := `
INSERT INTO customer (
id
@@ -85,7 +86,7 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?)
return d.addWriteTx(query, args)
}
func (d *SqliteDB) WriteNewUser(u models.User) error {
func (d *SqliteDB) WriteNewUser(u entities.User) error {
query := `
INSERT INTO user (
id
@@ -128,7 +129,7 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
return d.addWriteTx(query, args)
}
func (d *SqliteDB) UpdateUserNKode(u models.User) error {
func (d *SqliteDB) UpdateUserNKode(u entities.User) error {
query := `
UPDATE user
SET renew = ?
@@ -158,7 +159,7 @@ WHERE email = ? AND customer_id = ?
return d.addWriteTx(query, args)
}
func (d *SqliteDB) UpdateUserInterface(id models.UserId, ui models.UserInterface) error {
func (d *SqliteDB) UpdateUserInterface(id models.UserId, ui entities.UserInterface) error {
query := `
UPDATE user SET idx_interface = ?, last_login = ? WHERE id = ?
`
@@ -219,20 +220,20 @@ WHERE customer_id = ?
if err != nil {
return err
}
user := models.User{
user := entities.User{
Id: models.UserId{},
CustomerId: models.CustomerId{},
Email: "",
EncipheredPasscode: models.EncipheredNKode{},
Kp: models.KeypadDimension{
Kp: entities.KeypadDimension{
AttrsPerKey: attrsPerKey,
NumbOfKeys: numbOfKeys,
},
CipherKeys: models.UserCipherKeys{
CipherKeys: entities.UserCipherKeys{
AlphaKey: security.ByteArrToUint64Arr(alphaBytes),
SetKey: security.ByteArrToUint64Arr(setBytes),
},
Interface: models.UserInterface{},
Interface: entities.UserInterface{},
Renew: false,
}
err = user.RenewKeys(setXor, attrXor)
@@ -255,7 +256,7 @@ WHERE id = ?;
return d.addWriteTx(renewQuery, renewArgs)
}
func (d *SqliteDB) RefreshUserPasscode(user models.User, passcodeIdx []int, customerAttr models.CustomerAttributes) error {
func (d *SqliteDB) RefreshUserPasscode(user entities.User, passcodeIdx []int, customerAttr entities.CustomerAttributes) error {
err := user.RefreshPasscode(passcodeIdx, customerAttr)
if err != nil {
return err
@@ -276,7 +277,7 @@ WHERE id = ?;
args := []any{user.RefreshToken, 0, user.EncipheredPasscode.Code, user.EncipheredPasscode.Mask, security.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), security.Uint64ArrToByteArr(user.CipherKeys.SetKey), security.Uint64ArrToByteArr(user.CipherKeys.PassKey), security.Uint64ArrToByteArr(user.CipherKeys.MaskKey), user.CipherKeys.Salt, uuid.UUID(user.Id).String()}
return d.addWriteTx(query, args)
}
func (d *SqliteDB) GetCustomer(id models.CustomerId) (*models.Customer, error) {
func (d *SqliteDB) GetCustomer(id models.CustomerId) (*entities.Customer, error) {
tx, err := d.db.Begin()
if err != nil {
return nil, err
@@ -324,7 +325,7 @@ WHERE id = ?
if err != nil {
return nil, err
}
customer := models.Customer{
customer := entities.Customer{
Id: id,
NKodePolicy: models.NKodePolicy{
MaxNkodeLen: maxNKodeLen,
@@ -334,7 +335,7 @@ WHERE id = ?
LockOut: lockOut,
Expiration: expiration,
},
Attributes: models.NewCustomerAttributesFromBytes(attributeValues, setValues),
Attributes: entities.NewCustomerAttributesFromBytes(attributeValues, setValues),
}
if err = tx.Commit(); err != nil {
return nil, err
@@ -342,7 +343,7 @@ WHERE id = ?
return &customer, nil
}
func (d *SqliteDB) GetUser(email models.UserEmail, customerId models.CustomerId) (*models.User, error) {
func (d *SqliteDB) GetUser(email models.UserEmail, customerId models.CustomerId) (*entities.User, error) {
tx, err := d.db.Begin()
if err != nil {
return nil, err
@@ -401,7 +402,7 @@ WHERE user.email = ? AND user.customer_id = ?
renew = true
}
user := models.User{
user := entities.User{
Id: models.UserId(userId),
CustomerId: customerId,
Email: email,
@@ -409,11 +410,11 @@ WHERE user.email = ? AND user.customer_id = ?
Code: code,
Mask: mask,
},
Kp: models.KeypadDimension{
Kp: entities.KeypadDimension{
AttrsPerKey: attrsPerKey,
NumbOfKeys: numbOfKeys,
},
CipherKeys: models.UserCipherKeys{
CipherKeys: entities.UserCipherKeys{
AlphaKey: security.ByteArrToUint64Arr(alphaKey),
SetKey: security.ByteArrToUint64Arr(setKey),
PassKey: security.ByteArrToUint64Arr(passKey),
@@ -422,7 +423,7 @@ WHERE user.email = ? AND user.customer_id = ?
MaxNKodeLen: maxNKodeLen,
Kp: nil,
},
Interface: models.UserInterface{
Interface: entities.UserInterface{
IdxInterface: security.ByteArrToIntArr(idxInterface),
SvgId: security.ByteArrToIntArr(svgIdInterface),
Kp: nil,
@@ -438,7 +439,7 @@ WHERE user.email = ? AND user.customer_id = ?
return &user, nil
}
func (d *SqliteDB) RandomSvgInterface(kp models.KeypadDimension) ([]string, error) {
func (d *SqliteDB) RandomSvgInterface(kp entities.KeypadDimension) ([]string, error) {
ids, err := d.getRandomIds(kp.TotalAttrs())
if err != nil {
return nil, err
@@ -446,7 +447,7 @@ func (d *SqliteDB) RandomSvgInterface(kp models.KeypadDimension) ([]string, erro
return d.getSvgsById(ids)
}
func (d *SqliteDB) RandomSvgIdxInterface(kp models.KeypadDimension) (models.SvgIdInterface, error) {
func (d *SqliteDB) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) {
return d.getRandomIds(kp.TotalAttrs())
}

View File

@@ -2,7 +2,7 @@ package db
import (
"github.com/stretchr/testify/assert"
"go-nkode/internal/api"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"os"
"testing"
@@ -24,9 +24,9 @@ func TestNewSqliteDB(t *testing.T) {
// }
}
func testSignupLoginRenew(t *testing.T, db api.DbAccessor) {
func testSignupLoginRenew(t *testing.T, db CustomerUserRepository) {
nkodePolicy := models.NewDefaultNKodePolicy()
customerOrig, err := models.NewCustomer(nkodePolicy)
customerOrig, err := entities.NewCustomer(nkodePolicy)
assert.NoError(t, err)
err = db.WriteNewCustomer(*customerOrig)
assert.NoError(t, err)
@@ -34,12 +34,12 @@ func testSignupLoginRenew(t *testing.T, db api.DbAccessor) {
assert.NoError(t, err)
assert.Equal(t, customerOrig, customer)
username := "test_user@example.com"
kp := models.KeypadDefault
kp := entities.KeypadDefault
passcodeIdx := []int{0, 1, 2, 3}
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
ui, err := models.NewUserInterface(&kp, mockSvgInterface)
ui, err := entities.NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
userOrig, err := models.NewUser(*customer, username, passcodeIdx, *ui, kp)
userOrig, err := entities.NewUser(*customer, username, passcodeIdx, *ui, kp)
assert.NoError(t, err)
err = db.WriteNewUser(*userOrig)
assert.NoError(t, err)
@@ -52,8 +52,8 @@ func testSignupLoginRenew(t *testing.T, db api.DbAccessor) {
}
func testSqliteDBRandomSvgInterface(t *testing.T, db api.DbAccessor) {
kp := models.KeypadMax
func testSqliteDBRandomSvgInterface(t *testing.T, db CustomerUserRepository) {
kp := entities.KeypadMax
svgs, err := db.RandomSvgInterface(kp)
assert.NoError(t, err)
assert.Len(t, svgs, kp.TotalAttrs())

View File

@@ -14,7 +14,7 @@ import (
"time"
)
type EmailClient interface {
type Client interface {
SendEmail(Email) error
}
@@ -103,22 +103,22 @@ func (s *SESClient) SendEmail(email Email) error {
return nil
}
// EmailQueue represents the email queue with rate limiting
type EmailQueue struct {
// Queue represents the email queue with rate limiting
type Queue struct {
stop bool
emailQueue chan Email // Email queue
rateLimit <-chan time.Time // Rate limiter
client EmailClient // SES client to send emails
client Client // SES client to send emails
wg sync.WaitGroup // To wait for all emails to be processed
FailedSendCount int
}
// NewEmailQueue creates a new rate-limited email queue
func NewEmailQueue(bufferSize int, emailsPerSecond int, client EmailClient) *EmailQueue {
func NewEmailQueue(bufferSize int, emailsPerSecond int, client Client) *Queue {
// Create a ticker that ticks every second to limit the rate of sending emails
rateLimit := time.Tick(time.Second / time.Duration(emailsPerSecond))
return &EmailQueue{
return &Queue{
stop: false,
emailQueue: make(chan Email, bufferSize),
rateLimit: rateLimit,
@@ -128,7 +128,7 @@ func NewEmailQueue(bufferSize int, emailsPerSecond int, client EmailClient) *Ema
}
// AddEmail queues a new email to be sent
func (q *EmailQueue) AddEmail(email Email) {
func (q *Queue) AddEmail(email Email) {
if q.stop {
log.Printf("email %s with subject %s not add. Stopping queue", email.Recipient, email.Subject)
return
@@ -138,7 +138,7 @@ func (q *EmailQueue) AddEmail(email Email) {
}
// Start begins processing the email queue with rate limiting
func (q *EmailQueue) Start() {
func (q *Queue) Start() {
q.stop = false
// Worker goroutine that processes emails from the queue
go func() {
@@ -151,7 +151,7 @@ func (q *EmailQueue) Start() {
}
// sendEmail sends an email using the SES client
func (q *EmailQueue) sendEmail(email Email) {
func (q *Queue) sendEmail(email Email) {
if err := q.client.SendEmail(email); err != nil {
q.FailedSendCount += 1
log.Printf("Failed to send email to %s: %v\n", email.Recipient, err)
@@ -159,7 +159,7 @@ func (q *EmailQueue) sendEmail(email Email) {
}
// Stop stops the queue after all emails have been processed
func (q *EmailQueue) Stop() {
func (q *Queue) Stop() {
q.stop = true
// Wait for all emails to be processed
q.wg.Wait()

View File

@@ -1,25 +1,26 @@
package models
package entities
import (
"github.com/google/uuid"
"go-nkode/config"
"go-nkode/internal/models"
"go-nkode/internal/security"
"go-nkode/internal/utils"
)
type Customer struct {
Id CustomerId
NKodePolicy NKodePolicy
Id models.CustomerId
NKodePolicy models.NKodePolicy
Attributes CustomerAttributes
}
func NewCustomer(nkodePolicy NKodePolicy) (*Customer, error) {
func NewCustomer(nkodePolicy models.NKodePolicy) (*Customer, error) {
customerAttrs, err := NewCustomerAttributes()
if err != nil {
return nil, err
}
customer := Customer{
Id: CustomerId(uuid.New()),
Id: models.CustomerId(uuid.New()),
NKodePolicy: nkodePolicy,
Attributes: *customerAttrs,
}

View File

@@ -1,4 +1,4 @@
package models
package entities
import (
"go-nkode/internal/security"

View File

@@ -1,7 +1,8 @@
package models
package entities
import (
"github.com/stretchr/testify/assert"
"go-nkode/internal/models"
"testing"
)
@@ -18,10 +19,10 @@ func testNewCustomerAttributes(t *testing.T) {
func testCustomerValidKeyEntry(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 9}
nkodePolicy := NewDefaultNKodePolicy()
nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
userEmail := "testing@example.com"
@@ -42,10 +43,10 @@ func testCustomerValidKeyEntry(t *testing.T) {
func testCustomerIsValidNKode(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := NewDefaultNKodePolicy()
nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
userEmail := "testing123@example.com"

View File

@@ -1,4 +1,4 @@
package models
package entities
import (
"go-nkode/config"

View File

@@ -1,4 +1,4 @@
package models
package entities
import (
"errors"

View File

@@ -1,17 +1,18 @@
package models
package entities
import (
"github.com/google/uuid"
"go-nkode/config"
"go-nkode/internal/models"
"go-nkode/internal/security"
"log"
)
type User struct {
Id UserId
CustomerId CustomerId
Email UserEmail
EncipheredPasscode EncipheredNKode
Id models.UserId
CustomerId models.CustomerId
Email models.UserEmail
EncipheredPasscode models.EncipheredNKode
Kp KeypadDimension
CipherKeys UserCipherKeys
Interface UserInterface
@@ -116,7 +117,7 @@ func ValidKeyEntry(user User, customer Customer, selectedKeys []int) ([]int, err
}
func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInterface, kp KeypadDimension) (*User, error) {
_, err := ParseEmail(userEmail)
_, err := models.ParseEmail(userEmail)
if err != nil {
return nil, err
}
@@ -133,8 +134,8 @@ func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInte
return nil, err
}
newUser := User{
Id: UserId(uuid.New()),
Email: UserEmail(userEmail),
Id: models.UserId(uuid.New()),
Email: models.UserEmail(userEmail),
EncipheredPasscode: *encipheredNKode,
CipherKeys: *newKeys,
Interface: ui,

View File

@@ -1,9 +1,10 @@
package models
package entities
import (
"crypto/sha256"
"errors"
"go-nkode/config"
"go-nkode/internal/models"
"go-nkode/internal/security"
"golang.org/x/crypto/bcrypt"
)
@@ -166,7 +167,7 @@ func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen
return passcodeSet, nil
}
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*EncipheredNKode, error) {
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*models.EncipheredNKode, error) {
attrVals, err := customerAttrs.AttrValsForKp(*u.Kp)
code, err := u.EncipherSaltHashCode(passcodeAttrIdx, attrVals)
if err != nil {
@@ -185,7 +186,7 @@ func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs Cust
if err != nil {
return nil, err
}
encipheredCode := EncipheredNKode{
encipheredCode := models.EncipheredNKode{
Code: code,
Mask: mask,
}

View File

@@ -1,19 +1,20 @@
package models
package entities
import (
"go-nkode/config"
"go-nkode/internal/models"
"go-nkode/internal/security"
"go-nkode/internal/utils"
"log"
)
type UserInterface struct {
IdxInterface IdxInterface
SvgId SvgIdInterface
IdxInterface models.IdxInterface
SvgId models.SvgIdInterface
Kp *KeypadDimension
}
func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) {
func NewUserInterface(kp *KeypadDimension, svgId models.SvgIdInterface) (*UserInterface, error) {
idxInterface := security.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{
IdxInterface: idxInterface,

View File

@@ -1,8 +1,9 @@
package models
package entities
import (
"github.com/google/uuid"
"go-nkode/config"
"go-nkode/internal/models"
"go-nkode/internal/security"
py "go-nkode/internal/utils"
"log"
@@ -10,20 +11,20 @@ import (
)
type UserSignSession struct {
Id SessionId
CustomerId CustomerId
Id models.SessionId
CustomerId models.CustomerId
LoginUserInterface UserInterface
Kp KeypadDimension
SetIdxInterface IdxInterface
ConfirmIdxInterface IdxInterface
SetKeySelection KeySelection
UserEmail UserEmail
SetIdxInterface models.IdxInterface
ConfirmIdxInterface models.IdxInterface
SetKeySelection models.KeySelection
UserEmail models.UserEmail
Reset bool
Expire int
Colors []RGBColor
Colors []models.RGBColor
}
func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) {
func NewSignupResetSession(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerId, svgInterface models.SvgIdInterface, reset bool) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(&kp, svgInterface)
if err != nil {
return nil, err
@@ -33,7 +34,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
return nil, err
}
session := UserSignSession{
Id: SessionId(uuid.New()),
Id: models.SessionId(uuid.New()),
CustomerId: customerId,
LoginUserInterface: *loginInterface,
SetIdxInterface: signupInterface.IdxInterface,
@@ -48,7 +49,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
return &session, nil
}
func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) {
func (s *UserSignSession) DeducePasscode(confirmKeyEntry models.KeySelection) ([]int, error) {
validEntry := py.All[int](confirmKeyEntry, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
@@ -109,7 +110,7 @@ func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, e
return passcode, nil
}
func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) {
func (s *UserSignSession) SetUserNKode(keySelection models.KeySelection) (models.IdxInterface, error) {
validKeySelection := py.All[int](keySelection, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys
})
@@ -129,7 +130,7 @@ func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface,
return s.ConfirmIdxInterface, nil
}
func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInterface []int) ([][]int, error) {
func (s *UserSignSession) getSelectedKeyVals(keySelections models.KeySelection, userInterface []int) ([][]int, error) {
signupKp := s.SignupKeypad()
keypadInterface, err := security.ListToMatrix(userInterface, signupKp.AttrsPerKey)
if err != nil {
@@ -143,7 +144,7 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInt
return keyVals, nil
}
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []RGBColor, error) {
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []models.RGBColor, error) {
// This method randomly drops sets from the base user interface so it is a square and dispersable matrix
if kp.IsDispersable() {
return nil, nil, config.ErrKeypadIsNotDispersible
@@ -170,11 +171,11 @@ func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*User
setIdxs = setIdxs[:kp.NumbOfKeys]
sort.Ints(setIdxs)
selectedSets := make([][]int, kp.NumbOfKeys)
selectedColors := make([]RGBColor, kp.NumbOfKeys)
selectedColors := make([]models.RGBColor, kp.NumbOfKeys)
for idx, setIdx := range setIdxs {
selectedSets[idx] = attrSetView[setIdx]
selectedColors[idx] = SetColors[setIdx]
selectedColors[idx] = models.SetColors[setIdx]
}
// convert set view back into key view
selectedSets, err = security.MatrixTranspose(selectedSets)

View File

@@ -1,7 +1,8 @@
package models
package entities
import (
"github.com/stretchr/testify/assert"
"go-nkode/internal/models"
py "go-nkode/internal/utils"
"testing"
)
@@ -64,7 +65,7 @@ func TestUserInterface_RandomShuffle(t *testing.T) {
AttrsPerKey: 10,
NumbOfKeys: 8,
}
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
userInterfaceCopy := make([]int, len(userInterface.IdxInterface))
@@ -87,7 +88,7 @@ func TestUserInterface_DisperseInterface(t *testing.T) {
for idx := 0; idx < 10000; idx++ {
kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10}
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
preDispersion, err := userInterface.AttributeAdjacencyGraph()
@@ -106,7 +107,7 @@ func TestUserInterface_DisperseInterface(t *testing.T) {
func TestUserInterface_PartialInterfaceShuffle(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10}
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err)
preShuffle := userInterface.IdxInterface