lib/postfix_admin/cli.rb in postfix_admin-0.3.0 vs lib/postfix_admin/cli.rb in postfix_admin-0.3.1

- old
+ new

@@ -55,13 +55,13 @@ if name # domain name show_domain_details(name) else # no argument: show all domains and admins - show_domain + show_domains puts - show_admin + show_admins end end def show_summary(domain_name = nil) if domain_name @@ -71,28 +71,36 @@ end end # Set up a domain # Add a domain, add an admin, and grant the admin access to the domain - def setup_domain(domain_name, password) + def setup_domain(domain_name, password, scheme: nil, rounds: nil) admin = "admin@#{domain_name}" add_domain(domain_name) - add_admin(admin, password) + add_admin(admin, password, scheme: scheme, rounds: rounds) add_admin_domain(admin, domain_name) end + # Tear down a domain + # Delete a domain and delete an admin user for it + def teardown_domain(domain_name) + admin = "admin@#{domain_name}" + delete_domain(domain_name) + delete_admin(admin) + end + def show_account_details(user_name, display_password: false) account_check(user_name) mailbox = Mailbox.find(user_name) mail_alias = Alias.find(user_name) rows = [] puts_title("Mailbox") rows << ["Address", mailbox.username] rows << ["Name", mailbox.name] rows << ["Password", mailbox.password] if display_password - rows << ["Quota (MB)", mailbox.quota_mb_str] + rows << ["Quota (MB)", mailbox.quota_display_str(format: "%.1f")] rows << ["Go to", mail_alias.goto] rows << ["Active", mailbox.active_str] puts_table(rows: rows) end @@ -123,11 +131,11 @@ rows << ["Active", mail_alias.active_str] puts_table(rows: rows) end - def show_domain + def show_domains rows = [] headings = ["No.", "Domain", "Aliases", "Mailboxes","Max Quota (MB)", "Active", "Description"] puts_title("Domains") @@ -150,16 +158,16 @@ def add_domain(domain_name, description: nil) @base.add_domain(domain_name, description: description) puts_registered(domain_name, "a domain") end - def change_admin_password(user_name, password) - change_password(Admin, user_name, password) + def change_admin_password(user_name, password, scheme: nil, rounds: nil) + change_password(Admin, user_name, password, scheme: scheme, rounds: rounds) end - def change_account_password(user_name, password) - change_password(Mailbox, user_name, password) + def change_account_password(user_name, password, scheme: nil, rounds: nil) + change_password(Mailbox, user_name, password, scheme: scheme, rounds: rounds) end def edit_admin(admin_name, options) admin_check(admin_name) admin = Admin.find(admin_name) @@ -169,11 +177,11 @@ end admin.active = options[:active] unless options[:active].nil? admin.save! - puts "Successfully updated #{admin_name}" + puts "successfully updated #{admin_name}" show_admin_details(admin_name) end def edit_domain(domain_name, options) domain_check(domain_name) @@ -183,22 +191,22 @@ domain.maxquota = options[:maxquota] if options[:maxquota] domain.active = options[:active] unless options[:active].nil? domain.description = options[:description] if options[:description] domain.save! - puts "Successfully updated #{domain_name}" + puts "successfully updated #{domain_name}" show_summary(domain_name) end def delete_domain(domain_name) @base.delete_domain(domain_name) puts_deleted(domain_name) end - def show_admin(domain_name = nil) + def show_admins(domain_name = nil) admins = domain_name ? Admin.select { |a| a.rel_domains.exists?(domain_name) } : Admin.all - headings = %w[No. Admin Domains Active] + headings = ["No.", "Admin", "Domains", "Active", "Scheme Prefix"] puts_title("Admins") if admins.empty? puts "No admins" return @@ -206,49 +214,64 @@ rows = [] admins.each_with_index do |a, i| no = i + 1 domains = a.super_admin? ? 'Super Admin' : a.rel_domains.count - rows << [no.to_s, a.username, domains.to_s, a.active_str] + rows << [no.to_s, a.username, domains.to_s, a.active_str, a.scheme_prefix] end puts_table(headings: headings, rows: rows) end - def show_address(domain_name) - domain_check(domain_name) + def show_accounts(domain_name=nil) + domain_check(domain_name) if domain_name rows = [] - mailboxes = Domain.find(domain_name).rel_mailboxes - headings = ["No.", "Email", "Name", "Quota (MB)", "Active", "Maildir"] + mailboxes = if domain_name + Domain.find(domain_name).rel_mailboxes + else + Mailbox.all + end + headings = ["No.", "Email", "Name", "Quota (MB)", "Active", + "Scheme Prefix", "Maildir"] - puts_title("Addresses") + puts_title("Accounts") if mailboxes.empty? - puts "No addresses" + puts "No accounts" return end mailboxes.each_with_index do |m, i| no = i + 1 - rows << [no.to_s, m.username, m.name, m.quota_mb_str, - m.active_str, m.maildir] + rows << [no.to_s, m.username, m.name, m.quota_display_str, + m.active_str, m.scheme_prefix, m.maildir] end puts_table(headings: headings, rows: rows) end - def show_alias(domain_name) - domain_check(domain_name) + def show_forwards(domain_name=nil) + domain_check(domain_name) if domain_name - forwards, aliases = Domain.find(domain_name).rel_aliases.partition { |a| a.mailbox? } + forwards = if domain_name + Domain.find(domain_name).rel_aliases.forward + else + Alias.forward + end - forwards.delete_if do |f| - f.address == f.goto - end - show_alias_base("Forwards", forwards) - puts + end + + def show_aliases(domain_name=nil) + domain_check(domain_name) if domain_name + + aliases = if domain_name + Domain.find(domain_name).rel_aliases.pure + else + db_aliases = Alias.pure + end + show_alias_base("Aliases", aliases) end def show_admin_domain(user_name) admin = Admin.find(user_name) @@ -264,14 +287,18 @@ rows << [no.to_s, d.domain] end puts_table(rows: rows, headings: %w[No. Domain]) end - def add_admin(user_name, password, super_admin = false, scheme = nil) + def add_admin(user_name, password, super_admin: false, + scheme: nil, rounds: nil) validate_password(password) - @base.add_admin(user_name, hashed_password(password, scheme)) + h_password = hashed_password(password, user_name: user_name, + scheme: scheme, rounds: rounds) + @base.add_admin(user_name, h_password) + if super_admin Admin.find(user_name).super_admin = true puts_registered(user_name, "a super admin") else puts_registered(user_name, "an admin") @@ -286,48 +313,53 @@ def delete_admin_domain(user_name, domain_name) @base.delete_admin_domain(user_name, domain_name) puts "#{domain_name} was successfully deleted from #{user_name}" end - def add_account(address, password, scheme = nil, name = nil) + def add_account(address, password, name: nil, scheme: nil, rounds: nil) validate_password(password) - @base.add_account(address, hashed_password(password, scheme), name: name) + h_password = hashed_password(password, user_name: address, + scheme: scheme, rounds: rounds) + @base.add_account(address, h_password, name: name) puts_registered(address, "an account") end def add_alias(address, goto) @base.add_alias(address, goto) puts_registered("#{address}: #{goto}", "an alias") end def edit_account(address, options) + quota = options[:quota] + raise "Invalid Quota value: #{quota}" if quota && quota <= 0 + mailbox_check(address) mailbox = Mailbox.find(address) mailbox.name = options[:name] if options[:name] - mailbox.quota = options[:quota] * KB_TO_MB if options[:quota] + mailbox.quota_mb = quota if quota mailbox.active = options[:active] unless options[:active].nil? mailbox.save! if options[:goto] mail_alias = Alias.find(address) mail_alias.goto = options[:goto] mail_alias.save! end - puts "Successfully updated #{address}" + puts "successfully updated #{address}" show_account_details(address) end def edit_alias(address, options) alias_check(address) mail_alias = Alias.find(address) mail_alias.goto = options[:goto] if options[:goto] mail_alias.active = options[:active] unless options[:active].nil? mail_alias.save or raise "Could not save Alias" - puts "Successfully updated #{address}" + puts "successfully updated #{address}" show_alias_details(address) end def delete_alias(address) @base.delete_alias(address) @@ -426,15 +458,17 @@ puts_title(domain_name) puts_table(rows: rows) end def show_domain_details(domain_name) - show_admin(domain_name) + show_admins(domain_name) puts - show_address(domain_name) + show_accounts(domain_name) puts - show_alias(domain_name) + show_forwards(domain_name) + puts + show_aliases(domain_name) end def show_alias_base(title, addresses) rows = [] puts_title(title) @@ -522,26 +556,46 @@ if password.size < MIN_NUM_PASSWORD_CHARACTER raise ArgumentError, "Password is too short. It should be larger than #{MIN_NUM_PASSWORD_CHARACTER}" end end - def change_password(klass, user_name, password) + def change_password(klass, user_name, password, scheme: nil, rounds: nil) raise Error, "Could not find #{user_name}" unless klass.exists?(user_name) validate_password(password) obj = klass.find(user_name) + h_password = hashed_password(password, scheme: scheme, rounds: rounds, + user_name: user_name) - if obj.update(password: hashed_password(password)) - puts "the password of #{user_name} was successfully changed." + if obj.update(password: h_password) + puts "the password of #{user_name} was successfully updated." else raise "Could not change password of #{klass.name}" end end - def hashed_password(password, in_scheme = nil) + # The default number of rounds for BLF-CRYPT in `doveadm pw` is 5. + # However, this method uses 10 rounds by default, similar to + # the password_hash() function in PHP. + # + # https://www.php.net/manual/en/function.password-hash.php + # <?php + # echo password_hash("password", PASSWORD_BCRYPT); + # + # $2y$10$qzRgjWZWfH4VsNQGvp/DNObFSaMiZxXJSzgXqOOS/qtF68qIhhwFe + DEFAULT_BLF_CRYPT_ROUNDS = 10 + + # Generate a hashed password + def hashed_password(password, scheme: nil, rounds: nil, user_name: nil) prefix = @base.config[:passwordhash_prefix] - scheme = in_scheme || @base.config[:scheme] - PostfixAdmin::Doveadm.password(password, scheme, prefix) + new_scheme = scheme || @base.config[:scheme] + new_rounds = if rounds + rounds + elsif new_scheme == "BLF-CRYPT" + DEFAULT_BLF_CRYPT_ROUNDS + end + PostfixAdmin::Doveadm.password(password, new_scheme, rounds: new_rounds, + user_name: user_name, prefix: prefix) end end end