chore(tfstated): refactor setting last login date time on successful HTTP basic auth
This commit is contained in:
parent
6d00e12097
commit
1dbb1b9ee7
2 changed files with 39 additions and 32 deletions
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.adyxax.org/adyxax/tfstated/pkg/database"
|
"git.adyxax.org/adyxax/tfstated/pkg/database"
|
||||||
"git.adyxax.org/adyxax/tfstated/pkg/helpers"
|
"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"))
|
helpers.ErrorResponse(w, http.StatusForbidden, fmt.Errorf("Forbidden"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
now := time.Now().UTC()
|
if err := db.TouchAccount(account); err != nil {
|
||||||
_, err = db.Exec(`UPDATE accounts SET last_login = ? WHERE id = ?`, now.Unix(), account.Id)
|
|
||||||
if err != nil {
|
|
||||||
helpers.ErrorResponse(w, http.StatusInternalServerError, err)
|
helpers.ErrorResponse(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
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) {
|
func (db *DB) LoadAccountByUsername(username string) (*model.Account, error) {
|
||||||
account := model.Account{
|
account := model.Account{
|
||||||
Username: username,
|
Username: username,
|
||||||
|
@ -49,32 +79,12 @@ func (db *DB) LoadAccountByUsername(username string) (*model.Account, error) {
|
||||||
return &account, nil
|
return &account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) InitAdminAccount() error {
|
func (db *DB) TouchAccount(account *model.Account) error {
|
||||||
return db.WithTransaction(func(tx *sql.Tx) error {
|
now := time.Now().UTC()
|
||||||
var hasAdminAccount bool
|
_, err := db.Exec(`UPDATE accounts SET last_login = ? WHERE id = ?`, now.Unix(), account.Id)
|
||||||
if err := tx.QueryRowContext(db.ctx, `SELECT EXISTS (SELECT 1 FROM accounts WHERE is_admin);`).Scan(&hasAdminAccount); err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to select if there is an admin account in the database: %w", err)
|
return fmt.Errorf("failed to update last_login for user %s: %w", account.Username, 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
account.LastLogin = now
|
||||||
return nil
|
return nil
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue