Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
ea1c8254b4 | |||
8eb41be04a | |||
d08f82ba66 | |||
09d3149932 | |||
3ccd936601 | |||
837db0c6ec | |||
df4035ef1e |
12 changed files with 274 additions and 38 deletions
|
@ -18,7 +18,7 @@ jobs:
|
||||||
- run: go mod tidy
|
- run: go mod tidy
|
||||||
- run: go test -v ./...
|
- run: go test -v ./...
|
||||||
- run: git reset --hard
|
- run: git reset --hard
|
||||||
- uses: goreleaser/goreleaser-action@v2
|
- uses: goreleaser/goreleaser-action@v5
|
||||||
if: success() && startsWith(github.ref, 'refs/tags/')
|
if: success() && startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
|
|
|
@ -18,8 +18,6 @@ builds:
|
||||||
-X git.maurice.fr/thomas/mailout/pkg/version.Version={{ .Version }}
|
-X git.maurice.fr/thomas/mailout/pkg/version.Version={{ .Version }}
|
||||||
-X git.maurice.fr/thomas/mailout/pkg/version.Commit={{ .Commit }}
|
-X git.maurice.fr/thomas/mailout/pkg/version.Commit={{ .Commit }}
|
||||||
-X git.maurice.fr/thomas/mailout/pkg/version.BuildTime={{ .Date }}
|
-X git.maurice.fr/thomas/mailout/pkg/version.BuildTime={{ .Date }}
|
||||||
ignore:
|
|
||||||
- goarch: "386"
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- format: tar.gz
|
||||||
name_template: >-
|
name_template: >-
|
||||||
|
@ -65,15 +63,6 @@ changelog:
|
||||||
order: 400
|
order: 400
|
||||||
- title: Other miscellaneous work
|
- title: Other miscellaneous work
|
||||||
order: 500
|
order: 500
|
||||||
# nfpms:
|
|
||||||
# - maintainer: Carlos A Becker <root@carlosbecker.dev>
|
|
||||||
# description: Sample project.
|
|
||||||
# homepage: https://github.com/caarlos0/tasktimer
|
|
||||||
# license: MIT
|
|
||||||
# formats:
|
|
||||||
# - deb
|
|
||||||
# - rpm
|
|
||||||
# - apk
|
|
||||||
release:
|
release:
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
gitea_urls:
|
gitea_urls:
|
||||||
|
|
16
README.md
16
README.md
|
@ -17,9 +17,6 @@ The plan is basically:
|
||||||
* you have one for the DKIM keys you use
|
* you have one for the DKIM keys you use
|
||||||
* you have a view to expose the relevant key to use for opendkim
|
* 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
|
## Features
|
||||||
|
|
||||||
* Create mail users
|
* Create mail users
|
||||||
|
@ -40,8 +37,9 @@ For authentication, you want to change your `/etc/dovecot/dovecot-sql.conf.ext`
|
||||||
```
|
```
|
||||||
driver = pgsql
|
driver = pgsql
|
||||||
connect = host=YOURHOST port=5432 user=YOURUSER password=APASSWORD dbname=DBNAME
|
connect = host=YOURHOST port=5432 user=YOURUSER password=APASSWORD dbname=DBNAME
|
||||||
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'
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
### OpenDKIM
|
### OpenDKIM
|
||||||
|
@ -60,6 +58,12 @@ postgres:
|
||||||
user: postgres
|
user: postgres
|
||||||
password: postgres123
|
password: postgres123
|
||||||
sslmode: disable
|
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:
|
providers:
|
||||||
ovh:
|
ovh:
|
||||||
application_key: <CHANGEME>
|
application_key: <CHANGEME>
|
||||||
|
@ -68,4 +72,4 @@ providers:
|
||||||
endpoint: ovh-eu
|
endpoint: ovh-eu
|
||||||
```
|
```
|
||||||
|
|
||||||
pointing to your DB/OVH account and you're good
|
pointing to your DB/OVH account and you're good
|
||||||
|
|
|
@ -12,4 +12,4 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- postgres:/var/lib/postgresql/15/main
|
- postgres:/var/lib/postgresql/15/main
|
||||||
volumes:
|
volumes:
|
||||||
postgres: {}
|
postgres: {}
|
||||||
|
|
18
go.mod
18
go.mod
|
@ -4,36 +4,38 @@ go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/ovh/go-ovh v1.4.3
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pterm/pterm v0.12.79
|
github.com/pterm/pterm v0.12.79
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cobra v1.8.0
|
github.com/spf13/cobra v1.8.0
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.19.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/driver/postgres v1.5.6
|
gorm.io/driver/postgres v1.5.6
|
||||||
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
|
gorm.io/gorm v1.25.7
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
atomicgo.dev/cursor v0.2.0 // indirect
|
atomicgo.dev/cursor v0.2.0 // indirect
|
||||||
atomicgo.dev/keyboard v0.2.9 // indirect
|
atomicgo.dev/keyboard v0.2.9 // indirect
|
||||||
atomicgo.dev/schedule v0.1.0 // indirect
|
atomicgo.dev/schedule v0.1.0 // indirect
|
||||||
github.com/containerd/console v1.0.3 // indirect
|
github.com/containerd/console v1.0.4 // indirect
|
||||||
github.com/gookit/color v1.5.4 // indirect
|
github.com/gookit/color v1.5.4 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
github.com/jackc/pgx/v5 v5.5.3 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/lithammer/fuzzysearch v1.1.8 // indirect
|
github.com/lithammer/fuzzysearch v1.1.8 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/ovh/go-ovh v1.4.3 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.17.0 // indirect
|
golang.org/x/sys v0.17.0 // indirect
|
||||||
golang.org/x/term v0.16.0 // indirect
|
golang.org/x/term v0.17.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
19
go.sum
19
go.sum
|
@ -14,6 +14,8 @@ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYew
|
||||||
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
|
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
|
||||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||||
|
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
|
||||||
|
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -29,8 +31,14 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
@ -63,6 +71,8 @@ github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IG
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
@ -84,6 +94,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
@ -93,6 +105,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -104,6 +118,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
@ -114,6 +129,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
|
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
@ -142,3 +159,5 @@ gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU=
|
||||||
gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
||||||
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
|
||||||
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
|
|
@ -5,7 +5,12 @@ postgres:
|
||||||
user: postgres
|
user: postgres
|
||||||
password: postgres123
|
password: postgres123
|
||||||
sslmode: disable
|
sslmode: disable
|
||||||
defaultProvider: ovh
|
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:
|
providers:
|
||||||
ovh:
|
ovh:
|
||||||
application_key: <CHANGEME>
|
application_key: <CHANGEME>
|
||||||
|
|
|
@ -27,10 +27,10 @@ var DKIMKeyCmd = &cobra.Command{
|
||||||
Short: "manages DKIM keys",
|
Short: "manages DKIM keys",
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if flagProvider == "" {
|
if flagProvider == "" {
|
||||||
if cfg.DefaultProvider == "" {
|
if cfg.Defaults.Provider == "" {
|
||||||
logrus.Fatal("no provider specified and no default provider in config, aborting")
|
logrus.Fatal("no provider specified and no default provider in config, aborting")
|
||||||
}
|
}
|
||||||
flagProvider = cfg.DefaultProvider
|
flagProvider = cfg.Defaults.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -240,7 +240,7 @@ var DKIMKeyPublishCmd = &cobra.Command{
|
||||||
|
|
||||||
pv := flagProvider
|
pv := flagProvider
|
||||||
if flagProvider == "" {
|
if flagProvider == "" {
|
||||||
pv = cfg.DefaultProvider
|
pv = cfg.Defaults.Provider
|
||||||
if pv == "" {
|
if pv == "" {
|
||||||
logrus.Fatal("no provider specified")
|
logrus.Fatal("no provider specified")
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ var DKIMKeyUnpublishCmd = &cobra.Command{
|
||||||
|
|
||||||
pv := flagProvider
|
pv := flagProvider
|
||||||
if flagProvider == "" {
|
if flagProvider == "" {
|
||||||
pv = cfg.DefaultProvider
|
pv = cfg.Defaults.Provider
|
||||||
if pv == "" {
|
if pv == "" {
|
||||||
logrus.Fatal("no provider specified")
|
logrus.Fatal("no provider specified")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
"git.maurice.fr/thomas/mailout/pkg/config"
|
"git.maurice.fr/thomas/mailout/pkg/config"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -27,11 +30,19 @@ var RootCmd = &cobra.Command{
|
||||||
func InitRootCmd() {
|
func InitRootCmd() {
|
||||||
InitUserCmd()
|
InitUserCmd()
|
||||||
InitDKIMKeyCmd()
|
InitDKIMKeyCmd()
|
||||||
|
InitTestCmd()
|
||||||
|
|
||||||
RootCmd.AddCommand(VersionCmd)
|
RootCmd.AddCommand(VersionCmd)
|
||||||
RootCmd.AddCommand(InitDBCmd)
|
RootCmd.AddCommand(InitDBCmd)
|
||||||
RootCmd.AddCommand(UserCmd)
|
RootCmd.AddCommand(UserCmd)
|
||||||
RootCmd.AddCommand(DKIMKeyCmd)
|
RootCmd.AddCommand(DKIMKeyCmd)
|
||||||
|
RootCmd.AddCommand(TestCmd)
|
||||||
|
|
||||||
RootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "mailout.yml", "Configuration file")
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defaultConfigFile := path.Join(homeDir, ".mailout.yml")
|
||||||
|
|
||||||
|
RootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", defaultConfigFile, "Configuration file")
|
||||||
}
|
}
|
||||||
|
|
95
pkg/cmd/test.go
Normal file
95
pkg/cmd/test.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
flagTestMessage string
|
||||||
|
flagTestMessageSubject string
|
||||||
|
)
|
||||||
|
|
||||||
|
var TestCmd = &cobra.Command{
|
||||||
|
Use: "test",
|
||||||
|
Short: "sends an email through the configured server",
|
||||||
|
Long: ``,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if cfg.Test == nil {
|
||||||
|
logrus.Fatal("you need to specify a `test` config block")
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: strings.Split(cfg.Test.Address, ":")[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := tls.Dial("tcp", cfg.Test.Address, tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := smtp.NewClient(conn, strings.Split(cfg.Test.Address, ":")[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := make(map[string]string)
|
||||||
|
headers["From"] = cfg.Test.Username
|
||||||
|
headers["To"] = args[0]
|
||||||
|
headers["Subject"] = flagTestMessageSubject
|
||||||
|
|
||||||
|
message := ""
|
||||||
|
for k, v := range headers {
|
||||||
|
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||||
|
}
|
||||||
|
message += "\r\n"
|
||||||
|
|
||||||
|
message += flagTestMessage
|
||||||
|
|
||||||
|
auth := smtp.PlainAuth("", cfg.Test.Username, cfg.Test.Password, strings.Split(cfg.Test.Address, ":")[0])
|
||||||
|
|
||||||
|
if err = c.Auth(auth); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("could not authenticate to server")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.Mail(cfg.Test.Username); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("could not create email")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.Rcpt(args[0]); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("could not set email destination")
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := c.Data()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("could not set email data")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write([]byte(message))
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("could not set email data")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("close email")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Quit()
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
109
pkg/cmd/user.go
109
pkg/cmd/user.go
|
@ -1,7 +1,9 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"git.maurice.fr/thomas/mailout/pkg/database"
|
"git.maurice.fr/thomas/mailout/pkg/database"
|
||||||
"git.maurice.fr/thomas/mailout/pkg/models"
|
"git.maurice.fr/thomas/mailout/pkg/models"
|
||||||
|
@ -12,7 +14,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
flagUserActive bool
|
flagUserActive bool
|
||||||
|
flagUserHome string
|
||||||
|
flagUserQuota int64
|
||||||
|
flagUserPassword string
|
||||||
|
flagUserGID int
|
||||||
|
flagUserUID int
|
||||||
)
|
)
|
||||||
|
|
||||||
var UserCmd = &cobra.Command{
|
var UserCmd = &cobra.Command{
|
||||||
|
@ -73,6 +80,24 @@ var UserAddCmd = &cobra.Command{
|
||||||
Active: flagUserActive,
|
Active: flagUserActive,
|
||||||
Password: fmt.Sprintf("{BLF-CRYPT}%s", string(passwordHash)),
|
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
|
err = db.Save(&user).Error
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,10 +125,10 @@ var UserListCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
tData := pterm.TableData{
|
tData := pterm.TableData{
|
||||||
{"id", "username", "domain", "active", "uid", "gid", "created_at", "updated_at"},
|
{"id", "username", "domain", "active", "uid", "gid", "home"},
|
||||||
}
|
}
|
||||||
for _, u := range qRes {
|
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.CreatedAt.String(), u.UpdatedAt.String()})
|
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()
|
pterm.DefaultTable.WithHasHeader().WithData(tData).Render()
|
||||||
|
@ -182,12 +207,90 @@ var UserDeactivateCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UserEditCmd = &cobra.Command{
|
||||||
|
Use: "edit <user>",
|
||||||
|
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() {
|
func InitUserCmd() {
|
||||||
UserCmd.AddCommand(UserAddCmd)
|
UserCmd.AddCommand(UserAddCmd)
|
||||||
|
UserCmd.AddCommand(UserEditCmd)
|
||||||
UserCmd.AddCommand(UserListCmd)
|
UserCmd.AddCommand(UserListCmd)
|
||||||
UserCmd.AddCommand(UserDeleteCmd)
|
UserCmd.AddCommand(UserDeleteCmd)
|
||||||
UserCmd.AddCommand(UserActivateCmd)
|
UserCmd.AddCommand(UserActivateCmd)
|
||||||
UserCmd.AddCommand(UserDeactivateCmd)
|
UserCmd.AddCommand(UserDeactivateCmd)
|
||||||
|
|
||||||
UserAddCmd.PersistentFlags().BoolVarP(&flagUserActive, "active", "a", true, "whether or not the created user is active")
|
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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,18 @@ type Config struct {
|
||||||
Database string `yaml:"database"`
|
Database string `yaml:"database"`
|
||||||
SSLMode string `yaml:"sslmode"`
|
SSLMode string `yaml:"sslmode"`
|
||||||
} `yaml:"postgres"`
|
} `yaml:"postgres"`
|
||||||
DefaultProvider string `yaml:"defaultProvider"`
|
Defaults struct {
|
||||||
Providers struct {
|
HomeTemplate string `yaml:"homeTemplate"`
|
||||||
|
Provider string `yaml:"provider"`
|
||||||
|
} `yaml:"defaults"`
|
||||||
|
Providers struct {
|
||||||
OVH *providerConfigs.OVHConfig `yaml:"ovh"`
|
OVH *providerConfigs.OVHConfig `yaml:"ovh"`
|
||||||
} `yaml:"providers"`
|
} `yaml:"providers"`
|
||||||
|
Test *struct {
|
||||||
|
Address string `yaml:"address"`
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
} `yaml:"test"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig(path string) (*Config, error) {
|
func LoadConfig(path string) (*Config, error) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue