Restore --reset-admin-password flag for CLI admin password reset

This commit is contained in:
Christoph Haas 2026-03-23 21:58:41 +01:00
parent 1ac8c2de5a
commit 88c870ab3c
2 changed files with 53 additions and 6 deletions

View file

@ -3,15 +3,17 @@
package main
import (
"flag" // standard library for parsing command-line flags
"fmt" // formatted I/O, used here for printing output
"log" // logging package
"net/http" // HTTP server and client
"os" // OS-level operations like reading command-line args
"strings" // string manipulation utilities
"crypto/rand" // cryptographically secure random number generator
"flag" // standard library for parsing command-line flags
"fmt" // formatted I/O, used here for printing output
"log" // logging package
"net/http" // HTTP server and client
"os" // OS-level operations like reading command-line args
"strings" // string manipulation utilities
"github.com/gin-gonic/gin" // web framework
"github.com/imc-vibe/backend/internal/api" // HTTP API routing and handlers
"github.com/imc-vibe/backend/internal/auth" // password hashing
"github.com/imc-vibe/backend/internal/config" // configuration loading
"github.com/imc-vibe/backend/internal/db" // database connection and operations
)
@ -33,6 +35,10 @@ func main() {
// Common ports: 80 (HTTP), 443 (HTTPS), 8080 (HTTP alternate).
port := flag.String("port", "", "Port to listen on (default: 8080)")
// --reset-admin-password: Generate a random password for the admin user and exit.
// Useful for initial setup or recovering from a lost password.
resetAdminPassword := flag.Bool("reset-admin-password", false, "Reset admin password to a random value and exit")
// Customize the help output to show double-hyphen style (Unix convention).
// By default, Go's flag package uses single hyphens.
flag.Usage = func() {
@ -75,6 +81,23 @@ func main() {
log.Printf("Warning: Could not initialize schema: %v", err) // Non-fatal = continue
}
// Handle --reset-admin-password flag.
// When this flag is set, we generate a random password, update the database, and exit.
if *resetAdminPassword {
password := generateRandomPassword(16)
hash, err := auth.HashPassword(password)
if err != nil {
log.Fatalf("Failed to hash password: %v", err)
}
if err := database.UpsertAdminUser("admin", hash); err != nil {
log.Fatalf("Failed to reset admin password: %v", err)
}
fmt.Printf("Admin password reset successfully.\n")
fmt.Printf("Username: admin\n")
fmt.Printf("Password: %s\n", password)
return
}
// Start the web server.
// From here on, we set up the HTTP router and handlers.
@ -162,6 +185,19 @@ func serveGinStaticFile(c *gin.Context, fs http.FileSystem, path string) {
http.ServeContent(c.Writer, c.Request, fi.Name(), fi.ModTime(), file)
}
// generateRandomPassword creates a cryptographically secure random password.
func generateRandomPassword(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
result := make([]byte, length)
if _, err := rand.Read(result); err != nil {
log.Fatalf("Failed to generate random password: %v", err)
}
for i := range result {
result[i] = charset[int(result[i])%len(charset)]
}
return string(result)
}
// mimeType returns the MIME type for a file based on its extension.
// MIME types tell the browser what kind of file it is.
// This is important for browsers to correctly interpret files.

View file

@ -68,6 +68,17 @@ func (d *DB) DeleteImcUser(id uint) error {
return d.Delete(&ImcUser{}, id).Error // Delete by primary key
}
// UpsertAdminUser creates the admin user if it doesn't exist, or updates the password if it does.
func (d *DB) UpsertAdminUser(username, passwordHash string) error {
var user ImcUser
err := d.Where("username = ? AND role = ?", username, "admin").First(&user).Error
if err == nil {
return d.Model(&ImcUser{}).Where("id = ?", user.ID).Update("password_hash", passwordHash).Error
}
_, err = d.CreateImcUser(username, passwordHash, "admin")
return err
}
// =============================================================================
// Domain Access Control
// These functions manage which domains users can access.