Add passwd command, fix template rendering, update deployment docs
- Add `passwd` CLI command to reset user passwords - Fix web UI templates: parse each page template with layout so blocks render correctly (was outputting empty pages) - Add login error logging for debugging auth failures - Update README with deploy workflow and container management commands - Update RUNBOOK for Docker-on-deimos deployment (replaces systemd refs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
77
cmd/eng-pad-server/passwd.go
Normal file
77
cmd/eng-pad-server/passwd.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.wntrmute.dev/kyle/eng-pad-server/internal/auth"
|
||||
"git.wntrmute.dev/kyle/eng-pad-server/internal/config"
|
||||
"git.wntrmute.dev/kyle/eng-pad-server/internal/db"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var passwdCmd = &cobra.Command{
|
||||
Use: "passwd <username>",
|
||||
Short: "Set password for a user",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runPasswd,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(passwdCmd)
|
||||
}
|
||||
|
||||
func runPasswd(cmd *cobra.Command, args []string) error {
|
||||
username := args[0]
|
||||
|
||||
cfg, err := config.Load(cfgFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
database, err := db.Open(cfg.Database.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = database.Close() }()
|
||||
|
||||
// Verify user exists.
|
||||
var userID int64
|
||||
err = database.QueryRow("SELECT id FROM users WHERE username = ?", username).Scan(&userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("user %q not found", username)
|
||||
}
|
||||
|
||||
fmt.Print("New password: ")
|
||||
passBytes, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
return fmt.Errorf("read password: %w", err)
|
||||
}
|
||||
|
||||
password := strings.TrimSpace(string(passBytes))
|
||||
if password == "" {
|
||||
return fmt.Errorf("password cannot be empty")
|
||||
}
|
||||
|
||||
params := auth.Argon2Params{
|
||||
Memory: cfg.Auth.Argon2Memory,
|
||||
Time: cfg.Auth.Argon2Time,
|
||||
Threads: cfg.Auth.Argon2Threads,
|
||||
}
|
||||
|
||||
hash, err := auth.HashPassword(password, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("hash password: %w", err)
|
||||
}
|
||||
|
||||
_, err = database.Exec("UPDATE users SET password_hash = ?, updated_at = unixepoch() WHERE id = ?", hash, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update password: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Password updated for %q.\n", username)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user