diff options
author | Julien Dessaux | 2025-01-31 20:53:29 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-01-31 20:53:29 +0100 |
commit | ab548d249b56988823cc91fa46ad7bfff0d75250 (patch) | |
tree | bc2c5c5e480a462eab19d873382bf11abacdffbe | |
parent | feat(webui): bootstrap account settings management with light and dark mode (diff) | |
download | tfstated-ab548d249b56988823cc91fa46ad7bfff0d75250.tar.gz tfstated-ab548d249b56988823cc91fa46ad7bfff0d75250.tar.bz2 tfstated-ab548d249b56988823cc91fa46ad7bfff0d75250.zip |
-rw-r--r-- | pkg/database/accounts.go | 23 | ||||
-rw-r--r-- | pkg/database/sql/000_init.sql | 6 | ||||
-rw-r--r-- | pkg/database/states.go | 4 | ||||
-rw-r--r-- | pkg/model/account.go | 2 | ||||
-rw-r--r-- | pkg/model/session.go | 2 | ||||
-rw-r--r-- | pkg/model/version.go | 5 | ||||
-rw-r--r-- | pkg/webui/html/login.html | 3 | ||||
-rw-r--r-- | pkg/webui/state.go | 2 |
8 files changed, 27 insertions, 20 deletions
diff --git a/pkg/database/accounts.go b/pkg/database/accounts.go index e6363f1..2c1dc6d 100644 --- a/pkg/database/accounts.go +++ b/pkg/database/accounts.go @@ -25,6 +25,10 @@ func (db *DB) InitAdminAccount() error { return fmt.Errorf("failed to select if there is an admin account in the database: %w", err) } if !hasAdminAccount { + var accountId uuid.UUID + if err := accountId.Generate(uuid.V7); err != nil { + return fmt.Errorf("failed to generate account id: %w", err) + } var password uuid.UUID if err := password.Generate(uuid.V4); err != nil { return fmt.Errorf("failed to generate initial admin password: %w", err) @@ -32,13 +36,14 @@ func (db *DB) InitAdminAccount() error { salt := helpers.GenerateSalt() hash := helpers.HashPassword(password.String(), salt) if _, err := tx.ExecContext(db.ctx, - `INSERT INTO accounts(username, salt, password_hash, is_admin, settings) - VALUES ("admin", :salt, :hash, TRUE, :settings) + `INSERT INTO accounts(id, username, salt, password_hash, is_admin, settings) + VALUES (:id, "admin", :salt, :hash, TRUE, :settings) ON CONFLICT DO UPDATE SET password_hash = :hash WHERE username = "admin";`, - sql.Named("salt", salt), + sql.Named("id", accountId), sql.Named("hash", hash), - []byte("{}"), + sql.Named("salt", salt), + sql.Named("settings", []byte("{}")), ); err == nil { AdvertiseAdminPassword(password.String()) } else { @@ -49,17 +54,17 @@ func (db *DB) InitAdminAccount() error { }) } -func (db *DB) LoadAccountUsernames() (map[int]string, error) { +func (db *DB) LoadAccountUsernames() (map[string]string, error) { rows, err := db.Query( `SELECT id, username FROM accounts;`) if err != nil { return nil, fmt.Errorf("failed to load accounts from database: %w", err) } defer rows.Close() - accounts := make(map[int]string) + accounts := make(map[string]string) for rows.Next() { var ( - id int + id string username string ) err = rows.Scan(&id, &username) @@ -74,7 +79,7 @@ func (db *DB) LoadAccountUsernames() (map[int]string, error) { return accounts, nil } -func (db *DB) LoadAccountById(id int) (*model.Account, error) { +func (db *DB) LoadAccountById(id string) (*model.Account, error) { account := model.Account{ Id: id, } @@ -99,7 +104,7 @@ func (db *DB) LoadAccountById(id int) (*model.Account, error) { if errors.Is(err, sql.ErrNoRows) { return nil, nil } - return nil, fmt.Errorf("failed to load account by id %d: %w", id, err) + return nil, fmt.Errorf("failed to load account by id %s: %w", id, err) } account.Created = time.Unix(created, 0) account.LastLogin = time.Unix(lastLogin, 0) diff --git a/pkg/database/sql/000_init.sql b/pkg/database/sql/000_init.sql index 80e8c8c..3530e52 100644 --- a/pkg/database/sql/000_init.sql +++ b/pkg/database/sql/000_init.sql @@ -3,7 +3,7 @@ CREATE TABLE schema_version ( ) STRICT; CREATE TABLE accounts ( - id INTEGER PRIMARY KEY, + id TEXT PRIMARY KEY, username TEXT NOT NULL, salt BLOB NOT NULL, password_hash BLOB NOT NULL, @@ -16,7 +16,7 @@ CREATE UNIQUE INDEX accounts_username on accounts(username); CREATE TABLE sessions ( id TEXT PRIMARY KEY, - account_id INTEGER NOT NULL, + account_id TEXT NOT NULL, created INTEGER NOT NULL DEFAULT (unixepoch()), updated INTEGER NOT NULL DEFAULT (unixepoch()), data TEXT NOT NULL, @@ -34,7 +34,7 @@ CREATE UNIQUE INDEX states_path on states(path); CREATE TABLE versions ( id INTEGER PRIMARY KEY, - account_id INTEGER NOT NULL, + account_id TEXT NOT NULL, state_id INTEGER, data BLOB, lock TEXT, diff --git a/pkg/database/states.go b/pkg/database/states.go index d65dd7c..ccae942 100644 --- a/pkg/database/states.go +++ b/pkg/database/states.go @@ -60,7 +60,7 @@ func (db *DB) LoadStateById(stateId int) (*model.State, error) { if errors.Is(err, sql.ErrNoRows) { return nil, nil } - return nil, fmt.Errorf("failed to load state id %s from database: %w", stateId, err) + return nil, fmt.Errorf("failed to load state id %d from database: %w", stateId, err) } state.Created = time.Unix(created, 0) state.Updated = time.Unix(updated, 0) @@ -96,7 +96,7 @@ func (db *DB) LoadStates() ([]model.State, error) { } // returns true in case of id mismatch -func (db *DB) SetState(path string, accountID int, data []byte, lockID string) (bool, error) { +func (db *DB) SetState(path string, accountID string, data []byte, lockID string) (bool, error) { encryptedData, err := db.dataEncryptionKey.EncryptAES256(data) if err != nil { return false, fmt.Errorf("failed to encrypt state data: %w", err) diff --git a/pkg/model/account.go b/pkg/model/account.go index 5055943..d47668a 100644 --- a/pkg/model/account.go +++ b/pkg/model/account.go @@ -11,7 +11,7 @@ import ( type AccountContextKey struct{} type Account struct { - Id int + Id string Username string Salt []byte PasswordHash []byte diff --git a/pkg/model/session.go b/pkg/model/session.go index afa6a77..8b2bb01 100644 --- a/pkg/model/session.go +++ b/pkg/model/session.go @@ -8,7 +8,7 @@ type SessionContextKey struct{} type Session struct { Id string - AccountId int + AccountId string Created time.Time Updated time.Time Data any diff --git a/pkg/model/version.go b/pkg/model/version.go index d8c3603..f07db45 100644 --- a/pkg/model/version.go +++ b/pkg/model/version.go @@ -1,13 +1,14 @@ package model import ( + "encoding/json" "time" ) type Version struct { - AccountId int + AccountId string Created time.Time - Data []byte + Data json.RawMessage Id int Lock *string StateId int diff --git a/pkg/webui/html/login.html b/pkg/webui/html/login.html index 4ff0265..deb6d4a 100644 --- a/pkg/webui/html/login.html +++ b/pkg/webui/html/login.html @@ -3,7 +3,8 @@ <form action="/login" method="post"> <fieldset> <div class="field border label{{ if .Forbidden }} invalid{{ end}}"> - <input id="username" + <input autofocus + id="username" name="username" type="text" value="{{ .Username }}" diff --git a/pkg/webui/state.go b/pkg/webui/state.go index 141d2d8..2ad1597 100644 --- a/pkg/webui/state.go +++ b/pkg/webui/state.go @@ -15,7 +15,7 @@ func handleStateGET(db *database.DB) http.Handler { type StatesData struct { Page *Page State *model.State - Usernames map[int]string + Usernames map[string]string Versions []model.Version } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |