296 lines
7.5 KiB
Go
296 lines
7.5 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"text/template"
|
|
|
|
"git.maurice.fr/thomas/mailout/pkg/database"
|
|
"git.maurice.fr/thomas/mailout/pkg/models"
|
|
"github.com/pterm/pterm"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
var (
|
|
flagUserActive bool
|
|
flagUserHome string
|
|
flagUserQuota int64
|
|
flagUserPassword string
|
|
flagUserGID int
|
|
flagUserUID int
|
|
)
|
|
|
|
var UserCmd = &cobra.Command{
|
|
Use: "user",
|
|
Short: "manages users",
|
|
}
|
|
|
|
var UserAddCmd = &cobra.Command{
|
|
Use: "add [user_address] [password]",
|
|
Short: "adds a user",
|
|
Args: cobra.ExactArgs(2),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
username, domain, err := splitUser(args[0])
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not parse user")
|
|
}
|
|
|
|
qRes := make([]models.User, 0)
|
|
var user models.User
|
|
userExists := false
|
|
logger := logrus.WithField("user", args[0])
|
|
|
|
err = db.Where(&models.User{Domain: domain, Username: username}).Find(&qRes).Error
|
|
if err != nil {
|
|
logger.WithError(err).Fatal("could not check user's existence")
|
|
}
|
|
|
|
if len(qRes) == 0 {
|
|
userExists = false
|
|
} else {
|
|
logger.Warning("user already exists, it's password will be updated")
|
|
user = qRes[0]
|
|
userExists = true
|
|
}
|
|
|
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(args[1]), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
logger.WithError(err).Fatal("could not compute user password hash")
|
|
}
|
|
|
|
if userExists {
|
|
err = db.Model(&models.User{}).Where(&user).Update("password", fmt.Sprintf("{BLF-CRYPT}%s", string(passwordHash))).Error
|
|
if err != nil {
|
|
logger.WithError(err).Fatal("could not update user password")
|
|
}
|
|
logger.Infof("updated user %s", user.ID)
|
|
return
|
|
}
|
|
|
|
user = models.User{
|
|
Username: username,
|
|
Domain: domain,
|
|
Active: flagUserActive,
|
|
Password: fmt.Sprintf("{BLF-CRYPT}%s", string(passwordHash)),
|
|
}
|
|
|
|
if flagUserHome == "" {
|
|
flagUserHome = cfg.Defaults.HomeTemplate
|
|
}
|
|
|
|
tmpl, err := template.New("").Parse(flagUserHome)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not parse the default home template")
|
|
}
|
|
|
|
buf := bytes.NewBufferString("")
|
|
err = tmpl.Execute(buf, user)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not render template")
|
|
}
|
|
|
|
user.Home = buf.String()
|
|
|
|
err = db.Save(&user).Error
|
|
|
|
if err != nil {
|
|
logger.WithError(err).Fatal("could not create user")
|
|
}
|
|
|
|
logger.Infof("created user %s", user.ID)
|
|
},
|
|
}
|
|
|
|
var UserListCmd = &cobra.Command{
|
|
Use: "list",
|
|
Short: "list users",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
qRes := make([]models.User, 0)
|
|
|
|
err = db.Find(&qRes).Error
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not list users")
|
|
}
|
|
|
|
tData := pterm.TableData{
|
|
{"id", "username", "domain", "active", "uid", "gid", "home"},
|
|
}
|
|
for _, u := range qRes {
|
|
tData = append(tData, []string{u.ID.String(), u.Username, u.Domain, fmt.Sprintf("%v", u.Active), fmt.Sprintf("%d", u.UID), fmt.Sprintf("%d", u.GID), u.Home})
|
|
}
|
|
|
|
pterm.DefaultTable.WithHasHeader().WithData(tData).Render()
|
|
},
|
|
}
|
|
|
|
var UserDeleteCmd = &cobra.Command{
|
|
Use: "delete",
|
|
Short: "delete users",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
userQuery, err := buildUserQuery(args[0])
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("unable to determine user")
|
|
}
|
|
|
|
err = db.Where(&userQuery).Delete(&models.User{}).Error
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not delete user")
|
|
}
|
|
|
|
logrus.Infof("deleted user %s if it existed", args[0])
|
|
},
|
|
}
|
|
|
|
var UserActivateCmd = &cobra.Command{
|
|
Use: "activate",
|
|
Short: "activates a user",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
userQuery, err := buildUserQuery(args[0])
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("unable to determine user")
|
|
}
|
|
|
|
err = db.Model(&models.User{}).Where(&userQuery).Update("active", true).Error
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not activate user")
|
|
}
|
|
|
|
logrus.Infof("activated user %s", args[0])
|
|
},
|
|
}
|
|
|
|
var UserDeactivateCmd = &cobra.Command{
|
|
Use: "deactivate",
|
|
Short: "deactivates a user",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
userQuery, err := buildUserQuery(args[0])
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("unable to determine user")
|
|
}
|
|
|
|
err = db.Model(&models.User{}).Where(&userQuery).Update("active", false).Error
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not deactivate user")
|
|
}
|
|
|
|
logrus.Infof("deactivated user %s", args[0])
|
|
},
|
|
}
|
|
|
|
var UserEditCmd = &cobra.Command{
|
|
Use: "edit",
|
|
Short: "edites a user",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
db, err := database.NewDB(cfg)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not connect to the database")
|
|
}
|
|
|
|
userQuery, err := buildUserQuery(args[0])
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("unable to determine user")
|
|
}
|
|
|
|
qRes := make([]models.User, 0)
|
|
|
|
err = db.Model(&models.User{}).Find(&qRes, userQuery).Error
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not preload user")
|
|
}
|
|
|
|
if len(qRes) == 0 {
|
|
logrus.Fatal("no such user")
|
|
}
|
|
|
|
user := qRes[0]
|
|
|
|
if flagUserHome != "" {
|
|
tmpl, err := template.New("").Parse(flagUserHome)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not parse the default home template")
|
|
}
|
|
|
|
buf := bytes.NewBufferString("")
|
|
err = tmpl.Execute(buf, user)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not render home template")
|
|
}
|
|
|
|
user.Home = buf.String()
|
|
}
|
|
|
|
if flagUserPassword != "" {
|
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(args[1]), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not compute user password hash")
|
|
}
|
|
|
|
user.Password = fmt.Sprintf("{BLF-CRYPT}%s", string(passwordHash))
|
|
}
|
|
|
|
if flagUserGID != -1 {
|
|
user.GID = flagUserGID
|
|
}
|
|
|
|
if flagUserUID != -1 {
|
|
user.UID = flagUserUID
|
|
}
|
|
|
|
err = db.Save(&user).Error
|
|
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("could not update user")
|
|
}
|
|
|
|
logrus.Infof("edited user %s", args[0])
|
|
},
|
|
}
|
|
|
|
func InitUserCmd() {
|
|
UserCmd.AddCommand(UserAddCmd)
|
|
UserCmd.AddCommand(UserEditCmd)
|
|
UserCmd.AddCommand(UserListCmd)
|
|
UserCmd.AddCommand(UserDeleteCmd)
|
|
UserCmd.AddCommand(UserActivateCmd)
|
|
UserCmd.AddCommand(UserDeactivateCmd)
|
|
|
|
UserAddCmd.PersistentFlags().BoolVarP(&flagUserActive, "active", "a", true, "whether or not the created user is active")
|
|
UserAddCmd.PersistentFlags().StringVarP(&flagUserHome, "home", "", "", "template to use for user's home directories")
|
|
|
|
UserEditCmd.PersistentFlags().StringVarP(&flagUserPassword, "password", "p", "", "User password")
|
|
UserEditCmd.PersistentFlags().StringVarP(&flagUserHome, "home", "", "", "home (user's mailbox)")
|
|
UserEditCmd.PersistentFlags().Int64VarP(&flagUserQuota, "quota", "q", -1, "Quota in bytes for the user")
|
|
UserEditCmd.PersistentFlags().IntVarP(&flagUserUID, "uid", "u", -1, "user's uid")
|
|
UserEditCmd.PersistentFlags().IntVarP(&flagUserGID, "gid", "g", -1, "user's gid")
|
|
}
|