package sqlite3 import ( "database/sql" "fmt" "golang.org/x/crypto/bcrypt" ) type TableConfig struct { db *sql.DB get *sql.Stmt set *sql.Stmt } const configSchema = ` CREATE TABLE IF NOT EXISTS config ( key TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY(key) ); ` const configGet = ` SELECT value FROM config WHERE key = $1 ` const configSet = ` INSERT OR REPLACE INTO config (key, value) VALUES($1, $2) ` func NewTableConfig(db *sql.DB) (*TableConfig, error) { t := &TableConfig{ db: db, } _, err := db.Exec(configSchema) if err != nil { return nil, fmt.Errorf("db.Exec: %w", err) } t.get, err = db.Prepare(configGet) if err != nil { return nil, fmt.Errorf("db.Prepare(get): %w", err) } t.set, err = db.Prepare(configSet) if err != nil { return nil, fmt.Errorf("db.Prepare(set): %w", err) } return t, nil } func (t *TableConfig) ConfigGet(key string) (string, error) { var value string err := t.get.QueryRow(key).Scan(&value) if err == sql.ErrNoRows { return "", nil } return value, err } func (t *TableConfig) ConfigSet(key, value string) error { _, err := t.set.Exec(key, value) return err } func (t *TableConfig) ConfigSetPassword(password string) error { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return fmt.Errorf("bcrypt.GenerateFromPassword: %w", err) } return t.ConfigSet("password", string(hash)) } func (t *TableConfig) ConfigTryPassword(password string) (bool, error) { dbPasswordHash, err := t.ConfigGet("password") if err != nil { return false, err } if dbPasswordHash == "" { return true, nil // TODO: Do we want to allow login if no password is set? } err = bcrypt.CompareHashAndPassword([]byte(dbPasswordHash), []byte(password)) if err == nil { return true, nil } return false, err }