postfix_admin 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -4
- data/CHANGELOG.md +21 -14
- data/Rakefile +29 -0
- data/db/reset.rb +7 -0
- data/db/seeds.rb +26 -0
- data/docker-admin/config.local.php +3 -1
- data/docker-compose.yml +3 -7
- data/lib/postfix_admin/base.rb +4 -17
- data/lib/postfix_admin/cli.rb +102 -48
- data/lib/postfix_admin/doveadm.rb +31 -15
- data/lib/postfix_admin/{admin.rb → models/admin.rb} +20 -2
- data/lib/postfix_admin/{alias.rb → models/alias.rb} +16 -7
- data/lib/postfix_admin/{application_record.rb → models/application_record.rb} +1 -1
- data/lib/postfix_admin/{concerns → models/concerns}/existing_timestamp.rb +1 -2
- data/lib/postfix_admin/models/concerns/has_password.rb +16 -0
- data/lib/postfix_admin/{domain.rb → models/domain.rb} +23 -0
- data/lib/postfix_admin/models/domain_admin.rb +19 -0
- data/lib/postfix_admin/models/log.rb +20 -0
- data/lib/postfix_admin/models/mailbox.rb +126 -0
- data/lib/postfix_admin/models/quota2.rb +18 -0
- data/lib/postfix_admin/models.rb +8 -9
- data/lib/postfix_admin/runner.rb +57 -7
- data/lib/postfix_admin/version.rb +1 -1
- metadata +15 -14
- data/lib/postfix_admin/concerns/dovecot_cram_md5_password.rb +0 -29
- data/lib/postfix_admin/domain_admin.rb +0 -8
- data/lib/postfix_admin/log.rb +0 -5
- data/lib/postfix_admin/mail_domain.rb +0 -9
- data/lib/postfix_admin/mailbox.rb +0 -97
- data/lib/postfix_admin/quota.rb +0 -6
- /data/lib/postfix_admin/{concerns → models/concerns}/.keep +0 -0
@@ -1,5 +1,18 @@
|
|
1
1
|
module PostfixAdmin
|
2
2
|
class Alias < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe alias;
|
5
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | address | varchar(255) | NO | PRI | NULL | |
|
9
|
+
# | goto | text | NO | | NULL | |
|
10
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
11
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
12
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
13
|
+
# | active | tinyint(1) | NO | | 1 | |
|
14
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
15
|
+
|
3
16
|
self.table_name = :alias
|
4
17
|
self.primary_key = :address
|
5
18
|
|
@@ -21,15 +34,11 @@ module PostfixAdmin
|
|
21
34
|
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
22
35
|
belongs_to :mailbox, foreign_key: :address, optional: true
|
23
36
|
|
37
|
+
# aliases which do not belong to any mailbox
|
24
38
|
scope :pure, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username" => nil) }
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
before_validation do |a|
|
29
|
-
unless a.address
|
30
|
-
a.address = "#{a.local_part}@#{a.domain}" unless a.local_part.empty?
|
31
|
-
end
|
32
|
-
end
|
40
|
+
# aliases which belong to a mailbox and have forwardings to other addresses
|
41
|
+
scope :forward, -> { joins("LEFT OUTER JOIN mailbox ON alias.address = mailbox.username").where("mailbox.username <> alias.goto") }
|
33
42
|
|
34
43
|
def mailbox?
|
35
44
|
!!mailbox
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module HasPassword
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# example: {CRAM-MD5}, {BLF-CRYPT}, {PLAIN}
|
7
|
+
# return nil if no scheme prefix
|
8
|
+
def scheme_prefix
|
9
|
+
res = password&.match(/^\{.*?\}/)
|
10
|
+
if res
|
11
|
+
res[0]
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,5 +1,23 @@
|
|
1
1
|
module PostfixAdmin
|
2
2
|
class Domain < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe domain;
|
5
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | domain | varchar(255) | NO | PRI | NULL | |
|
9
|
+
# | description | varchar(255) | NO | | NULL | |
|
10
|
+
# | aliases | int(10) | NO | | 0 | |
|
11
|
+
# | mailboxes | int(10) | NO | | 0 | |
|
12
|
+
# | maxquota | bigint(20) | NO | | 0 | |
|
13
|
+
# | quota | bigint(20) | NO | | 0 | |
|
14
|
+
# | transport | varchar(255) | NO | | NULL | |
|
15
|
+
# | backupmx | tinyint(1) | NO | | 0 | |
|
16
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
17
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
18
|
+
# | active | tinyint(1) | NO | | 1 | |
|
19
|
+
# +-------------+--------------+------+-----+---------------------+-------+
|
20
|
+
|
3
21
|
self.table_name = :domain
|
4
22
|
self.primary_key = :domain
|
5
23
|
|
@@ -31,6 +49,10 @@ module PostfixAdmin
|
|
31
49
|
has_many :rel_aliases, class_name: "Alias", foreign_key: :domain,
|
32
50
|
dependent: :destroy
|
33
51
|
|
52
|
+
# logs that belong to this domain
|
53
|
+
has_many :logs, class_name: "Log", foreign_key: :domain,
|
54
|
+
dependent: :destroy
|
55
|
+
|
34
56
|
# It causes errors to set `dependent: :destroy` as other columns
|
35
57
|
# because the domain_admins table doesn't have a single primary key.
|
36
58
|
#
|
@@ -45,6 +67,7 @@ module PostfixAdmin
|
|
45
67
|
# It works well with `dependent: :delete_all` instead.
|
46
68
|
#
|
47
69
|
# PostfixAdmin::DomainAdmin Destroy (0.4ms) DELETE FROM `domain_admins` WHERE `domain_admins`.`domain` = 'example.com'
|
70
|
+
# Domain <-> DomainAdmin <-> Admin
|
48
71
|
has_many :domain_admins, foreign_key: :domain, dependent: :delete_all
|
49
72
|
|
50
73
|
has_many :admins, through: :domain_admins
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class DomainAdmin < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe domain_admins;
|
5
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | username | varchar(255) | NO | MUL | NULL | |
|
9
|
+
# | domain | varchar(255) | NO | | NULL | |
|
10
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
11
|
+
# | active | tinyint(1) | NO | | 1 | |
|
12
|
+
# +----------+--------------+------+-----+---------------------+-------+
|
13
|
+
|
14
|
+
self.table_name = :domain_admins
|
15
|
+
|
16
|
+
belongs_to :admin, primary_key: :username, foreign_key: :username
|
17
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class Log < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe log;
|
5
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
8
|
+
# | timestamp | datetime | NO | MUL | 2000-01-01 00:00:00 | |
|
9
|
+
# | username | varchar(255) | NO | | NULL | |
|
10
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
11
|
+
# | action | varchar(255) | NO | | NULL | |
|
12
|
+
# | data | text | NO | | NULL | |
|
13
|
+
# | id | int(11) | NO | PRI | NULL | auto_increment |
|
14
|
+
# +-----------+--------------+------+-----+---------------------+----------------+
|
15
|
+
|
16
|
+
self.table_name = :log
|
17
|
+
|
18
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'postfix_admin/models/concerns/has_password'
|
2
|
+
|
3
|
+
module PostfixAdmin
|
4
|
+
class Mailbox < ApplicationRecord
|
5
|
+
# version: 1841
|
6
|
+
# > describe mailbox;
|
7
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
8
|
+
# | Field | Type | Null | Key | Default | Extra |
|
9
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
10
|
+
# | username | varchar(255) | NO | PRI | NULL | |
|
11
|
+
# | password | varchar(255) | NO | | NULL | |
|
12
|
+
# | name | varchar(255) | NO | | NULL | |
|
13
|
+
# | maildir | varchar(255) | NO | | NULL | |
|
14
|
+
# | quota | bigint(20) | NO | | 0 | |
|
15
|
+
# | local_part | varchar(255) | NO | | NULL | |
|
16
|
+
# | domain | varchar(255) | NO | MUL | NULL | |
|
17
|
+
# | created | datetime | NO | | 2000-01-01 00:00:00 | |
|
18
|
+
# | modified | datetime | NO | | 2000-01-01 00:00:00 | |
|
19
|
+
# | active | tinyint(1) | NO | | 1 | |
|
20
|
+
# | phone | varchar(30) | NO | | | |
|
21
|
+
# | email_other | varchar(255) | NO | | | |
|
22
|
+
# | token | varchar(255) | NO | | | |
|
23
|
+
# | token_validity | datetime | NO | | 2000-01-01 00:00:00 | |
|
24
|
+
# +----------------+--------------+------+-----+---------------------+-------+
|
25
|
+
|
26
|
+
self.table_name = :mailbox
|
27
|
+
self.primary_key = :username
|
28
|
+
|
29
|
+
include HasPassword
|
30
|
+
|
31
|
+
# attribute :quota_mb, :integer
|
32
|
+
|
33
|
+
validates :username, presence: true, uniqueness: { case_sensitive: false },
|
34
|
+
format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
|
35
|
+
message: "must be a valid email address" }
|
36
|
+
validates :maildir, presence: true, uniqueness: { case_sensitive: false }
|
37
|
+
validates :local_part, presence: true
|
38
|
+
|
39
|
+
# quota (KB)
|
40
|
+
validates :quota, presence: true,
|
41
|
+
numericality: { only_integer: true,
|
42
|
+
greater_than_or_equal_to: 0 }
|
43
|
+
|
44
|
+
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
45
|
+
has_one :alias, foreign_key: :address, dependent: :destroy
|
46
|
+
has_one :quota_usage, class_name: "Quota2", foreign_key: :username,
|
47
|
+
dependent: :destroy
|
48
|
+
|
49
|
+
validate on: :create do |mailbox|
|
50
|
+
domain = mailbox.rel_domain
|
51
|
+
if !domain.mailboxes.zero? && domain.rel_mailboxes.count >= domain.mailboxes
|
52
|
+
message = "already has the maximum number of mailboxes " \
|
53
|
+
"(maximum is #{domain.mailboxes} mailboxes)"
|
54
|
+
mailbox.errors.add(:domain, message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# just in case
|
59
|
+
validate on: :update do |mailbox|
|
60
|
+
mailbox.errors.add(:username, 'cannot be changed') if mailbox.username_changed?
|
61
|
+
mailbox.errors.add(:local_part, 'cannot be changed') if mailbox.local_part_changed?
|
62
|
+
end
|
63
|
+
|
64
|
+
validate do |mailbox|
|
65
|
+
next if mailbox.quota == -1
|
66
|
+
|
67
|
+
domain = mailbox.rel_domain
|
68
|
+
|
69
|
+
unless domain.maxquota.zero?
|
70
|
+
if mailbox.quota.zero?
|
71
|
+
mailbox.errors.add(:quota, "cannot be 0")
|
72
|
+
elsif mailbox.quota_mb > domain.maxquota
|
73
|
+
message = "must be less than or equal to #{domain.maxquota} (MB)"
|
74
|
+
mailbox.errors.add(:quota, message)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
before_validation do |mailbox|
|
80
|
+
mailbox.name = "" if mailbox.name.nil?
|
81
|
+
mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
|
82
|
+
mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
|
83
|
+
mailbox.build_alias(address: mailbox.username, goto: mailbox.username,
|
84
|
+
domain: mailbox.domain)
|
85
|
+
end
|
86
|
+
|
87
|
+
def quota_mb
|
88
|
+
raise Error, "quota is out of range: #{quota}" if quota < 0
|
89
|
+
|
90
|
+
quota / KB_TO_MB
|
91
|
+
end
|
92
|
+
|
93
|
+
def quota_mb=(value)
|
94
|
+
raise Error, "quota is out of range: #{value}" if value < 0
|
95
|
+
|
96
|
+
self.quota = value * KB_TO_MB
|
97
|
+
end
|
98
|
+
|
99
|
+
def quota_usage_str(format: "%6.1f")
|
100
|
+
usage_mb = if quota_usage
|
101
|
+
usage_mb = quota_usage.bytes / KB_TO_MB.to_f
|
102
|
+
else
|
103
|
+
0.0
|
104
|
+
end
|
105
|
+
|
106
|
+
format % usage_mb
|
107
|
+
end
|
108
|
+
|
109
|
+
def quota_mb_str(format: "%6.1f")
|
110
|
+
case quota
|
111
|
+
when -1
|
112
|
+
# It's not sure what 'disabled' means for quota.
|
113
|
+
"Disabled"
|
114
|
+
when 0
|
115
|
+
"Unlimited"
|
116
|
+
else
|
117
|
+
quota_mb = quota / KB_TO_MB.to_f
|
118
|
+
format % quota_mb
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def quota_display_str(format: "%6.1f")
|
123
|
+
"%s / %s" % [quota_usage_str(format: format), quota_mb_str(format: format)]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PostfixAdmin
|
2
|
+
class Quota2 < ApplicationRecord
|
3
|
+
# version: 1841
|
4
|
+
# > describe quota2;
|
5
|
+
# +----------+--------------+------+-----+---------+-------+
|
6
|
+
# | Field | Type | Null | Key | Default | Extra |
|
7
|
+
# +----------+--------------+------+-----+---------+-------+
|
8
|
+
# | username | varchar(100) | NO | PRI | NULL | |
|
9
|
+
# | bytes | bigint(20) | NO | | 0 | |
|
10
|
+
# | messages | int(11) | NO | | 0 | |
|
11
|
+
# +----------+--------------+------+-----+---------+-------+
|
12
|
+
|
13
|
+
self.table_name = :quota2
|
14
|
+
self.primary_key = :username
|
15
|
+
|
16
|
+
belongs_to :rel_mailbox, class_name: "Mailbox", foreign_key: :username
|
17
|
+
end
|
18
|
+
end
|
data/lib/postfix_admin/models.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'active_record'
|
2
|
-
require 'postfix_admin/application_record'
|
3
|
-
require 'postfix_admin/admin'
|
4
|
-
require 'postfix_admin/domain'
|
5
|
-
require 'postfix_admin/mailbox'
|
6
|
-
require 'postfix_admin/alias'
|
7
|
-
require 'postfix_admin/domain_admin'
|
8
|
-
require 'postfix_admin/log'
|
9
|
-
require 'postfix_admin/
|
10
|
-
require 'postfix_admin/quota'
|
2
|
+
require 'postfix_admin/models/application_record'
|
3
|
+
require 'postfix_admin/models/admin'
|
4
|
+
require 'postfix_admin/models/domain'
|
5
|
+
require 'postfix_admin/models/mailbox'
|
6
|
+
require 'postfix_admin/models/alias'
|
7
|
+
require 'postfix_admin/models/domain_admin'
|
8
|
+
require 'postfix_admin/models/log'
|
9
|
+
require 'postfix_admin/models/quota2'
|
data/lib/postfix_admin/runner.rb
CHANGED
@@ -30,21 +30,66 @@ module PostfixAdmin
|
|
30
30
|
runner { @cli.show(name) }
|
31
31
|
end
|
32
32
|
|
33
|
-
desc "
|
33
|
+
desc "admins", "List all admin users"
|
34
|
+
def admins
|
35
|
+
runner { @cli.show_admins }
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "domains", "List all domains"
|
39
|
+
def domains
|
40
|
+
runner { @cli.show_domains }
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "accounts", "List all accounts"
|
44
|
+
def accounts
|
45
|
+
runner { @cli.show_accounts }
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "aliases", "List all aliases"
|
49
|
+
def aliases
|
50
|
+
runner { @cli.show_aliases }
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "forwards", "List all forwards"
|
54
|
+
def forwards
|
55
|
+
runner { @cli.show_forwards }
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "setup example.com password", "Set up a domain (add a domain and an admin user for it)"
|
59
|
+
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
60
|
+
method_option :rounds, type: :string, aliases: "-r", desc: "encryption rounds for BLF-CRYPT, SHA256-CRYPT and SHA512-CRYPT schemes"
|
34
61
|
def setup(domain_name, password)
|
35
|
-
runner
|
62
|
+
runner do
|
63
|
+
@cli.setup_domain(domain_name, password,
|
64
|
+
scheme: options[:scheme], rounds: options[:rounds])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "teardown example.com", "Tear down a domain (delete a domain and an admin user for it)"
|
69
|
+
def teardown(domain_name)
|
70
|
+
runner { @cli.teardown_domain(domain_name) }
|
36
71
|
end
|
37
72
|
|
38
73
|
desc "admin_passwd admin@example.com new_password",
|
39
74
|
"Change the password of an admin user"
|
75
|
+
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
76
|
+
method_option :rounds, type: :string, aliases: "-r", desc: "encryption rounds for BLF-CRYPT, SHA256-CRYPT and SHA512-CRYPT schemes"
|
40
77
|
def admin_passwd(user_name, password)
|
41
|
-
runner
|
78
|
+
runner do
|
79
|
+
@cli.change_admin_password(user_name, password,
|
80
|
+
scheme: options[:scheme], rounds: options[:rounds])
|
81
|
+
end
|
42
82
|
end
|
43
83
|
|
44
84
|
desc "account_passwd user@example.com new_password",
|
45
85
|
"Change the password of an account"
|
86
|
+
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
87
|
+
method_option :rounds, type: :string, aliases: "-r", desc: "encryption rounds for BLF-CRYPT, SHA256-CRYPT and SHA512-CRYPT schemes"
|
46
88
|
def account_passwd(user_name, password)
|
47
|
-
runner
|
89
|
+
runner do
|
90
|
+
@cli.change_account_password(user_name, password,
|
91
|
+
scheme: options[:scheme], rounds: options[:rounds])
|
92
|
+
end
|
48
93
|
end
|
49
94
|
|
50
95
|
desc "add_domain example.com", "Add a new domain"
|
@@ -86,8 +131,9 @@ module PostfixAdmin
|
|
86
131
|
end
|
87
132
|
|
88
133
|
desc "add_account user@example.com password", "Add a new account"
|
89
|
-
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
90
134
|
method_option :name, type: :string, aliases: "-n", desc: "full name"
|
135
|
+
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
136
|
+
method_option :rounds, type: :string, aliases: "-r", desc: "encryption rounds for BLF-CRYPT, SHA256-CRYPT and SHA512-CRYPT schemes"
|
91
137
|
def add_account(address, password)
|
92
138
|
runner do
|
93
139
|
if options[:scheme] == 'scheme'
|
@@ -98,7 +144,8 @@ module PostfixAdmin
|
|
98
144
|
warn "Specify name"
|
99
145
|
help('add_account')
|
100
146
|
else
|
101
|
-
@cli.add_account(address, password,
|
147
|
+
@cli.add_account(address, password, name: options[:name],
|
148
|
+
scheme: options[:scheme], rounds: options[:rounds])
|
102
149
|
end
|
103
150
|
end
|
104
151
|
end
|
@@ -146,13 +193,16 @@ module PostfixAdmin
|
|
146
193
|
desc "add_admin admin@example.com password", "Add a new admin user"
|
147
194
|
method_option :super, type: :boolean, aliases: "-S", desc: "register as a super admin"
|
148
195
|
method_option :scheme, type: :string, aliases: "-s", desc: "password scheme"
|
196
|
+
method_option :rounds, type: :string, aliases: "-r", desc: "encryption rounds for BLF-CRYPT, SHA256-CRYPT and SHA512-CRYPT schemes"
|
149
197
|
def add_admin(user_name, password)
|
150
198
|
runner do
|
151
199
|
if options[:scheme] == 'scheme'
|
152
200
|
warn "Specify password scheme"
|
153
201
|
help('add_admin')
|
154
202
|
else
|
155
|
-
@cli.add_admin(user_name, password,
|
203
|
+
@cli.add_admin(user_name, password,
|
204
|
+
super_admin: options[:super], scheme: options[:scheme],
|
205
|
+
rounds: options[:rounds])
|
156
206
|
end
|
157
207
|
end
|
158
208
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postfix_admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hitoshi Kurokawa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -154,6 +154,8 @@ files:
|
|
154
154
|
- Rakefile
|
155
155
|
- Thorfile
|
156
156
|
- bin/console
|
157
|
+
- db/reset.rb
|
158
|
+
- db/seeds.rb
|
157
159
|
- docker-admin/Dockerfile
|
158
160
|
- docker-admin/config.local.php
|
159
161
|
- docker-app/Dockerfile
|
@@ -164,23 +166,22 @@ files:
|
|
164
166
|
- docker-db/postfix.v740.sql
|
165
167
|
- exe/postfix_admin
|
166
168
|
- lib/postfix_admin.rb
|
167
|
-
- lib/postfix_admin/admin.rb
|
168
|
-
- lib/postfix_admin/alias.rb
|
169
|
-
- lib/postfix_admin/application_record.rb
|
170
169
|
- lib/postfix_admin/base.rb
|
171
170
|
- lib/postfix_admin/cli.rb
|
172
|
-
- lib/postfix_admin/concerns/.keep
|
173
|
-
- lib/postfix_admin/concerns/dovecot_cram_md5_password.rb
|
174
|
-
- lib/postfix_admin/concerns/existing_timestamp.rb
|
175
|
-
- lib/postfix_admin/domain.rb
|
176
|
-
- lib/postfix_admin/domain_admin.rb
|
177
171
|
- lib/postfix_admin/doveadm.rb
|
178
172
|
- lib/postfix_admin/error.rb
|
179
|
-
- lib/postfix_admin/log.rb
|
180
|
-
- lib/postfix_admin/mail_domain.rb
|
181
|
-
- lib/postfix_admin/mailbox.rb
|
182
173
|
- lib/postfix_admin/models.rb
|
183
|
-
- lib/postfix_admin/
|
174
|
+
- lib/postfix_admin/models/admin.rb
|
175
|
+
- lib/postfix_admin/models/alias.rb
|
176
|
+
- lib/postfix_admin/models/application_record.rb
|
177
|
+
- lib/postfix_admin/models/concerns/.keep
|
178
|
+
- lib/postfix_admin/models/concerns/existing_timestamp.rb
|
179
|
+
- lib/postfix_admin/models/concerns/has_password.rb
|
180
|
+
- lib/postfix_admin/models/domain.rb
|
181
|
+
- lib/postfix_admin/models/domain_admin.rb
|
182
|
+
- lib/postfix_admin/models/log.rb
|
183
|
+
- lib/postfix_admin/models/mailbox.rb
|
184
|
+
- lib/postfix_admin/models/quota2.rb
|
184
185
|
- lib/postfix_admin/runner.rb
|
185
186
|
- lib/postfix_admin/version.rb
|
186
187
|
- postfix_admin.gemspec
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
|
3
|
-
module DovecotCramMD5Password
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
validates :password_unencrypted, length: { minimum: 5 }, allow_blank: true
|
8
|
-
validates_confirmation_of :password_unencrypted, allow_blank: true
|
9
|
-
|
10
|
-
validate do |record|
|
11
|
-
record.errors.add(:password_unencrypted, :blank) unless record.password.present?
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :password_unencrypted
|
15
|
-
end
|
16
|
-
|
17
|
-
def password_unencrypted=(unencrypted_password)
|
18
|
-
if unencrypted_password.nil?
|
19
|
-
self.password = nil
|
20
|
-
elsif !unencrypted_password.empty?
|
21
|
-
@password_unencrypted = unencrypted_password
|
22
|
-
self.password = DovecotCrammd5.calc(unencrypted_password)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def authenticate(unencrypted_password)
|
27
|
-
password == DovecotCrammd5.calc(unencrypted_password) && self
|
28
|
-
end
|
29
|
-
end
|
data/lib/postfix_admin/log.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
module PostfixAdmin
|
2
|
-
class Mailbox < ApplicationRecord
|
3
|
-
self.table_name = :mailbox
|
4
|
-
self.primary_key = :username
|
5
|
-
|
6
|
-
include DovecotCramMD5Password
|
7
|
-
|
8
|
-
attribute :quota_mb, :integer
|
9
|
-
|
10
|
-
validates :username, presence: true, uniqueness: { case_sensitive: false },
|
11
|
-
format: { with: RE_EMAIL_LIKE_WITH_ANCHORS,
|
12
|
-
message: "must be a valid email address" }
|
13
|
-
validates :maildir, presence: true, uniqueness: { case_sensitive: false }
|
14
|
-
validates :local_part, presence: true
|
15
|
-
|
16
|
-
# quota (KB)
|
17
|
-
validates :quota, presence: true,
|
18
|
-
numericality: { only_integer: true,
|
19
|
-
greater_than_or_equal_to: 0 }
|
20
|
-
|
21
|
-
# quota (MB), which actually doesn't exist in DB
|
22
|
-
validates :quota_mb, presence: true,
|
23
|
-
numericality: { only_integer: true,
|
24
|
-
greater_than_or_equal_to: 0 }
|
25
|
-
|
26
|
-
belongs_to :rel_domain, class_name: "Domain", foreign_key: :domain
|
27
|
-
has_one :alias, foreign_key: :address, dependent: :destroy
|
28
|
-
has_one :quota_usage, class_name: "Quota", foreign_key: :username,
|
29
|
-
dependent: :destroy
|
30
|
-
|
31
|
-
validate on: :create do |mailbox|
|
32
|
-
domain = mailbox.rel_domain
|
33
|
-
if !domain.mailboxes.zero? && domain.rel_mailboxes.count >= domain.mailboxes
|
34
|
-
message = "already has the maximum number of mailboxes " \
|
35
|
-
"(maximum is #{domain.mailboxes} mailboxes)"
|
36
|
-
mailbox.errors.add(:domain, message)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# just in case
|
41
|
-
validate on: :update do |mailbox|
|
42
|
-
mailbox.errors.add(:username, 'cannot be changed') if mailbox.username_changed?
|
43
|
-
mailbox.errors.add(:local_part, 'cannot be changed') if mailbox.local_part_changed?
|
44
|
-
end
|
45
|
-
|
46
|
-
validate do |mailbox|
|
47
|
-
domain = mailbox.rel_domain
|
48
|
-
|
49
|
-
unless domain.maxquota.zero?
|
50
|
-
if mailbox.quota_mb.zero?
|
51
|
-
mailbox.errors.add(:quota_mb, "cannot be 0")
|
52
|
-
elsif mailbox.quota_mb > domain.maxquota
|
53
|
-
message = "must be less than or equal to #{domain.maxquota} (MB)"
|
54
|
-
mailbox.errors.add(:quota_mb, message)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
before_validation do |mailbox|
|
60
|
-
mailbox.name = "" if mailbox.name.nil?
|
61
|
-
if mailbox.quota_mb
|
62
|
-
mailbox.quota = mailbox.quota_mb * KB_TO_MB
|
63
|
-
elsif mailbox.quota
|
64
|
-
mailbox.quota_mb = mailbox.quota / KB_TO_MB
|
65
|
-
else
|
66
|
-
mailbox.quota_mb = 0
|
67
|
-
mailbox.quota = 0
|
68
|
-
end
|
69
|
-
mailbox.username = "#{mailbox.local_part}@#{mailbox.domain}"
|
70
|
-
mailbox.maildir ||= "#{mailbox.domain}/#{mailbox.username}/"
|
71
|
-
mailbox.build_alias(local_part: mailbox.local_part, goto: mailbox.username,
|
72
|
-
domain: mailbox.domain)
|
73
|
-
end
|
74
|
-
|
75
|
-
def quota_usage_str
|
76
|
-
if quota_usage
|
77
|
-
usage_mb = quota_usage.bytes / KB_TO_MB
|
78
|
-
usage_mb.to_s
|
79
|
-
else
|
80
|
-
"0"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def quota_mb_str
|
85
|
-
case quota
|
86
|
-
when -1
|
87
|
-
# It's not sure what 'disabled' means for quota.
|
88
|
-
"Disabled"
|
89
|
-
when 0
|
90
|
-
"Unlimited"
|
91
|
-
else
|
92
|
-
mb_size = quota / KB_TO_MB
|
93
|
-
mb_size.to_s
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
data/lib/postfix_admin/quota.rb
DELETED
File without changes
|