diff --git a/README.md b/README.md index 7ace2b8..dd1a208 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ The plan is basically: * you have one for the DKIM keys you use * you have a view to expose the relevant key to use for opendkim +## Warning +I halfed assed that shit on an afternoon to suit my own needs, improvements will follow, or not. + ## Features * Create mail users @@ -37,9 +40,8 @@ For authentication, you want to change your `/etc/dovecot/dovecot-sql.conf.ext` ``` driver = pgsql connect = host=YOURHOST port=5432 user=YOURUSER password=APASSWORD dbname=DBNAME - -password_query = SELECT concat(username, '@', domain) AS user, password FROM users WHERE username = '%n' AND domain = '%d' AND active = true -user_query = SELECT home, 1000 AS uid, 1000 AS gid FROM users WHERE username = '%n' AND domain = '%d' AND active = true +password_query = SELECT password, username AS user FROM users WHERE username = '%n' AND domain = '%d' +user_query = SELECT maildir, 1000 AS uid, 1000 AS gid FROM users WHERE username = '%n' AND domain = '%d' AND active = '1' ``` ### OpenDKIM @@ -58,12 +60,6 @@ postgres: user: postgres password: postgres123 sslmode: disable -defaults: - provider: ovh - # this is used to create the `home` field of the user. - # in systems with virtual mail this corresponds to the physical - # location of the vmail directory on your host - homeTemplate: "/var/lib/vmail/{{ .Domain }}/{{ .Username }}" providers: ovh: application_key: @@ -72,4 +68,4 @@ providers: endpoint: ovh-eu ``` -pointing to your DB/OVH account and you're good +pointing to your DB/OVH account and you're good \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a3c0e92..a4628df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,4 +12,4 @@ services: volumes: - postgres:/var/lib/postgresql/15/main volumes: - postgres: {} + postgres: {} \ No newline at end of file diff --git a/mailout.yml.sample b/mailout.yml.sample index 445a136..038cb20 100644 --- a/mailout.yml.sample +++ b/mailout.yml.sample @@ -5,12 +5,7 @@ postgres: user: postgres password: postgres123 sslmode: disable -defaults: - provider: ovh - # this is used to create the `home` field of the user. - # in systems with virtual mail this corresponds to the physical - # location of the vmail directory on your host - homeTemplate: "/var/lib/vmail/{{ .Domain }}/{{ .Username }}" +defaultProvider: ovh providers: ovh: application_key: diff --git a/pkg/cmd/dkimkey.go b/pkg/cmd/dkimkey.go index caddd4a..1be46b7 100644 --- a/pkg/cmd/dkimkey.go +++ b/pkg/cmd/dkimkey.go @@ -27,10 +27,10 @@ var DKIMKeyCmd = &cobra.Command{ Short: "manages DKIM keys", PreRunE: func(cmd *cobra.Command, args []string) error { if flagProvider == "" { - if cfg.Defaults.Provider == "" { + if cfg.DefaultProvider == "" { logrus.Fatal("no provider specified and no default provider in config, aborting") } - flagProvider = cfg.Defaults.Provider + flagProvider = cfg.DefaultProvider } return nil @@ -240,7 +240,7 @@ var DKIMKeyPublishCmd = &cobra.Command{ pv := flagProvider if flagProvider == "" { - pv = cfg.Defaults.Provider + pv = cfg.DefaultProvider if pv == "" { logrus.Fatal("no provider specified") } @@ -299,7 +299,7 @@ var DKIMKeyUnpublishCmd = &cobra.Command{ pv := flagProvider if flagProvider == "" { - pv = cfg.Defaults.Provider + pv = cfg.DefaultProvider if pv == "" { logrus.Fatal("no provider specified") } diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 4ce4124..bd5029b 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -30,7 +30,6 @@ var RootCmd = &cobra.Command{ func InitRootCmd() { InitUserCmd() InitDKIMKeyCmd() - InitTestCmd() RootCmd.AddCommand(VersionCmd) RootCmd.AddCommand(InitDBCmd) diff --git a/pkg/cmd/test.go b/pkg/cmd/test.go index f173ace..6d99200 100644 --- a/pkg/cmd/test.go +++ b/pkg/cmd/test.go @@ -11,11 +11,6 @@ import ( "github.com/spf13/cobra" ) -var ( - flagTestMessage string - flagTestMessageSubject string -) - var TestCmd = &cobra.Command{ Use: "test", Short: "sends an email through the configured server", @@ -44,7 +39,7 @@ var TestCmd = &cobra.Command{ headers := make(map[string]string) headers["From"] = cfg.Test.Username headers["To"] = args[0] - headers["Subject"] = flagTestMessageSubject + headers["Subject"] = "This is a test email from the command line" message := "" for k, v := range headers { @@ -52,7 +47,7 @@ var TestCmd = &cobra.Command{ } message += "\r\n" - message += flagTestMessage + message += "This is a test email message sent through the command line utility." auth := smtp.PlainAuth("", cfg.Test.Username, cfg.Test.Password, strings.Split(cfg.Test.Address, ":")[0]) @@ -88,8 +83,3 @@ var TestCmd = &cobra.Command{ logrus.Info("sent test email") }, } - -func InitTestCmd() { - TestCmd.PersistentFlags().StringVarP(&flagTestMessage, "message", "m", "This is a test email message sent through the command line utility.", "What to send as a test message") - TestCmd.PersistentFlags().StringVarP(&flagTestMessageSubject, "subject", "s", "This is a test email from the command line", "What to send as a test message subject") -} diff --git a/pkg/cmd/user.go b/pkg/cmd/user.go index 5828aad..4cb794e 100644 --- a/pkg/cmd/user.go +++ b/pkg/cmd/user.go @@ -1,9 +1,7 @@ package cmd import ( - "bytes" "fmt" - "text/template" "git.maurice.fr/thomas/mailout/pkg/database" "git.maurice.fr/thomas/mailout/pkg/models" @@ -14,12 +12,7 @@ import ( ) var ( - flagUserActive bool - flagUserHome string - flagUserQuota int64 - flagUserPassword string - flagUserGID int - flagUserUID int + flagUserActive bool ) var UserCmd = &cobra.Command{ @@ -80,24 +73,6 @@ var UserAddCmd = &cobra.Command{ 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 { @@ -125,10 +100,10 @@ var UserListCmd = &cobra.Command{ } tData := pterm.TableData{ - {"id", "username", "domain", "active", "uid", "gid", "home"}, + {"id", "username", "domain", "active", "uid", "gid", "created_at", "updated_at"}, } 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}) + 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.CreatedAt.String(), u.UpdatedAt.String()}) } pterm.DefaultTable.WithHasHeader().WithData(tData).Render() @@ -207,90 +182,12 @@ var UserDeactivateCmd = &cobra.Command{ }, } -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(flagUserPassword), 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") } diff --git a/pkg/config/config.go b/pkg/config/config.go index eccb9c0..a282700 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -16,11 +16,8 @@ type Config struct { Database string `yaml:"database"` SSLMode string `yaml:"sslmode"` } `yaml:"postgres"` - Defaults struct { - HomeTemplate string `yaml:"homeTemplate"` - Provider string `yaml:"provider"` - } `yaml:"defaults"` - Providers struct { + DefaultProvider string `yaml:"defaultProvider"` + Providers struct { OVH *providerConfigs.OVHConfig `yaml:"ovh"` } `yaml:"providers"` Test *struct {