Remove ADMIN_PASSWORD configuration
Authentication now works only via hashed passwords in imc_users table. Users must be created through the password reset flow or directly in the database.
This commit is contained in:
parent
3e30f3845d
commit
b76ea568ae
5 changed files with 7 additions and 97 deletions
|
|
@ -8,9 +8,6 @@ DB_NAME=mailserver
|
|||
# Security - JWT secret must be at least 32 characters
|
||||
JWT_SECRET=your-secret-key-at-least-32-chars
|
||||
|
||||
# Admin user (optional - use --reset-admin-password to set password)
|
||||
ADMIN_USER=admin
|
||||
|
||||
# SMTP settings for password reset emails
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=587
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_USER=mailadmin
|
||||
DB_PASSWORD=MAILADMIN-PASSWORD-HERE
|
||||
DB_PASSWORD=your-db-password
|
||||
DB_NAME=mailserver
|
||||
JWT_SECRET=change-this-secret-in-production
|
||||
ADMIN_USER=admin
|
||||
ADMIN_PASSWORD=admin123
|
||||
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=587
|
||||
|
|
|
|||
|
|
@ -3,17 +3,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"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
|
||||
"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" // JWT authentication
|
||||
"github.com/imc-vibe/backend/internal/config" // configuration loading
|
||||
"github.com/imc-vibe/backend/internal/db" // database connection and operations
|
||||
)
|
||||
|
|
@ -26,10 +24,6 @@ func main() {
|
|||
// Flags are optional arguments passed after the program name.
|
||||
// Example: ./imc-vibe --bind=0.0.0.0 --port=8080
|
||||
|
||||
// --reset-admin-password: If set, 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")
|
||||
|
||||
// --bind: The IP address the server should listen on.
|
||||
// 0.0.0.0 means listen on all network interfaces (accessible from other machines).
|
||||
// 127.0.0.1 means listen only on localhost (accessible only from this machine).
|
||||
|
|
@ -81,33 +75,6 @@ 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.
|
||||
// We don't start the web server in this case.
|
||||
if *resetAdminPassword {
|
||||
// Generate a cryptographically secure random password.
|
||||
// The password will be 16 characters long, containing letters, numbers, and symbols.
|
||||
password := generateRandomPassword(16)
|
||||
fmt.Printf("Generated password: %s\n", password)
|
||||
|
||||
// Hash the password before storing it.
|
||||
// We never store plain-text passwords, only their hashes.
|
||||
// This uses bcrypt, which is a slow hashing algorithm designed to resist brute-force attacks.
|
||||
hash, err := auth.HashPassword(password)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to hash password: %v", err)
|
||||
}
|
||||
|
||||
// Store or update the admin user in the database.
|
||||
// EnsureAdminUser creates the user if it doesn't exist, or updates the password if it does.
|
||||
if err := database.EnsureAdminUser("admin", hash); err != nil {
|
||||
log.Fatalf("Failed to reset admin password: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Admin password reset successfully.")
|
||||
return // Exit the program
|
||||
}
|
||||
|
||||
// Start the web server.
|
||||
// From here on, we set up the HTTP router and handlers.
|
||||
|
||||
|
|
@ -195,33 +162,6 @@ 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.
|
||||
// length: how many characters the password should have.
|
||||
// Returns: a string containing random characters from a safe charset.
|
||||
func generateRandomPassword(length int) string {
|
||||
// Characters that are safe to use in passwords.
|
||||
// We avoid ambiguous characters like 0/O and 1/l/I.
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
|
||||
// Create a byte slice to hold random bytes.
|
||||
result := make([]byte, length)
|
||||
|
||||
// Use crypto/rand for cryptographically secure randomness.
|
||||
// This is better than math/rand for security-sensitive applications.
|
||||
if _, err := rand.Read(result); err != nil {
|
||||
log.Fatalf("Failed to generate random password: %v", err)
|
||||
}
|
||||
|
||||
// Convert random bytes to characters from our charset.
|
||||
// We use modulo to map bytes to charset indices.
|
||||
// This isn't perfectly uniform distribution, but is good enough for passwords.
|
||||
for i := range result {
|
||||
result[i] = charset[int(result[i])%len(charset)]
|
||||
}
|
||||
|
||||
return string(result) // Convert bytes to string
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ type Config struct {
|
|||
JWTSecret string // Secret key for signing JWT tokens (keep this secret!)
|
||||
TrustedProxies []string // IPs of trusted reverse proxies (for X-Forwarded-For)
|
||||
|
||||
// Admin user configuration (used when --reset-admin-password is not used)
|
||||
AdminUser string // Username for the admin account
|
||||
AdminPassword string // Password for the admin account (only used during startup)
|
||||
|
||||
// Mail server paths and settings
|
||||
MailDataDir string // Directory where mail is stored (e.g., /var/vmail)
|
||||
PostqueuePath string // Path to postqueue command (for mail queue operations)
|
||||
|
|
@ -94,10 +90,6 @@ func Load() *Config {
|
|||
// Default JWT secret is insecure - must be changed in production!
|
||||
JWTSecret: getEnv("JWT_SECRET", "change-this-secret-in-production"),
|
||||
|
||||
// Admin user (optional - used during startup if set)
|
||||
AdminUser: getEnv("ADMIN_USER", ""),
|
||||
AdminPassword: getEnv("ADMIN_PASSWORD", ""),
|
||||
|
||||
// Mail server paths
|
||||
MailDataDir: getEnv("MAIL_DATA_DIR", "/var/vmail"),
|
||||
PostqueuePath: getEnv("POSTQUEUE_PATH", "/usr/sbin/postqueue"),
|
||||
|
|
|
|||
|
|
@ -68,23 +68,6 @@ func (d *DB) DeleteImcUser(id uint) error {
|
|||
return d.Delete(&ImcUser{}, id).Error // Delete by primary key
|
||||
}
|
||||
|
||||
// EnsureAdminUser creates the admin user if it doesn't exist, or updates the password if it does.
|
||||
// This is used during --reset-admin-password and startup.
|
||||
// username: always "admin" in our case.
|
||||
// passwordHash: the bcrypt hash of the password.
|
||||
func (d *DB) EnsureAdminUser(username, passwordHash string) error {
|
||||
var user ImcUser
|
||||
// Try to find an existing admin user with this username.
|
||||
err := d.Where("username = ? AND role = ?", username, "admin").First(&user).Error
|
||||
if err == nil {
|
||||
// User exists - update their password.
|
||||
return d.Model(&ImcUser{}).Where("id = ?", user.ID).Update("password_hash", passwordHash).Error
|
||||
}
|
||||
// User doesn't exist - create them.
|
||||
_, err = d.CreateImcUser(username, passwordHash, "admin")
|
||||
return err
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Domain Access Control
|
||||
// These functions manage which domains users can access.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue