diff --git a/backup_sqlite.sh b/backup_sqlite.sh index d2dff60..f51b84f 100644 --- a/backup_sqlite.sh +++ b/backup_sqlite.sh @@ -26,8 +26,8 @@ if [ "$LOCAL_DB" = true ]; then DB_PATH="/Users/donov/databases/nkode.db" BACKUP_DIR="/var/tmp" else - DB_PATH="//remote/path/to/db" - BACKUP_DIR="/remote/path/to/backup/dir" + DB_PATH="/home/dkelly/databases/nkode.db" + BACKUP_DIR="/var/tmp" fi BACKUP_NAME="backup_nkode_$(date +'%Y%m%d%H%M%S').tar.gz" diff --git a/core/constants.go b/core/constants.go index 4de8ea8..bf65512 100644 --- a/core/constants.go +++ b/core/constants.go @@ -16,10 +16,10 @@ var ( ErrInvalidKeypadDimensions = errors.New("keypad dimensions out of range") ErrUserAlreadyExists = errors.New("user already exists") 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") - ErrCustomerDne = errors.New("customer dne") - ErrSvgDne = errors.New("svg dne") + ErrCustomerDne = errors.New("customer does not exist") + ErrSvgDne = errors.New("svg ") ErrStoppingDatabase = errors.New("stopping database") ErrSqliteTx = errors.New("sqlite begin, exec, query, or commit error. see logs") ErrEmptySvgTable = errors.New("empty svg_icon table") @@ -31,6 +31,8 @@ var ( ErrIncompleteUserSignupSession = errors.New("incomplete user signup session") ErrSetConfirmSignupMismatch = errors.New("set and confirm nkode are not the same") 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{ @@ -59,4 +61,25 @@ var HttpErrMap = map[error]int{ ErrIncompleteUserSignupSession: http.StatusBadRequest, ErrSetConfirmSignupMismatch: http.StatusBadRequest, 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 } diff --git a/core/nkode_api.go b/core/nkode_api.go index 177f725..f43fcf8 100644 --- a/core/nkode_api.go +++ b/core/nkode_api.go @@ -63,6 +63,7 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail UserEmail, customerId UserIdxInterface: signupSession.SetIdxInterface, SvgInterface: svgInterface, SessionId: uuid.UUID(signupSession.Id).String(), + Colors: signupSession.Colors, } return &resp, nil } @@ -143,6 +144,7 @@ func (n *NKodeAPI) GetLoginInterface(userEmail UserEmail, customerId CustomerId) SvgInterface: svgInterface, NumbOfKeys: user.Kp.NumbOfKeys, AttrsPerKey: user.Kp.AttrsPerKey, + Colors: SetColors, } return &resp, nil } @@ -190,10 +192,6 @@ func (n *NKodeAPI) RandomSvgInterface() ([]string, error) { 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) { user, err := n.Db.GetUser(userEmail, customerId) if err != nil { @@ -244,3 +242,11 @@ func (n *NKodeAPI) ResetNKode(userEmail UserEmail, customerId CustomerId) error n.EmailQueue.AddEmail(email) return nil } + +func getColors(colorIds []int) []RGBColor { + colors := make([]RGBColor, len(colorIds)) + for idx, colorIdx := range colorIds { + colors[idx] = SetColors[colorIdx] + } + return colors +} diff --git a/core/nkode_handler.go b/core/nkode_handler.go index 0f42edf..8119d9c 100644 --- a/core/nkode_handler.go +++ b/core/nkode_handler.go @@ -27,9 +27,10 @@ const ( ) const ( - malformedCustomerId = "malformed customer id" - malformedUserEmail = "malformed user email" - malformedSessionId = "malformed session id" + malformedCustomerId = "malformed customer id" + malformedUserEmail = "malformed user email" + malformedSessionId = "malformed session id" + invalidKeypadDimensions = "invalid keypad dimensions" ) func (h *NKodeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -99,7 +100,7 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter NumbOfKeys: signupResetPost.NumbOfKeys, } if err := kp.IsValidKeypadDimension(); err != nil { - badRequest(w, "invalid keypad dimensions") + badRequest(w, invalidKeypadDimensions) return } 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) { - + log.Print("get login interface") if r.Method != http.MethodPost { methodNotAllowed(w) 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) { + log.Println("login") if r.Method != http.MethodPost { methodNotAllowed(w) 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) { + log.Println("random svg interface") if r.Method != http.MethodGet { methodNotAllowed(w) } @@ -265,7 +268,12 @@ func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http. handleError(w, err) return } - respBody := RandomSvgInterfaceResp{Svgs: svgs} + + respBody := RandomSvgInterfaceResp{ + Svgs: svgs, + Colors: SetColors, + } + marshalAndWriteBytes(w, respBody) } diff --git a/core/sqlite-init/sqlite_init.go b/core/sqlite-init/sqlite_init.go index a410697..4bc7d84 100644 --- a/core/sqlite-init/sqlite_init.go +++ b/core/sqlite-init/sqlite_init.go @@ -17,7 +17,7 @@ type Icon struct { 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 { Prefix string `json:"prefix"` Icons map[string]Icon `json:"icons"` @@ -28,6 +28,9 @@ func main() { testDbPath := os.Getenv("TEST_DB_PATH") dbPath := os.Getenv("DB_PATH") dbPaths := []string{testDbPath, dbPath} + + //dbPath := "/Users/donov/Desktop/nkode.db" + //dbPaths := []string{dbPath} outputStr := MakeSvgFiles() for _, path := range dbPaths { MakeTables(path) @@ -152,59 +155,58 @@ PRAGMA journal_mode=WAL; --PRAGMA cache_size = -16000; -- Increase cache size (16MB)PRAGMA 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 --- created_at TEXT NOT NULL, --- last_renew TEXT NOT NULL, + 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 + ,last_renew TEXT NOT NULL + ,created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS user ( - id TEXT NOT NULL PRIMARY KEY, - username TEXT NOT NULL, --- email TEXT NOT NULL, --- first_name TEXT NOT NULL, --- last_name TEXT NOT NULL, - renew INT NOT NULL, - refresh_token TEXT, - customer_id TEXT NOT NULL, + id TEXT NOT NULL PRIMARY KEY + ,email TEXT NOT NULL +-- first_name TEXT NOT NULL +-- last_name TEXT NOT NULL + ,renew INT NOT NULL + ,refresh_token TEXT + ,customer_id TEXT NOT NULL -- Enciphered Passcode - code TEXT NOT NULL, - mask TEXT NOT NULL, + ,code TEXT NOT NULL + ,mask TEXT NOT NULL -- Keypad Dimensions - attributes_per_key INT NOT NULL, - number_of_keys INT NOT NULL, + ,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, + ,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, + ,idx_interface BLOB NOT NULL + ,svg_id_interface BLOB NOT NULL --- created_at TEXT NOT NULL, --- last_login TEXT NOT NULL, + ,last_login TEXT NULL + ,created_at TEXT - FOREIGN KEY (customer_id) REFERENCES customers(id), - UNIQUE(customer_id, username) + ,FOREIGN KEY (customer_id) REFERENCES customer(id) + ,UNIQUE(customer_id, email) ); CREATE TABLE IF NOT EXISTS svg_icon ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - svg TEXT NOT NULL + id INTEGER PRIMARY KEY AUTOINCREMENT + ,svg TEXT NOT NULL ); ` _, err = db.Exec(createTable) diff --git a/core/sqlite_db.go b/core/sqlite_db.go index 1881ef6..969911a 100644 --- a/core/sqlite_db.go +++ b/core/sqlite_db.go @@ -8,6 +8,7 @@ import ( "go-nkode/util" "log" "sync" + "time" ) type SqliteDB struct { @@ -59,17 +60,52 @@ func (d *SqliteDB) CloseDb() { func (d *SqliteDB) WriteNewCustomer(c Customer) error { query := ` -INSERT INTO customer (id, max_nkode_len, min_nkode_len, distinct_sets, distinct_attributes, lock_out, expiration, attribute_values, set_values) -VALUES (?,?,?,?,?,?,?,?,?) +INSERT INTO customer ( + 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) } func (d *SqliteDB) WriteNewUser(u User) error { 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) -VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) +INSERT INTO user ( + 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 if u.Renew { @@ -78,7 +114,14 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) 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) } @@ -86,8 +129,21 @@ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) func (d *SqliteDB) UpdateUserNKode(u User) error { query := ` 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 = ? -WHERE username = ? AND customer_id = ? +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 = ? +WHERE email = ? AND customer_id = ? ` var renew int if u.Renew { @@ -102,9 +158,9 @@ WHERE username = ? AND customer_id = ? func (d *SqliteDB) UpdateUserInterface(id UserId, ui UserInterface) error { 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) } @@ -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()} // TODO: replace with tx renewQuery := ` -UPDATE customer SET attribute_values = ?, set_values = ? WHERE id = ?; +UPDATE customer +SET attribute_values = ?, set_values = ? +WHERE id = ?; ` 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() 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 { 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) } renewQuery += ` @@ -190,7 +259,17 @@ func (d *SqliteDB) RefreshUserPasscode(user User, passcodeIdx []int, customerAtt return err } 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()} 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)) if err != nil { return nil, err @@ -249,35 +340,52 @@ func (d *SqliteDB) GetCustomer(id CustomerId) (*Customer, error) { 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() if err != nil { return nil, err } 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 -WHERE user.username = ? AND user.customer_id = ? +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 +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() { return nil, nil } - var id string - var renewVal int - var refreshToken string - var code string - var mask string - var attrsPerKey int - var numbOfKeys int - var alphaKey []byte - var setKey []byte - var passKey []byte - var maskKey []byte - var salt []byte - var maxNKodeLen int - var idxInterface []byte - var svgIdInterface []byte - + var ( + id string + renewVal int + refreshToken string + code string + mask string + attrsPerKey int + numbOfKeys int + alphaKey []byte + setKey []byte + passKey []byte + maskKey []byte + salt []byte + maxNKodeLen int + idxInterface []byte + svgIdInterface []byte + ) err = rows.Scan(&id, &renewVal, &refreshToken, &code, &mask, &attrsPerKey, &numbOfKeys, &alphaKey, &setKey, &passKey, &maskKey, &salt, &maxNKodeLen, &idxInterface, &svgIdInterface) userId, err := uuid.Parse(id) @@ -294,7 +402,7 @@ WHERE user.username = ? AND user.customer_id = ? user := User{ Id: UserId(userId), CustomerId: customerId, - Email: username, + Email: email, EncipheredPasscode: EncipheredNKode{ Code: code, Mask: mask, @@ -349,7 +457,11 @@ func (d *SqliteDB) getSvgsById(ids []int) ([]string, error) { if err != nil { return nil, err } - selectId := "SELECT svg FROM svg_icon where id = ?" + selectId := ` +SELECT svg +FROM svg_icon +WHERE id = ? +` svgs := make([]string, len(ids)) for idx, id := range ids { rows, err := tx.Query(selectId, id) @@ -444,3 +556,7 @@ func (d *SqliteDB) getRandomIds(count int) ([]int, error) { return perm[:count], nil } + +func timeStamp() string { + return time.Now().Format(time.RFC3339) +} diff --git a/core/sqlite_db_test.go b/core/sqlite_db_test.go index eabfe23..de1916a 100644 --- a/core/sqlite_db_test.go +++ b/core/sqlite_db_test.go @@ -23,8 +23,8 @@ func TestNewSqliteDB(t *testing.T) { } func testSignupLoginRenew(t *testing.T, db DbAccessor) { - nkode_policy := NewDefaultNKodePolicy() - customerOrig, err := NewCustomer(nkode_policy) + nkodePolicy := NewDefaultNKodePolicy() + customerOrig, err := NewCustomer(nkodePolicy) assert.NoError(t, err) err = db.WriteNewCustomer(*customerOrig) assert.NoError(t, err) diff --git a/core/type.go b/core/type.go index 372a318..f00d0ee 100644 --- a/core/type.go +++ b/core/type.go @@ -11,7 +11,8 @@ type SetNKodeResp struct { } type RandomSvgInterfaceResp struct { - Svgs []string `json:"svgs"` + Svgs []string `json:"svgs"` + Colors []RGBColor `json:"colors"` } type RefreshTokenResp struct { @@ -75,6 +76,7 @@ type GenerateSignupResetInterfaceResp struct { SessionId string `json:"session_id"` UserIdxInterface IdxInterface `json:"user_interface"` SvgInterface []string `json:"svg_interface"` + Colors []RGBColor `json:"colors"` } type GetLoginInterfaceResp struct { @@ -82,6 +84,7 @@ type GetLoginInterfaceResp struct { SvgInterface []string `json:"svg_interface"` AttrsPerKey int `json:"attrs_per_key"` NumbOfKeys int `json:"numb_of_keys"` + Colors []RGBColor `json:"colors"` } type KeySelection []int @@ -123,6 +126,12 @@ type EncipheredNKode struct { Mask string } +type RGBColor struct { + Red int `json:"red"` + Green int `json:"green"` + Blue int `json:"blue"` +} + type DbAccessor interface { GetCustomer(CustomerId) (*Customer, error) GetUser(UserEmail, CustomerId) (*User, error) diff --git a/core/user_cipher_keys.go b/core/user_cipher_keys.go index b066a4f..902a930 100644 --- a/core/user_cipher_keys.go +++ b/core/user_cipher_keys.go @@ -2,6 +2,7 @@ package core import ( "crypto/sha256" + "errors" "go-nkode/util" "golang.org/x/crypto/bcrypt" ) @@ -64,6 +65,9 @@ func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx [] passwordDigest := u.saltAndDigest(passcodeCipher) err := bcrypt.CompareHashAndPassword(hashBytes, passwordDigest) if err != nil { + if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) { + return ErrInvalidNKode + } return err } return nil diff --git a/core/user_interface.go b/core/user_interface.go index c09d7de..7ec856f 100644 --- a/core/user_interface.go +++ b/core/user_interface.go @@ -14,14 +14,12 @@ type UserInterface struct { func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) { idxInterface := util.IdentityArray(kp.TotalAttrs()) - userInterface := UserInterface{ IdxInterface: idxInterface, SvgId: svgId, Kp: kp, } - err := userInterface.RandomShuffle() - if err != nil { + if err := userInterface.RandomShuffle(); err != nil { return nil, err } return &userInterface, nil diff --git a/core/user_signup_session.go b/core/user_signup_session.go index 86dd9a4..07289f1 100644 --- a/core/user_signup_session.go +++ b/core/user_signup_session.go @@ -19,6 +19,7 @@ type UserSignSession struct { UserEmail UserEmail Reset bool Expire int + Colors []RGBColor } 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 { return nil, err } - signupInterface, err := signupInterface(*loginInterface, kp) + signupInterface, colors, err := signupInterface(*loginInterface, kp) if err != nil { return nil, err } @@ -40,6 +41,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C UserEmail: userEmail, Kp: kp, Reset: reset, + Colors: colors, } return &session, nil @@ -140,40 +142,52 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInt 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() { - return nil, ErrKeypadIsNotDispersible + return nil, nil, ErrKeypadIsNotDispersible } err := baseUserInterface.RandomShuffle() if err != nil { - return nil, err + return nil, nil, err } + // attributes are arranged by key interfaceMatrix interfaceMatrix, err := baseUserInterface.InterfaceMatrix() if err != nil { - return nil, err + return nil, nil, err } + // attributes are arranged by set attrSetView, err := util.MatrixTranspose(interfaceMatrix) 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 { - return nil, err - } - numbOfKeys := kp.NumbOfKeys - attrSetView = attrSetView[:numbOfKeys] - attrSetView, err = util.MatrixTranspose(attrSetView) - if err != nil { - return nil, err + return nil, nil, err } + signupUserInterface := UserInterface{ - IdxInterface: util.MatrixToList(attrSetView), + IdxInterface: util.MatrixToList(selectedSets), Kp: &KeypadDimension{ - AttrsPerKey: numbOfKeys, - NumbOfKeys: numbOfKeys, + AttrsPerKey: kp.NumbOfKeys, + NumbOfKeys: kp.NumbOfKeys, }, } - return &signupUserInterface, nil + return &signupUserInterface, selectedColors, nil } func (s *UserSignSession) SignupKeypad() KeypadDimension { diff --git a/deploy_api.sh b/deploy_api.sh index 4a61e2b..6b08d7a 100644 --- a/deploy_api.sh +++ b/deploy_api.sh @@ -1,22 +1,22 @@ #!/bin/bash # Create a temporary directory to hold the files -mkdir -p /tmp/nkodeapi - -cp -r ./core/* /tmp/nkodeapi/ -cp -r ./hashset/* /tmp/nkodeapi/ -cp -r ./py-builtin/* /tmp/nkodeapi/ -cp -r ./util/* /tmp/nkodeapi/ - -cp go.mod /tmp/nkodeapi/ -cp main.go /tmp/nkodeapi/ +#mkdir -p /tmp/nkodeapi +# +#cp -r ./core/* /tmp/nkodeapi/ +#cp -r ./hashset/* /tmp/nkodeapi/ +#cp -r ./py-builtin/* /tmp/nkodeapi/ +#cp -r ./util/* /tmp/nkodeapi/ +# +#cp go.mod /tmp/nkodeapi/ +#cp main.go /tmp/nkodeapi/ # Disable extended attributes and create the tar file 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 + +rm go-nkode.tar diff --git a/hashset/hashset.go b/hashset/hashset.go index 9b0a9b4..5788146 100644 --- a/hashset/hashset.go +++ b/hashset/hashset.go @@ -44,7 +44,7 @@ func (s *Set[T]) Copy() Set[T] { } func (s *Set[T]) IsDisjoint(otherSet Set[T]) bool { - for attr, _ := range *s { + for attr := range *s { if otherSet.Contains(attr) { 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] { intersect := make(Set[T]) - for val, _ := range *s { + for val := range *s { if otherSet.Contains(val) { intersect.Add(val) } diff --git a/main.go b/main.go index 742829a..3cd15cf 100644 --- a/main.go +++ b/main.go @@ -67,11 +67,11 @@ func AddDefaultCustomer(api core.NKodeAPI) { log.Fatal(err) } customerId := core.CustomerId(newId) - nkode_policy := core.NewDefaultNKodePolicy() - _, err = api.CreateNewCustomer(nkode_policy, &customerId) + nkodePolicy := core.NewDefaultNKodePolicy() + _, err = api.CreateNewCustomer(nkodePolicy, &customerId) if err != nil { - log.Print(err) + log.Println(err) } else { - log.Print("created new customer: ", newId) + log.Println("created new customer: ", newId) } } diff --git a/main_test.go b/main_test.go index 931a937..0ab8851 100644 --- a/main_test.go +++ b/main_test.go @@ -39,8 +39,8 @@ func TestApi(t *testing.T) { passcodeLen := 4 setInterface := signupInterfaceResp.UserIdxInterface userPasscode := setInterface[:passcodeLen] - kp_set := core.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys} - setKeySelection, err := core.SelectKeyByAttrIdx(setInterface, userPasscode, kp_set) + kpSet := core.KeypadDimension{NumbOfKeys: kp.NumbOfKeys, AttrsPerKey: kp.NumbOfKeys} + setKeySelection, err := core.SelectKeyByAttrIdx(setInterface, userPasscode, kpSet) assert.NoError(t, err) setNKodeBody := core.SetNKodePost{ CustomerId: customerResp.CustomerId, @@ -50,7 +50,7 @@ func TestApi(t *testing.T) { var setNKodeResp core.SetNKodeResp testApiPost(t, base+core.SetNKode, setNKodeBody, &setNKodeResp) confirmInterface := setNKodeResp.UserInterface - confirmKeySelection, err := core.SelectKeyByAttrIdx(confirmInterface, userPasscode, kp_set) + confirmKeySelection, err := core.SelectKeyByAttrIdx(confirmInterface, userPasscode, kpSet) assert.NoError(t, err) confirmNKodeBody := core.ConfirmNKodePost{ CustomerId: customerResp.CustomerId, @@ -125,7 +125,7 @@ func testApiPost(t *testing.T, endpointStr string, postBody any, respBody any) { reader := Marshal(t, postBody) resp, err := http.Post(endpointStr, "application/json", reader) assert.NoError(t, err) - assert.Equal(t, resp.StatusCode, http.StatusOK) + assert.Equal(t, http.StatusOK, resp.StatusCode) if respBody != nil { Unmarshal(t, resp, respBody) } diff --git a/util/util.go b/util/util.go index 68712d7..59b5ecc 100644 --- a/util/util.go +++ b/util/util.go @@ -13,10 +13,6 @@ import ( "time" ) -type ShuffleTypes interface { - []int | int | []uint64 | uint64 -} - var ( ErrFisherYatesShuffle = errors.New("unable to shuffle array") ErrRandomBytes = errors.New("random bytes error") @@ -30,7 +26,7 @@ var ( 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-- { bigJ, err := rand.Int(rand.Reader, big.NewInt(int64(i+1))) if err != nil { @@ -43,7 +39,7 @@ func fisherYatesShuffle[T ShuffleTypes](b *[]T) error { return nil } -func FisherYatesShuffle[T ShuffleTypes](b *[]T) error { +func FisherYatesShuffle[T any](b *[]T) error { return fisherYatesShuffle(b) }