add color to svg

This commit is contained in:
2024-10-19 16:36:47 -05:00
parent 9c33a61570
commit aebd25dc16
16 changed files with 318 additions and 142 deletions

View File

@@ -26,8 +26,8 @@ if [ "$LOCAL_DB" = true ]; then
DB_PATH="/Users/donov/databases/nkode.db" DB_PATH="/Users/donov/databases/nkode.db"
BACKUP_DIR="/var/tmp" BACKUP_DIR="/var/tmp"
else else
DB_PATH="//remote/path/to/db" DB_PATH="/home/dkelly/databases/nkode.db"
BACKUP_DIR="/remote/path/to/backup/dir" BACKUP_DIR="/var/tmp"
fi fi
BACKUP_NAME="backup_nkode_$(date +'%Y%m%d%H%M%S').tar.gz" BACKUP_NAME="backup_nkode_$(date +'%Y%m%d%H%M%S').tar.gz"

View File

@@ -16,10 +16,10 @@ var (
ErrInvalidKeypadDimensions = errors.New("keypad dimensions out of range") ErrInvalidKeypadDimensions = errors.New("keypad dimensions out of range")
ErrUserAlreadyExists = errors.New("user already exists") ErrUserAlreadyExists = errors.New("user already exists")
ErrSignupSessionDNE = errors.New("signup session does not exist") ErrSignupSessionDNE = errors.New("signup session does not exist")
ErrUserForCustomerDNE = errors.New("user for customer does not exist") ErrUserForCustomerDNE = errors.New("user does not exist")
ErrRefreshTokenInvalid = errors.New("refresh token invalid") ErrRefreshTokenInvalid = errors.New("refresh token invalid")
ErrCustomerDne = errors.New("customer dne") ErrCustomerDne = errors.New("customer does not exist")
ErrSvgDne = errors.New("svg dne") ErrSvgDne = errors.New("svg ")
ErrStoppingDatabase = errors.New("stopping database") ErrStoppingDatabase = errors.New("stopping database")
ErrSqliteTx = errors.New("sqlite begin, exec, query, or commit error. see logs") ErrSqliteTx = errors.New("sqlite begin, exec, query, or commit error. see logs")
ErrEmptySvgTable = errors.New("empty svg_icon table") ErrEmptySvgTable = errors.New("empty svg_icon table")
@@ -31,6 +31,8 @@ var (
ErrIncompleteUserSignupSession = errors.New("incomplete user signup session") ErrIncompleteUserSignupSession = errors.New("incomplete user signup session")
ErrSetConfirmSignupMismatch = errors.New("set and confirm nkode are not the same") ErrSetConfirmSignupMismatch = errors.New("set and confirm nkode are not the same")
ErrKeypadIsNotDispersible = errors.New("keypad is not dispersible") ErrKeypadIsNotDispersible = errors.New("keypad is not dispersible")
ErrInvalidNKode = errors.New("invalid nKode")
ErrStringIsNotAnSVG = errors.New("string is not an svg")
) )
var HttpErrMap = map[error]int{ var HttpErrMap = map[error]int{
@@ -59,4 +61,25 @@ var HttpErrMap = map[error]int{
ErrIncompleteUserSignupSession: http.StatusBadRequest, ErrIncompleteUserSignupSession: http.StatusBadRequest,
ErrSetConfirmSignupMismatch: http.StatusBadRequest, ErrSetConfirmSignupMismatch: http.StatusBadRequest,
ErrKeypadIsNotDispersible: http.StatusInternalServerError, ErrKeypadIsNotDispersible: http.StatusInternalServerError,
ErrInvalidNKode: http.StatusBadRequest,
ErrStringIsNotAnSVG: http.StatusInternalServerError,
}
var SetColors = []RGBColor{
{0, 0, 0}, // Black
{255, 0, 0}, // Red
{0, 128, 0}, // Dark Green
{0, 0, 255}, // Blue
{244, 200, 60}, // Yellow
{255, 0, 255}, // Magenta
{0, 200, 200}, // Cyan
{127, 0, 127}, // Purple
{232, 92, 13}, // Orange
{0, 127, 127}, // Teal
{127, 127, 0}, // Olive
{127, 0, 0}, // Dark Red
{128, 128, 128}, // Gray
{228, 102, 102}, // Dark Purple
{185, 17, 240}, // Salmon
{16, 200, 100}, // Green
} }

View File

@@ -63,6 +63,7 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail UserEmail, customerId
UserIdxInterface: signupSession.SetIdxInterface, UserIdxInterface: signupSession.SetIdxInterface,
SvgInterface: svgInterface, SvgInterface: svgInterface,
SessionId: uuid.UUID(signupSession.Id).String(), SessionId: uuid.UUID(signupSession.Id).String(),
Colors: signupSession.Colors,
} }
return &resp, nil return &resp, nil
} }
@@ -143,6 +144,7 @@ func (n *NKodeAPI) GetLoginInterface(userEmail UserEmail, customerId CustomerId)
SvgInterface: svgInterface, SvgInterface: svgInterface,
NumbOfKeys: user.Kp.NumbOfKeys, NumbOfKeys: user.Kp.NumbOfKeys,
AttrsPerKey: user.Kp.AttrsPerKey, AttrsPerKey: user.Kp.AttrsPerKey,
Colors: SetColors,
} }
return &resp, nil return &resp, nil
} }
@@ -190,10 +192,6 @@ func (n *NKodeAPI) RandomSvgInterface() ([]string, error) {
return n.Db.RandomSvgInterface(KeypadMax) return n.Db.RandomSvgInterface(KeypadMax)
} }
func (n *NKodeAPI) GetSvgStringInterface(svgId SvgIdInterface) ([]string, error) {
return n.Db.GetSvgStringInterface(svgId)
}
func (n *NKodeAPI) RefreshToken(userEmail UserEmail, customerId CustomerId, refreshToken string) (string, error) { func (n *NKodeAPI) RefreshToken(userEmail UserEmail, customerId CustomerId, refreshToken string) (string, error) {
user, err := n.Db.GetUser(userEmail, customerId) user, err := n.Db.GetUser(userEmail, customerId)
if err != nil { if err != nil {
@@ -244,3 +242,11 @@ func (n *NKodeAPI) ResetNKode(userEmail UserEmail, customerId CustomerId) error
n.EmailQueue.AddEmail(email) n.EmailQueue.AddEmail(email)
return nil return nil
} }
func getColors(colorIds []int) []RGBColor {
colors := make([]RGBColor, len(colorIds))
for idx, colorIdx := range colorIds {
colors[idx] = SetColors[colorIdx]
}
return colors
}

View File

@@ -27,9 +27,10 @@ const (
) )
const ( const (
malformedCustomerId = "malformed customer id" malformedCustomerId = "malformed customer id"
malformedUserEmail = "malformed user email" malformedUserEmail = "malformed user email"
malformedSessionId = "malformed session id" malformedSessionId = "malformed session id"
invalidKeypadDimensions = "invalid keypad dimensions"
) )
func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -99,7 +100,7 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter
NumbOfKeys: signupResetPost.NumbOfKeys, NumbOfKeys: signupResetPost.NumbOfKeys,
} }
if err := kp.IsValidKeypadDimension(); err != nil { if err := kp.IsValidKeypadDimension(); err != nil {
badRequest(w, "invalid keypad dimensions") badRequest(w, invalidKeypadDimensions)
return return
} }
customerId, err := uuid.Parse(signupResetPost.CustomerId) customerId, err := uuid.Parse(signupResetPost.CustomerId)
@@ -179,7 +180,7 @@ func (h *NKodeHandler) ConfirmNKodeHandler(w http.ResponseWriter, r *http.Reques
} }
func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.Request) { func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.Request) {
log.Print("get login interface")
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
methodNotAllowed(w) methodNotAllowed(w)
return return
@@ -207,6 +208,7 @@ func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.R
} }
func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
log.Println("login")
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
methodNotAllowed(w) methodNotAllowed(w)
return return
@@ -257,6 +259,7 @@ func (h *NKodeHandler) RenewAttributesHandler(w http.ResponseWriter, r *http.Req
} }
func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.Request) { func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.Request) {
log.Println("random svg interface")
if r.Method != http.MethodGet { if r.Method != http.MethodGet {
methodNotAllowed(w) methodNotAllowed(w)
} }
@@ -265,7 +268,12 @@ func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.
handleError(w, err) handleError(w, err)
return return
} }
respBody := RandomSvgInterfaceResp{Svgs: svgs}
respBody := RandomSvgInterfaceResp{
Svgs: svgs,
Colors: SetColors,
}
marshalAndWriteBytes(w, respBody) marshalAndWriteBytes(w, respBody)
} }

View File

@@ -17,7 +17,7 @@ type Icon struct {
Width *int `json:"width,omitempty"` Width *int `json:"width,omitempty"`
} }
// Define the Root struct to represent the entire JSON structure // Root Define the Root struct to represent the entire JSON structure
type Root struct { type Root struct {
Prefix string `json:"prefix"` Prefix string `json:"prefix"`
Icons map[string]Icon `json:"icons"` Icons map[string]Icon `json:"icons"`
@@ -28,6 +28,9 @@ func main() {
testDbPath := os.Getenv("TEST_DB_PATH") testDbPath := os.Getenv("TEST_DB_PATH")
dbPath := os.Getenv("DB_PATH") dbPath := os.Getenv("DB_PATH")
dbPaths := []string{testDbPath, dbPath} dbPaths := []string{testDbPath, dbPath}
//dbPath := "/Users/donov/Desktop/nkode.db"
//dbPaths := []string{dbPath}
outputStr := MakeSvgFiles() outputStr := MakeSvgFiles()
for _, path := range dbPaths { for _, path := range dbPaths {
MakeTables(path) MakeTables(path)
@@ -152,59 +155,58 @@ PRAGMA journal_mode=WAL;
--PRAGMA cache_size = -16000; -- Increase cache size (16MB)PRAGMA --PRAGMA cache_size = -16000; -- Increase cache size (16MB)PRAGMA
CREATE TABLE IF NOT EXISTS customer ( CREATE TABLE IF NOT EXISTS customer (
id TEXT NOT NULL PRIMARY KEY, id TEXT NOT NULL PRIMARY KEY
max_nkode_len INTEGER NOT NULL, ,max_nkode_len INTEGER NOT NULL
min_nkode_len INTEGER NOT NULL, ,min_nkode_len INTEGER NOT NULL
distinct_sets INTEGER NOT NULL, ,distinct_sets INTEGER NOT NULL
distinct_attributes INTEGER NOT NULL, ,distinct_attributes INTEGER NOT NULL
lock_out INTEGER NOT NULL, ,lock_out INTEGER NOT NULL
expiration INTEGER NOT NULL, ,expiration INTEGER NOT NULL
attribute_values BLOB NOT NULL, ,attribute_values BLOB NOT NULL
set_values BLOB NOT NULL ,set_values BLOB NOT NULL
-- created_at TEXT NOT NULL, ,last_renew TEXT NOT NULL
-- last_renew TEXT NOT NULL, ,created_at TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS user ( CREATE TABLE IF NOT EXISTS user (
id TEXT NOT NULL PRIMARY KEY, id TEXT NOT NULL PRIMARY KEY
username TEXT NOT NULL, ,email TEXT NOT NULL
-- email TEXT NOT NULL, -- first_name TEXT NOT NULL
-- first_name TEXT NOT NULL, -- last_name TEXT NOT NULL
-- last_name TEXT NOT NULL, ,renew INT NOT NULL
renew INT NOT NULL, ,refresh_token TEXT
refresh_token TEXT, ,customer_id TEXT NOT NULL
customer_id TEXT NOT NULL,
-- Enciphered Passcode -- Enciphered Passcode
code TEXT NOT NULL, ,code TEXT NOT NULL
mask TEXT NOT NULL, ,mask TEXT NOT NULL
-- Keypad Dimensions -- Keypad Dimensions
attributes_per_key INT NOT NULL, ,attributes_per_key INT NOT NULL
number_of_keys INT NOT NULL, ,number_of_keys INT NOT NULL
-- User Keys -- User Keys
alpha_key BLOB NOT NULL, ,alpha_key BLOB NOT NULL
set_key BLOB NOT NULL, ,set_key BLOB NOT NULL
pass_key BLOB NOT NULL, ,pass_key BLOB NOT NULL
mask_key BLOB NOT NULL, ,mask_key BLOB NOT NULL
salt BLOB NOT NULL, ,salt BLOB NOT NULL
max_nkode_len INT NOT NULL, ,max_nkode_len INT NOT NULL
-- User Interface -- User Interface
idx_interface BLOB NOT NULL, ,idx_interface BLOB NOT NULL
svg_id_interface BLOB NOT NULL, ,svg_id_interface BLOB NOT NULL
-- created_at TEXT NOT NULL, ,last_login TEXT NULL
-- last_login TEXT NOT NULL, ,created_at TEXT
FOREIGN KEY (customer_id) REFERENCES customers(id), ,FOREIGN KEY (customer_id) REFERENCES customer(id)
UNIQUE(customer_id, username) ,UNIQUE(customer_id, email)
); );
CREATE TABLE IF NOT EXISTS svg_icon ( CREATE TABLE IF NOT EXISTS svg_icon (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT
svg TEXT NOT NULL ,svg TEXT NOT NULL
); );
` `
_, err = db.Exec(createTable) _, err = db.Exec(createTable)

View File

@@ -8,6 +8,7 @@ import (
"go-nkode/util" "go-nkode/util"
"log" "log"
"sync" "sync"
"time"
) )
type SqliteDB struct { type SqliteDB struct {
@@ -59,17 +60,52 @@ func (d *SqliteDB) CloseDb() {
func (d *SqliteDB) WriteNewCustomer(c Customer) error { func (d *SqliteDB) WriteNewCustomer(c Customer) error {
query := ` query := `
INSERT INTO customer (id, max_nkode_len, min_nkode_len, distinct_sets, distinct_attributes, lock_out, expiration, attribute_values, set_values) INSERT INTO customer (
VALUES (?,?,?,?,?,?,?,?,?) id
,max_nkode_len
,min_nkode_len
,distinct_sets
,distinct_attributes
,lock_out
,expiration
,attribute_values
,set_values
,last_renew
,created_at
)
VALUES (?,?,?,?,?,?,?,?,?,?,?)
` `
args := []any{uuid.UUID(c.Id), c.NKodePolicy.MaxNkodeLen, c.NKodePolicy.MinNkodeLen, c.NKodePolicy.DistinctSets, c.NKodePolicy.DistinctAttributes, c.NKodePolicy.LockOut, c.NKodePolicy.Expiration, c.Attributes.AttrBytes(), c.Attributes.SetBytes()} args := []any{
uuid.UUID(c.Id), c.NKodePolicy.MaxNkodeLen, c.NKodePolicy.MinNkodeLen, c.NKodePolicy.DistinctSets,
c.NKodePolicy.DistinctAttributes, c.NKodePolicy.LockOut, c.NKodePolicy.Expiration,
c.Attributes.AttrBytes(), c.Attributes.SetBytes(), timeStamp(), timeStamp(),
}
return d.addWriteTx(query, args) return d.addWriteTx(query, args)
} }
func (d *SqliteDB) WriteNewUser(u User) error { func (d *SqliteDB) WriteNewUser(u User) error {
query := ` query := `
INSERT INTO user (id, username, renew, refresh_token, customer_id, 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) INSERT INTO user (
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) id
,email
,renew
,refresh_token
,customer_id
,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
,created_at
)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
` `
var renew int var renew int
if u.Renew { if u.Renew {
@@ -78,7 +114,14 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
renew = 0 renew = 0
} }
args := []any{uuid.UUID(u.Id), u.Email, renew, u.RefreshToken, uuid.UUID(u.CustomerId), u.EncipheredPasscode.Code, u.EncipheredPasscode.Mask, u.Kp.AttrsPerKey, u.Kp.NumbOfKeys, util.Uint64ArrToByteArr(u.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(u.CipherKeys.SetKey), util.Uint64ArrToByteArr(u.CipherKeys.PassKey), util.Uint64ArrToByteArr(u.CipherKeys.MaskKey), u.CipherKeys.Salt, u.CipherKeys.MaxNKodeLen, util.IntArrToByteArr(u.Interface.IdxInterface), util.IntArrToByteArr(u.Interface.SvgId)} args := []any{
uuid.UUID(u.Id), u.Email, renew, u.RefreshToken, uuid.UUID(u.CustomerId),
u.EncipheredPasscode.Code, u.EncipheredPasscode.Mask, u.Kp.AttrsPerKey, u.Kp.NumbOfKeys,
util.Uint64ArrToByteArr(u.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(u.CipherKeys.SetKey),
util.Uint64ArrToByteArr(u.CipherKeys.PassKey), util.Uint64ArrToByteArr(u.CipherKeys.MaskKey),
u.CipherKeys.Salt, u.CipherKeys.MaxNKodeLen, util.IntArrToByteArr(u.Interface.IdxInterface),
util.IntArrToByteArr(u.Interface.SvgId), timeStamp(),
}
return d.addWriteTx(query, args) return d.addWriteTx(query, args)
} }
@@ -86,8 +129,21 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
func (d *SqliteDB) UpdateUserNKode(u User) error { func (d *SqliteDB) UpdateUserNKode(u User) error {
query := ` query := `
UPDATE user UPDATE user
SET renew = ?, refresh_token = ?, 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 = ? SET renew = ?
WHERE username = ? AND customer_id = ? ,refresh_token = ?
,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 = ?
WHERE email = ? AND customer_id = ?
` `
var renew int var renew int
if u.Renew { if u.Renew {
@@ -102,9 +158,9 @@ WHERE username = ? AND customer_id = ?
func (d *SqliteDB) UpdateUserInterface(id UserId, ui UserInterface) error { func (d *SqliteDB) UpdateUserInterface(id UserId, ui UserInterface) error {
query := ` query := `
UPDATE user SET idx_interface = ? WHERE id = ? UPDATE user SET idx_interface = ?, last_login = ? WHERE id = ?
` `
args := []any{util.IntArrToByteArr(ui.IdxInterface), uuid.UUID(id).String()} args := []any{util.IntArrToByteArr(ui.IdxInterface), timeStamp(), uuid.UUID(id).String()}
return d.addWriteTx(query, args) return d.addWriteTx(query, args)
} }
@@ -131,11 +187,20 @@ func (d *SqliteDB) Renew(id CustomerId) error {
renewArgs := []any{util.Uint64ArrToByteArr(customer.Attributes.AttrVals), util.Uint64ArrToByteArr(customer.Attributes.SetVals), uuid.UUID(customer.Id).String()} renewArgs := []any{util.Uint64ArrToByteArr(customer.Attributes.AttrVals), util.Uint64ArrToByteArr(customer.Attributes.SetVals), uuid.UUID(customer.Id).String()}
// TODO: replace with tx // TODO: replace with tx
renewQuery := ` renewQuery := `
UPDATE customer SET attribute_values = ?, set_values = ? WHERE id = ?; UPDATE customer
SET attribute_values = ?, set_values = ?
WHERE id = ?;
` `
userQuery := ` userQuery := `
SELECT id, alpha_key, set_key, attributes_per_key, number_of_keys FROM user WHERE customer_id = ? SELECT
id
,alpha_key
,set_key
,attributes_per_key
,number_of_keys
FROM user
WHERE customer_id = ?
` `
tx, err := d.db.Begin() tx, err := d.db.Begin()
if err != nil { if err != nil {
@@ -172,7 +237,11 @@ SELECT id, alpha_key, set_key, attributes_per_key, number_of_keys FROM user WHER
if err != nil { if err != nil {
return err return err
} }
renewQuery += "\nUPDATE user SET alpha_key = ?, set_key = ?, renew = ? WHERE id = ?;" renewQuery += `
UPDATE user
SET alpha_key = ?, set_key = ?, renew = ?
WHERE id = ?;
`
renewArgs = append(renewArgs, util.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(user.CipherKeys.SetKey), 1, userId) renewArgs = append(renewArgs, util.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(user.CipherKeys.SetKey), 1, userId)
} }
renewQuery += ` renewQuery += `
@@ -190,7 +259,17 @@ func (d *SqliteDB) RefreshUserPasscode(user User, passcodeIdx []int, customerAtt
return err return err
} }
query := ` query := `
UPDATE user SET renew = ?, code = ?, mask = ?, alpha_key = ?, set_key = ?, pass_key = ?, mask_key = ?, salt = ? WHERE id = ?; UPDATE user
SET
renew = ?
,code = ?
,mask = ?
,alpha_key = ?
,set_key = ?
,pass_key = ?
,mask_key = ?
,salt = ?
WHERE id = ?;
` `
args := []any{user.RefreshToken, 0, user.EncipheredPasscode.Code, user.EncipheredPasscode.Mask, util.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(user.CipherKeys.SetKey), util.Uint64ArrToByteArr(user.CipherKeys.PassKey), util.Uint64ArrToByteArr(user.CipherKeys.MaskKey), user.CipherKeys.Salt, uuid.UUID(user.Id).String()} args := []any{user.RefreshToken, 0, user.EncipheredPasscode.Code, user.EncipheredPasscode.Mask, util.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), util.Uint64ArrToByteArr(user.CipherKeys.SetKey), util.Uint64ArrToByteArr(user.CipherKeys.PassKey), util.Uint64ArrToByteArr(user.CipherKeys.MaskKey), user.CipherKeys.Salt, uuid.UUID(user.Id).String()}
return d.addWriteTx(query, args) return d.addWriteTx(query, args)
@@ -208,7 +287,19 @@ 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 = ?` 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 := tx.Query(selectCustomer, uuid.UUID(id)) rows, err := tx.Query(selectCustomer, uuid.UUID(id))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -249,35 +340,52 @@ func (d *SqliteDB) GetCustomer(id CustomerId) (*Customer, error) {
return &customer, nil return &customer, nil
} }
func (d *SqliteDB) GetUser(username UserEmail, customerId CustomerId) (*User, error) { func (d *SqliteDB) GetUser(email UserEmail, customerId CustomerId) (*User, error) {
tx, err := d.db.Begin() tx, err := d.db.Begin()
if err != nil { if err != nil {
return nil, err return nil, err
} }
userSelect := ` userSelect := `
SELECT id, renew, refresh_token, 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 SELECT
WHERE user.username = ? AND user.customer_id = ? id
,renew
,refresh_token
,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.email = ? AND user.customer_id = ?
` `
rows, err := tx.Query(userSelect, string(username), uuid.UUID(customerId).String()) rows, err := tx.Query(userSelect, string(email), uuid.UUID(customerId).String())
if !rows.Next() { if !rows.Next() {
return nil, nil return nil, nil
} }
var id string var (
var renewVal int id string
var refreshToken string renewVal int
var code string refreshToken string
var mask string code string
var attrsPerKey int mask string
var numbOfKeys int attrsPerKey int
var alphaKey []byte numbOfKeys int
var setKey []byte alphaKey []byte
var passKey []byte setKey []byte
var maskKey []byte passKey []byte
var salt []byte maskKey []byte
var maxNKodeLen int salt []byte
var idxInterface []byte maxNKodeLen int
var svgIdInterface []byte idxInterface []byte
svgIdInterface []byte
)
err = rows.Scan(&id, &renewVal, &refreshToken, &code, &mask, &attrsPerKey, &numbOfKeys, &alphaKey, &setKey, &passKey, &maskKey, &salt, &maxNKodeLen, &idxInterface, &svgIdInterface) err = rows.Scan(&id, &renewVal, &refreshToken, &code, &mask, &attrsPerKey, &numbOfKeys, &alphaKey, &setKey, &passKey, &maskKey, &salt, &maxNKodeLen, &idxInterface, &svgIdInterface)
userId, err := uuid.Parse(id) userId, err := uuid.Parse(id)
@@ -294,7 +402,7 @@ WHERE user.username = ? AND user.customer_id = ?
user := User{ user := User{
Id: UserId(userId), Id: UserId(userId),
CustomerId: customerId, CustomerId: customerId,
Email: username, Email: email,
EncipheredPasscode: EncipheredNKode{ EncipheredPasscode: EncipheredNKode{
Code: code, Code: code,
Mask: mask, Mask: mask,
@@ -349,7 +457,11 @@ func (d *SqliteDB) getSvgsById(ids []int) ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
selectId := "SELECT svg FROM svg_icon where id = ?" selectId := `
SELECT svg
FROM svg_icon
WHERE id = ?
`
svgs := make([]string, len(ids)) svgs := make([]string, len(ids))
for idx, id := range ids { for idx, id := range ids {
rows, err := tx.Query(selectId, id) rows, err := tx.Query(selectId, id)
@@ -444,3 +556,7 @@ func (d *SqliteDB) getRandomIds(count int) ([]int, error) {
return perm[:count], nil return perm[:count], nil
} }
func timeStamp() string {
return time.Now().Format(time.RFC3339)
}

View File

@@ -23,8 +23,8 @@ func TestNewSqliteDB(t *testing.T) {
} }
func testSignupLoginRenew(t *testing.T, db DbAccessor) { func testSignupLoginRenew(t *testing.T, db DbAccessor) {
nkode_policy := NewDefaultNKodePolicy() nkodePolicy := NewDefaultNKodePolicy()
customerOrig, err := NewCustomer(nkode_policy) customerOrig, err := NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
err = db.WriteNewCustomer(*customerOrig) err = db.WriteNewCustomer(*customerOrig)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -11,7 +11,8 @@ type SetNKodeResp struct {
} }
type RandomSvgInterfaceResp struct { type RandomSvgInterfaceResp struct {
Svgs []string `json:"svgs"` Svgs []string `json:"svgs"`
Colors []RGBColor `json:"colors"`
} }
type RefreshTokenResp struct { type RefreshTokenResp struct {
@@ -75,6 +76,7 @@ type GenerateSignupResetInterfaceResp struct {
SessionId string `json:"session_id"` SessionId string `json:"session_id"`
UserIdxInterface IdxInterface `json:"user_interface"` UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"` SvgInterface []string `json:"svg_interface"`
Colors []RGBColor `json:"colors"`
} }
type GetLoginInterfaceResp struct { type GetLoginInterfaceResp struct {
@@ -82,6 +84,7 @@ type GetLoginInterfaceResp struct {
SvgInterface []string `json:"svg_interface"` SvgInterface []string `json:"svg_interface"`
AttrsPerKey int `json:"attrs_per_key"` AttrsPerKey int `json:"attrs_per_key"`
NumbOfKeys int `json:"numb_of_keys"` NumbOfKeys int `json:"numb_of_keys"`
Colors []RGBColor `json:"colors"`
} }
type KeySelection []int type KeySelection []int
@@ -123,6 +126,12 @@ type EncipheredNKode struct {
Mask string Mask string
} }
type RGBColor struct {
Red int `json:"red"`
Green int `json:"green"`
Blue int `json:"blue"`
}
type DbAccessor interface { type DbAccessor interface {
GetCustomer(CustomerId) (*Customer, error) GetCustomer(CustomerId) (*Customer, error)
GetUser(UserEmail, CustomerId) (*User, error) GetUser(UserEmail, CustomerId) (*User, error)

View File

@@ -2,6 +2,7 @@ package core
import ( import (
"crypto/sha256" "crypto/sha256"
"errors"
"go-nkode/util" "go-nkode/util"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -64,6 +65,9 @@ func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []
passwordDigest := u.saltAndDigest(passcodeCipher) passwordDigest := u.saltAndDigest(passcodeCipher)
err := bcrypt.CompareHashAndPassword(hashBytes, passwordDigest) err := bcrypt.CompareHashAndPassword(hashBytes, passwordDigest)
if err != nil { if err != nil {
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
return ErrInvalidNKode
}
return err return err
} }
return nil return nil

View File

@@ -14,14 +14,12 @@ type UserInterface struct {
func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) { func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) {
idxInterface := util.IdentityArray(kp.TotalAttrs()) idxInterface := util.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{ userInterface := UserInterface{
IdxInterface: idxInterface, IdxInterface: idxInterface,
SvgId: svgId, SvgId: svgId,
Kp: kp, Kp: kp,
} }
err := userInterface.RandomShuffle() if err := userInterface.RandomShuffle(); err != nil {
if err != nil {
return nil, err return nil, err
} }
return &userInterface, nil return &userInterface, nil

View File

@@ -19,6 +19,7 @@ type UserSignSession struct {
UserEmail UserEmail UserEmail UserEmail
Reset bool Reset bool
Expire int Expire int
Colors []RGBColor
} }
func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) { func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) {
@@ -26,7 +27,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
if err != nil { if err != nil {
return nil, err return nil, err
} }
signupInterface, err := signupInterface(*loginInterface, kp) signupInterface, colors, err := signupInterface(*loginInterface, kp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -40,6 +41,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
UserEmail: userEmail, UserEmail: userEmail,
Kp: kp, Kp: kp,
Reset: reset, Reset: reset,
Colors: colors,
} }
return &session, nil return &session, nil
@@ -140,40 +142,52 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInt
return keyVals, nil return keyVals, nil
} }
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, error) { func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []RGBColor, error) {
// This method randomly drops sets from the base user interface so it is a square and dispersable matrix
if kp.IsDispersable() { if kp.IsDispersable() {
return nil, ErrKeypadIsNotDispersible return nil, nil, ErrKeypadIsNotDispersible
} }
err := baseUserInterface.RandomShuffle() err := baseUserInterface.RandomShuffle()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// attributes are arranged by key interfaceMatrix
interfaceMatrix, err := baseUserInterface.InterfaceMatrix() interfaceMatrix, err := baseUserInterface.InterfaceMatrix()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// attributes are arranged by set
attrSetView, err := util.MatrixTranspose(interfaceMatrix) attrSetView, err := util.MatrixTranspose(interfaceMatrix)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
err = util.FisherYatesShuffle[[]int](&attrSetView)
setIdxs := util.IdentityArray(kp.AttrsPerKey)
if err := util.FisherYatesShuffle[int](&setIdxs); err != nil {
return nil, nil, err
}
setIdxs = setIdxs[:kp.NumbOfKeys]
selectedSets := make([][]int, kp.NumbOfKeys)
selectedColors := make([]RGBColor, kp.NumbOfKeys)
for idx, setIdx := range setIdxs {
selectedSets[idx] = attrSetView[setIdx]
selectedColors[idx] = SetColors[setIdx]
}
// convert set view back into key view
selectedSets, err = util.MatrixTranspose(selectedSets)
if err != nil { if err != nil {
return nil, err return nil, nil, err
}
numbOfKeys := kp.NumbOfKeys
attrSetView = attrSetView[:numbOfKeys]
attrSetView, err = util.MatrixTranspose(attrSetView)
if err != nil {
return nil, err
} }
signupUserInterface := UserInterface{ signupUserInterface := UserInterface{
IdxInterface: util.MatrixToList(attrSetView), IdxInterface: util.MatrixToList(selectedSets),
Kp: &KeypadDimension{ Kp: &KeypadDimension{
AttrsPerKey: numbOfKeys, AttrsPerKey: kp.NumbOfKeys,
NumbOfKeys: numbOfKeys, NumbOfKeys: kp.NumbOfKeys,
}, },
} }
return &signupUserInterface, nil return &signupUserInterface, selectedColors, nil
} }
func (s *UserSignSession) SignupKeypad() KeypadDimension { func (s *UserSignSession) SignupKeypad() KeypadDimension {

View File

@@ -1,22 +1,22 @@
#!/bin/bash #!/bin/bash
# Create a temporary directory to hold the files # Create a temporary directory to hold the files
mkdir -p /tmp/nkodeapi #mkdir -p /tmp/nkodeapi
#
cp -r ./core/* /tmp/nkodeapi/ #cp -r ./core/* /tmp/nkodeapi/
cp -r ./hashset/* /tmp/nkodeapi/ #cp -r ./hashset/* /tmp/nkodeapi/
cp -r ./py-builtin/* /tmp/nkodeapi/ #cp -r ./py-builtin/* /tmp/nkodeapi/
cp -r ./util/* /tmp/nkodeapi/ #cp -r ./util/* /tmp/nkodeapi/
#
cp go.mod /tmp/nkodeapi/ #cp go.mod /tmp/nkodeapi/
cp main.go /tmp/nkodeapi/ #cp main.go /tmp/nkodeapi/
# Disable extended attributes and create the tar file # Disable extended attributes and create the tar file
export COPYFILE_DISABLE=1 export COPYFILE_DISABLE=1
tar -cvf go-nkode.tar -C /tmp nkodeapi tar -cvf go-nkode.tar -C ../ go-nkode
# Clean up the temporary directory after the archive is created
rm -rf /tmp/webapp
scp go-nkode.tar dkelly@api.nkode.tech:/home/dkelly scp go-nkode.tar dkelly@api.nkode.tech:/home/dkelly
rm go-nkode.tar

View File

@@ -44,7 +44,7 @@ func (s *Set[T]) Copy() Set[T] {
} }
func (s *Set[T]) IsDisjoint(otherSet Set[T]) bool { func (s *Set[T]) IsDisjoint(otherSet Set[T]) bool {
for attr, _ := range *s { for attr := range *s {
if otherSet.Contains(attr) { if otherSet.Contains(attr) {
return false return false
} }
@@ -54,7 +54,7 @@ func (s *Set[T]) IsDisjoint(otherSet Set[T]) bool {
func (s *Set[T]) Intersect(otherSet Set[T]) Set[T] { func (s *Set[T]) Intersect(otherSet Set[T]) Set[T] {
intersect := make(Set[T]) intersect := make(Set[T])
for val, _ := range *s { for val := range *s {
if otherSet.Contains(val) { if otherSet.Contains(val) {
intersect.Add(val) intersect.Add(val)
} }

View File

@@ -67,11 +67,11 @@ func AddDefaultCustomer(api core.NKodeAPI) {
log.Fatal(err) log.Fatal(err)
} }
customerId := core.CustomerId(newId) customerId := core.CustomerId(newId)
nkode_policy := core.NewDefaultNKodePolicy() nkodePolicy := core.NewDefaultNKodePolicy()
_, err = api.CreateNewCustomer(nkode_policy, &customerId) _, err = api.CreateNewCustomer(nkodePolicy, &customerId)
if err != nil { if err != nil {
log.Print(err) log.Println(err)
} else { } else {
log.Print("created new customer: ", newId) log.Println("created new customer: ", newId)
} }
} }

View File

@@ -39,8 +39,8 @@ func TestApi(t *testing.T) {
passcodeLen := 4 passcodeLen := 4
setInterface := signupInterfaceResp.UserIdxInterface setInterface := signupInterfaceResp.UserIdxInterface
userPasscode := setInterface[:passcodeLen] userPasscode := setInterface[:passcodeLen]
kp_set := core.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys} kpSet := core.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys}
setKeySelection, err := core.SelectKeyByAttrIdx(setInterface, userPasscode, kp_set) setKeySelection, err := core.SelectKeyByAttrIdx(setInterface, userPasscode, kpSet)
assert.NoError(t, err) assert.NoError(t, err)
setNKodeBody := core.SetNKodePost{ setNKodeBody := core.SetNKodePost{
CustomerId: customerResp.CustomerId, CustomerId: customerResp.CustomerId,
@@ -50,7 +50,7 @@ func TestApi(t *testing.T) {
var setNKodeResp core.SetNKodeResp var setNKodeResp core.SetNKodeResp
testApiPost(t, base+core.SetNKode, setNKodeBody, &setNKodeResp) testApiPost(t, base+core.SetNKode, setNKodeBody, &setNKodeResp)
confirmInterface := setNKodeResp.UserInterface confirmInterface := setNKodeResp.UserInterface
confirmKeySelection, err := core.SelectKeyByAttrIdx(confirmInterface, userPasscode, kp_set) confirmKeySelection, err := core.SelectKeyByAttrIdx(confirmInterface, userPasscode, kpSet)
assert.NoError(t, err) assert.NoError(t, err)
confirmNKodeBody := core.ConfirmNKodePost{ confirmNKodeBody := core.ConfirmNKodePost{
CustomerId: customerResp.CustomerId, CustomerId: customerResp.CustomerId,
@@ -125,7 +125,7 @@ func testApiPost(t *testing.T, endpointStr string, postBody any, respBody any) {
reader := Marshal(t, postBody) reader := Marshal(t, postBody)
resp, err := http.Post(endpointStr, "application/json", reader) resp, err := http.Post(endpointStr, "application/json", reader)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, resp.StatusCode, http.StatusOK) assert.Equal(t, http.StatusOK, resp.StatusCode)
if respBody != nil { if respBody != nil {
Unmarshal(t, resp, respBody) Unmarshal(t, resp, respBody)
} }

View File

@@ -13,10 +13,6 @@ import (
"time" "time"
) )
type ShuffleTypes interface {
[]int | int | []uint64 | uint64
}
var ( var (
ErrFisherYatesShuffle = errors.New("unable to shuffle array") ErrFisherYatesShuffle = errors.New("unable to shuffle array")
ErrRandomBytes = errors.New("random bytes error") ErrRandomBytes = errors.New("random bytes error")
@@ -30,7 +26,7 @@ var (
ErrXorLengthMismatch = errors.New("xor length mismatch") ErrXorLengthMismatch = errors.New("xor length mismatch")
) )
func fisherYatesShuffle[T ShuffleTypes](b *[]T) error { func fisherYatesShuffle[T any](b *[]T) error {
for i := len(*b) - 1; i > 0; i-- { for i := len(*b) - 1; i > 0; i-- {
bigJ, err := rand.Int(rand.Reader, big.NewInt(int64(i+1))) bigJ, err := rand.Int(rand.Reader, big.NewInt(int64(i+1)))
if err != nil { if err != nil {
@@ -43,7 +39,7 @@ func fisherYatesShuffle[T ShuffleTypes](b *[]T) error {
return nil return nil
} }
func FisherYatesShuffle[T ShuffleTypes](b *[]T) error { func FisherYatesShuffle[T any](b *[]T) error {
return fisherYatesShuffle(b) return fisherYatesShuffle(b)
} }