chore(tfstated): refactor setting last login date time on successful HTTP basic auth

This commit is contained in:
Julien Dessaux 2024-12-28 23:16:09 +01:00
parent 6d00e12097
commit 1dbb1b9ee7
Signed by: adyxax
GPG key ID: F92E51B86E07177E
2 changed files with 39 additions and 32 deletions

View file

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"time"
"git.adyxax.org/adyxax/tfstated/pkg/database"
"git.adyxax.org/adyxax/tfstated/pkg/helpers"
@ -29,9 +28,7 @@ func Middleware(db *database.DB) func(http.Handler) http.Handler {
helpers.ErrorResponse(w, http.StatusForbidden, fmt.Errorf("Forbidden"))
return
}
now := time.Now().UTC()
_, err = db.Exec(`UPDATE accounts SET last_login = ? WHERE id = ?`, now.Unix(), account.Id)
if err != nil {
if err := db.TouchAccount(account); err != nil {
helpers.ErrorResponse(w, http.StatusInternalServerError, err)
return
}

View file

@ -17,6 +17,36 @@ var AdvertiseAdminPassword = func(password string) {
slog.Info("Generated an initial admin password, please change it or delete the admin account after your first login", "password", password)
}
func (db *DB) InitAdminAccount() error {
return db.WithTransaction(func(tx *sql.Tx) error {
var hasAdminAccount bool
if err := tx.QueryRowContext(db.ctx, `SELECT EXISTS (SELECT 1 FROM accounts WHERE is_admin);`).Scan(&hasAdminAccount); err != nil {
return fmt.Errorf("failed to select if there is an admin account in the database: %w", err)
}
if !hasAdminAccount {
var password uuid.UUID
if err := password.Generate(uuid.V4); err != nil {
return fmt.Errorf("failed to generate initial admin password: %w", err)
}
salt := helpers.GenerateSalt()
hash := helpers.HashPassword(password.String(), salt)
if _, err := tx.ExecContext(db.ctx,
`INSERT INTO accounts(username, salt, password_hash, is_admin)
VALUES ("admin", :salt, :hash, TRUE)
ON CONFLICT DO UPDATE SET password_hash = :hash
WHERE username = "admin";`,
sql.Named("salt", salt),
sql.Named("hash", hash),
); err == nil {
AdvertiseAdminPassword(password.String())
} else {
return fmt.Errorf("failed to set initial admin password: %w", err)
}
}
return nil
})
}
func (db *DB) LoadAccountByUsername(username string) (*model.Account, error) {
account := model.Account{
Username: username,
@ -49,32 +79,12 @@ func (db *DB) LoadAccountByUsername(username string) (*model.Account, error) {
return &account, nil
}
func (db *DB) InitAdminAccount() error {
return db.WithTransaction(func(tx *sql.Tx) error {
var hasAdminAccount bool
if err := tx.QueryRowContext(db.ctx, `SELECT EXISTS (SELECT 1 FROM accounts WHERE is_admin);`).Scan(&hasAdminAccount); err != nil {
return fmt.Errorf("failed to select if there is an admin account in the database: %w", err)
}
if !hasAdminAccount {
var password uuid.UUID
if err := password.Generate(uuid.V4); err != nil {
return fmt.Errorf("failed to generate initial admin password: %w", err)
}
salt := helpers.GenerateSalt()
hash := helpers.HashPassword(password.String(), salt)
if _, err := tx.ExecContext(db.ctx,
`INSERT INTO accounts(username, salt, password_hash, is_admin)
VALUES ("admin", :salt, :hash, TRUE)
ON CONFLICT DO UPDATE SET password_hash = :hash
WHERE username = "admin";`,
sql.Named("salt", salt),
sql.Named("hash", hash),
); err == nil {
AdvertiseAdminPassword(password.String())
} else {
return fmt.Errorf("failed to set initial admin password: %w", err)
}
func (db *DB) TouchAccount(account *model.Account) error {
now := time.Now().UTC()
_, err := db.Exec(`UPDATE accounts SET last_login = ? WHERE id = ?`, now.Unix(), account.Id)
if err != nil {
return fmt.Errorf("failed to update last_login for user %s: %w", account.Username, err)
}
account.LastLogin = now
return nil
})
}