forked from goffee/goffee
user:password [username] [newpassword] [dev|prod] username - the name of the user to update password - the new password to set env - "dev" to use .env-dev, "prod" to use .env
163 lines
4.1 KiB
Go
163 lines
4.1 KiB
Go
// Copyright (c) 2026 Zeni Kim <zenik@smarteching.com>
|
|
// Use of this source code is governed by MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/joho/godotenv"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/driver/mysql"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
var UserPasswordCmd = &cobra.Command{
|
|
Use: "user:password [username] [newpassword] [dev|prod]",
|
|
Short: "Change a user password",
|
|
Long: `Set the password for the user account with the specified name.
|
|
|
|
Requires three arguments:
|
|
username - the name of the user to update
|
|
password - the new password to set
|
|
env - "dev" to use .env-dev, "prod" to use .env
|
|
|
|
Example:
|
|
goffee user:password someuser 'strongpassword' dev
|
|
goffee user:password admin 'newpass123' prod
|
|
|
|
`,
|
|
Args: cobra.ExactArgs(3),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
|
|
username := args[0]
|
|
newPassword := args[1]
|
|
envMode := args[2]
|
|
|
|
// Determine which env file to load
|
|
var envFile string
|
|
switch envMode {
|
|
case "dev":
|
|
envFile = ".env-dev"
|
|
case "prod":
|
|
envFile = ".env"
|
|
default:
|
|
fmt.Printf("Error: environment must be 'dev' or 'prod', got '%s'\n", envMode)
|
|
return
|
|
}
|
|
|
|
// Build full path to env file
|
|
envPath := filepath.Join(".", envFile)
|
|
if _, err := os.Stat(envPath); os.IsNotExist(err) {
|
|
fmt.Printf("Error: environment file '%s' not found in current directory\n", envFile)
|
|
return
|
|
}
|
|
|
|
// Load env file
|
|
err := godotenv.Load(envPath)
|
|
if err != nil {
|
|
fmt.Printf("Error loading environment file '%s': %v\n", envFile, err)
|
|
return
|
|
}
|
|
|
|
// Connect to database
|
|
db, err := connectDatabase()
|
|
if err != nil {
|
|
fmt.Printf("Error connecting to database: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Find user by name
|
|
type User struct {
|
|
ID uint
|
|
Name string
|
|
Password string
|
|
Email string
|
|
}
|
|
var user User
|
|
result := db.Where("name = ?", username).First(&user)
|
|
if result.Error != nil {
|
|
if strings.Contains(result.Error.Error(), "record not found") {
|
|
fmt.Printf("Error: user '%s' not found\n", username)
|
|
} else {
|
|
fmt.Printf("Error finding user: %v\n", result.Error)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Hash the new password
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
fmt.Printf("Error hashing password: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Update password in database
|
|
result = db.Model(&user).Update("password", string(hashedPassword))
|
|
if result.Error != nil {
|
|
fmt.Printf("Error updating password: %v\n", result.Error)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Password updated successfully for user '%s'\n", username)
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(UserPasswordCmd)
|
|
}
|
|
|
|
// connectDatabase establishes a database connection based on the loaded environment variables.
|
|
func connectDatabase() (*gorm.DB, error) {
|
|
dbDriver := os.Getenv("DB_DRIVER")
|
|
|
|
var dialector gorm.Dialector
|
|
switch dbDriver {
|
|
case "sqlite":
|
|
sqlitePath := os.Getenv("SQLITE_DB_PATH")
|
|
if sqlitePath == "" {
|
|
return nil, fmt.Errorf("SQLITE_DB_PATH environment variable not set")
|
|
}
|
|
dialector = sqlite.Open(sqlitePath)
|
|
case "mysql":
|
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
|
|
os.Getenv("MYSQL_USERNAME"),
|
|
os.Getenv("MYSQL_PASSWORD"),
|
|
os.Getenv("MYSQL_HOST"),
|
|
os.Getenv("MYSQL_PORT"),
|
|
os.Getenv("MYSQL_DB_NAME"),
|
|
os.Getenv("MYSQL_CHARSET"),
|
|
)
|
|
dialector = mysql.Open(dsn)
|
|
case "postgres":
|
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s TimeZone=%s",
|
|
os.Getenv("POSTGRES_HOST"),
|
|
os.Getenv("POSTGRES_USER"),
|
|
os.Getenv("POSTGRES_PASSWORD"),
|
|
os.Getenv("POSTGRES_DB_NAME"),
|
|
os.Getenv("POSTGRES_PORT"),
|
|
os.Getenv("POSTGRES_SSL_MODE"),
|
|
os.Getenv("POSTGRES_TIMEZONE"),
|
|
)
|
|
dialector = postgres.Open(dsn)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database driver: '%s'", dbDriver)
|
|
}
|
|
|
|
db, err := gorm.Open(dialector, &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db, nil
|
|
}
|