From 974f95f25ee9272b47a68e9a5f0fc73ff5da532a Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Thu, 24 Aug 2017 07:23:54 -0700 Subject: [PATCH 01/19] backport new bulk operations --- admin/mailu/admin/models.py | 18 +++++++++++++++--- admin/mailu/admin/views/__init__.py | 0 admin/manage.py | 21 +++++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 admin/mailu/admin/views/__init__.py diff --git a/admin/mailu/admin/models.py b/admin/mailu/admin/models.py index 9e4bcd10..e8085d98 100644 --- a/admin/mailu/admin/models.py +++ b/admin/mailu/admin/models.py @@ -163,16 +163,28 @@ class User(Base, Email): def get_id(self): return self.email + scheme_dict = {'SHA512-CRYPT': "sha512_crypt", + 'SHA256-CRYPT': "sha256_crypt", + 'MD5-CRYPT': "md5_crypt", + 'CRYPT': "des_crypt"} pw_context = context.CryptContext( - ["sha512_crypt", "sha256_crypt", "md5_crypt"] + schemes = scheme_dict.values(), + default='sha512_crypt', ) def check_password(self, password): reference = re.match('({[^}]+})?(.*)', self.password).group(2) return User.pw_context.verify(password, reference) - def set_password(self, password): - self.password = '{SHA512-CRYPT}' + User.pw_context.encrypt(password) + def set_password(self, password, hash_scheme='SHA512-CRYPT', raw=False): + """Set password for user with specified encryption scheme + @password: plain text password to encrypt (if raw == True the hash itself) + """ + # for the list of hash schemes see https://wiki2.dovecot.org/Authentication/PasswordSchemes + if raw: + self.password = '{'+hash_scheme+'}' + password + else: + self.password = '{'+hash_scheme+'}' + User.pw_context.encrypt(password, self.scheme_dict[hash_scheme]) def get_managed_domains(self): if self.global_admin: diff --git a/admin/mailu/admin/views/__init__.py b/admin/mailu/admin/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/admin/manage.py b/admin/manage.py index a277d719..b57b2e2d 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -35,7 +35,7 @@ def admin(localpart, domain_name, password): @manager.command -def user(localpart, domain_name, password): +def user(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): """ Create an user """ domain = models.Domain.query.get(domain_name) @@ -47,7 +47,24 @@ def user(localpart, domain_name, password): domain=domain, global_admin=False ) - user.set_password(password) + user.set_password(password, hash_scheme=hash_scheme) + db.session.add(user) + db.session.commit() + +@manager.command +def user_raw(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): + """ Create an user + """ + domain = models.Domain.query.get(domain_name) + if not domain: + domain = models.Domain(name=domain_name) + db.session.add(domain) + user = models.User( + localpart=localpart, + domain=domain, + global_admin=False + ) + user.set_password(password, hash_scheme=hash_scheme) db.session.add(user) db.session.commit() From 4dc2f896a2f0052a0c4adf5af79ab2a38f608b6e Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Thu, 24 Aug 2017 09:07:28 -0700 Subject: [PATCH 02/19] rename user_raw to user_import for more clarity. Add proper docstring --- admin/manage.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/admin/manage.py b/admin/manage.py index b57b2e2d..8ec6ade8 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -36,7 +36,7 @@ def admin(localpart, domain_name, password): @manager.command def user(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): - """ Create an user + """ Create a user """ domain = models.Domain.query.get(domain_name) if not domain: @@ -52,8 +52,12 @@ def user(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): db.session.commit() @manager.command -def user_raw(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): - """ Create an user +def user_import(localpart, domain_name, password_hash, hash_scheme='SHA512-CRYPT'): + """ Import a user along with password hash. Available hashes: + 'SHA512-CRYPT' + 'SHA256-CRYPT' + 'MD5-CRYPT' + 'CRYPT' """ domain = models.Domain.query.get(domain_name) if not domain: @@ -64,7 +68,7 @@ def user_raw(localpart, domain_name, password, hash_scheme='SHA512-CRYPT'): domain=domain, global_admin=False ) - user.set_password(password, hash_scheme=hash_scheme) + user.set_password(password_hash, hash_scheme=hash_scheme, raw=True) db.session.add(user) db.session.commit() From 59bc07cde515cdf9104d21c5cde99db462e9343e Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 25 Aug 2017 12:44:05 -0700 Subject: [PATCH 03/19] add config sync for bulk operations on users and aliases driven by config management systems etc. --- admin/manage.py | 48 ++++++++++++++++++++++++++++++++++++++++++ admin/requirements.txt | 1 + 2 files changed, 49 insertions(+) diff --git a/admin/manage.py b/admin/manage.py index 8ec6ade8..bb3c4a5e 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -72,6 +72,54 @@ def user_import(localpart, domain_name, password_hash, hash_scheme='SHA512-CRYPT db.session.add(user) db.session.commit() +@manager.command +def config_update(): + """sync configuration with data from stdin""" + import yaml, sys + new_config=yaml.load(sys.stdin) + # print new_config + users=new_config['users'] + for user_config in users: + localpart=user_config['localpart'] + domain_name=user_config['domain'] + password_hash=user_config['password_hash'] + hash_scheme=user_config['hash_scheme'] + domain = models.Domain.query.get(domain_name) + if not domain: + domain = models.Domain(name=domain_name) + db.session.add(domain) + user = models.User.query.get('{0}@{1}'.format(localpart,domain_name)) + if not user: + user = models.User( + localpart=localpart, + domain=domain, + global_admin=False + ) + user.set_password(password_hash, hash_scheme=hash_scheme, raw=True) + db.session.add(user) + + aliases=new_config['aliases'] + for alias_config in aliases: + localpart=alias_config['localpart'] + domain_name=alias_config['domain'] + destination=alias_config['destination'] + domain = models.Domain.query.get(domain_name) + if not domain: + domain = models.Domain(name=domain_name) + db.session.add(domain) + alias = models.Alias.query.get('{0}@{1}'.format(localpart, domain_name)) + if not alias: + alias = models.Alias( + localpart=localpart, + domain=domain, + destination=destination.split(','), + email="%s@%s" % (localpart, domain_name) + ) + else: + alias.destination = destination.split(',') + db.session.add(alias) + + db.session.commit() @manager.command def alias(localpart, domain_name, destination): diff --git a/admin/requirements.txt b/admin/requirements.txt index f5337d48..3d0ce119 100644 --- a/admin/requirements.txt +++ b/admin/requirements.txt @@ -14,3 +14,4 @@ docker-py tabulate apscheduler certbot +PyYAML From 28f490ddee6c05056c18664196f25265a04f5224 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 25 Aug 2017 13:07:07 -0700 Subject: [PATCH 04/19] added object deletion to config update --- admin/manage.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/admin/manage.py b/admin/manage.py index bb3c4a5e..53d5c7f1 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -73,22 +73,25 @@ def user_import(localpart, domain_name, password_hash, hash_scheme='SHA512-CRYPT db.session.commit() @manager.command -def config_update(): - """sync configuration with data from stdin""" +def config_update(delete_objects=False): + """sync configuration with data from YAML-formatted stdin""" import yaml, sys new_config=yaml.load(sys.stdin) # print new_config users=new_config['users'] + tracked_users=set() for user_config in users: localpart=user_config['localpart'] domain_name=user_config['domain'] password_hash=user_config['password_hash'] hash_scheme=user_config['hash_scheme'] domain = models.Domain.query.get(domain_name) + email='{0}@{1}'.format(localpart,domain_name) if not domain: domain = models.Domain(name=domain_name) db.session.add(domain) - user = models.User.query.get('{0}@{1}'.format(localpart,domain_name)) + user = models.User.query.get(email) + tracked_users.add(email) if not user: user = models.User( localpart=localpart, @@ -99,26 +102,36 @@ def config_update(): db.session.add(user) aliases=new_config['aliases'] + tracked_aliases=set() for alias_config in aliases: localpart=alias_config['localpart'] domain_name=alias_config['domain'] destination=alias_config['destination'] domain = models.Domain.query.get(domain_name) + email='{0}@{1}'.format(localpart,domain_name) if not domain: domain = models.Domain(name=domain_name) db.session.add(domain) - alias = models.Alias.query.get('{0}@{1}'.format(localpart, domain_name)) + alias = models.Alias.query.get(email) + tracked_aliases.add(email) if not alias: alias = models.Alias( localpart=localpart, domain=domain, destination=destination.split(','), - email="%s@%s" % (localpart, domain_name) + email=email ) else: alias.destination = destination.split(',') db.session.add(alias) + if delete_objects: + for user in db.session.query(models.User).all(): + if not ( user.email in tracked_users ): + db.session.delete(user) + for alias in db.session.query(models.Alias).all(): + if not ( alias.email in tracked_aliases ): + db.session.delete(alias) db.session.commit() @manager.command From 95fd89808c5224e01abf3f5aabde5fe91d1a7306 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 25 Aug 2017 14:38:16 -0700 Subject: [PATCH 05/19] add more CLI operations: deletions of users and aliases --- admin/manage.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/admin/manage.py b/admin/manage.py index 53d5c7f1..02dc0f11 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -134,6 +134,22 @@ def config_update(delete_objects=False): db.session.delete(alias) db.session.commit() +@manager.command +def user_delete(email): + """delete user""" + user = models.User.query.get(email) + if user: + db.session.delete(user) + db.session.commit() + +@manager.command +def alias_delete(email): + """delete alias""" + alias = models.Alias.query.get(email) + if alias: + db.session.delete(alias) + db.session.commit() + @manager.command def alias(localpart, domain_name, destination): """ Create an alias From 6525969a56e726461439372ed0297bd8814e5c4b Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 25 Aug 2017 14:48:36 -0700 Subject: [PATCH 06/19] ignoring virtualenv artefacts etc. --- admin/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 admin/.gitignore diff --git a/admin/.gitignore b/admin/.gitignore new file mode 100644 index 00000000..5bb3bd8e --- /dev/null +++ b/admin/.gitignore @@ -0,0 +1,4 @@ +.fg/ +lib64 +.vscode +tags From fcf37e6d5e506668930901e89f377ce9e95966e8 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 25 Aug 2017 14:49:27 -0700 Subject: [PATCH 07/19] ignore vscode artefacts --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b5f73c9f..eb84ec09 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ pip-selfcheck.json /data /docker-compose.mac.yml /docker-compose.yml -/.idea \ No newline at end of file +/.idea +/.vscode From e28285155ef5dd5ebdfd9376550a2acdd31df88a Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Mon, 11 Sep 2017 09:11:12 -0700 Subject: [PATCH 08/19] Expect list instead of string for destination --- admin/manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/manage.py b/admin/manage.py index 02dc0f11..717d1d80 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -118,7 +118,7 @@ def config_update(delete_objects=False): alias = models.Alias( localpart=localpart, domain=domain, - destination=destination.split(','), + # destination=destination.split(','), email=email ) else: From e6a92af806d2ab17e6b4ff4c39aacd80fcb72f10 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Mon, 11 Sep 2017 09:48:35 -0700 Subject: [PATCH 09/19] add verbosity level configuration option --- admin/manage.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/admin/manage.py b/admin/manage.py index 717d1d80..76bfe9a4 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -73,7 +73,7 @@ def user_import(localpart, domain_name, password_hash, hash_scheme='SHA512-CRYPT db.session.commit() @manager.command -def config_update(delete_objects=False): +def config_update(verbose=False, delete_objects=False): """sync configuration with data from YAML-formatted stdin""" import yaml, sys new_config=yaml.load(sys.stdin) @@ -81,6 +81,8 @@ def config_update(delete_objects=False): users=new_config['users'] tracked_users=set() for user_config in users: + if verbose: + print user_config localpart=user_config['localpart'] domain_name=user_config['domain'] password_hash=user_config['password_hash'] @@ -104,6 +106,8 @@ def config_update(delete_objects=False): aliases=new_config['aliases'] tracked_aliases=set() for alias_config in aliases: + if verbose: + print alias_config localpart=alias_config['localpart'] domain_name=alias_config['domain'] destination=alias_config['destination'] From e6bedabef07bca4b40bc3cd318886b4e7498f3a1 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Mon, 11 Sep 2017 14:06:00 -0700 Subject: [PATCH 10/19] fix print call --- admin/manage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/manage.py b/admin/manage.py index 76bfe9a4..9ac3079a 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -82,7 +82,7 @@ def config_update(verbose=False, delete_objects=False): tracked_users=set() for user_config in users: if verbose: - print user_config + print(str(user_config)) localpart=user_config['localpart'] domain_name=user_config['domain'] password_hash=user_config['password_hash'] @@ -107,7 +107,7 @@ def config_update(verbose=False, delete_objects=False): tracked_aliases=set() for alias_config in aliases: if verbose: - print alias_config + print(str(alias_config)) localpart=alias_config['localpart'] domain_name=alias_config['domain'] destination=alias_config['destination'] From 9ddfa0a63399000e6bbf3a9a0d9ae93ef358cac6 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Tue, 19 Sep 2017 08:05:10 -0700 Subject: [PATCH 11/19] adjust ciphers to a more secure set --- dovecot/conf/dovecot.conf | 3 ++- nginx/nginx.conf.default | 7 ++++--- nginx/nginx.conf.fallback | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dovecot/conf/dovecot.conf b/dovecot/conf/dovecot.conf index 0f4b04d8..36471272 100644 --- a/dovecot/conf/dovecot.conf +++ b/dovecot/conf/dovecot.conf @@ -61,7 +61,8 @@ ssl_key = Date: Tue, 19 Sep 2017 08:27:19 -0700 Subject: [PATCH 12/19] be smarted about destination field --- admin/manage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin/manage.py b/admin/manage.py index 9ac3079a..0ba3501f 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -126,7 +126,10 @@ def config_update(verbose=False, delete_objects=False): email=email ) else: - alias.destination = destination.split(',') + if type(destination) == type(""): + alias.destination = destination.split(',') + else: + alias.destination = destination db.session.add(alias) if delete_objects: From b3d961a3dc07a7aa6e5946dd300cd5ddddef612c Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Thu, 21 Sep 2017 23:56:15 -0700 Subject: [PATCH 13/19] adding nginx modularity --- nginx/Dockerfile | 2 ++ nginx/extra.d/.keep | 0 nginx/http.d/.keep | 0 nginx/nginx.conf.default | 3 +++ nginx/nginx.conf.fallback | 4 ++++ 5 files changed, 9 insertions(+) create mode 100644 nginx/extra.d/.keep create mode 100644 nginx/http.d/.keep diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 15d00972..2a8308f9 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -4,6 +4,8 @@ RUN apk add --no-cache nginx-mod-http-lua openssl COPY nginx.conf.default /etc/nginx/nginx.conf.default COPY nginx.conf.fallback /etc/nginx/nginx.conf.fallback +COPY http.d /etc/nginx/ +COPY extra.d /etc/nginx/ COPY start.sh /start.sh diff --git a/nginx/extra.d/.keep b/nginx/extra.d/.keep new file mode 100644 index 00000000..e69de29b diff --git a/nginx/http.d/.keep b/nginx/http.d/.keep new file mode 100644 index 00000000..e69de29b diff --git a/nginx/nginx.conf.default b/nginx/nginx.conf.default index 2dd4729c..87982712 100644 --- a/nginx/nginx.conf.default +++ b/nginx/nginx.conf.default @@ -50,6 +50,7 @@ http { set_by_lua $webdav 'return os.getenv("WEBDAV")'; set_by_lua $expose_admin 'return os.getenv("EXPOSE_ADMIN")'; + include http.d/*.conf; # Actual logic location / { @@ -97,3 +98,5 @@ http { } } } + +include extra.d/*.conf; diff --git a/nginx/nginx.conf.fallback b/nginx/nginx.conf.fallback index 985c6189..50bb77cb 100644 --- a/nginx/nginx.conf.fallback +++ b/nginx/nginx.conf.fallback @@ -36,6 +36,8 @@ http { add_header Strict-Transport-Security max-age=15768000; + include http.d/*.conf; + if ($scheme = http) { return 301 https://$host$request_uri; } @@ -45,3 +47,5 @@ http { } } } + +include extra.d/*.conf; From d4cf5430e898905a842943da6ff973ee84a1bf3e Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Fri, 22 Sep 2017 00:50:42 -0700 Subject: [PATCH 14/19] nginx is gone --- nginx/extra.d/.keep | 0 nginx/http.d/.keep | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 nginx/extra.d/.keep delete mode 100644 nginx/http.d/.keep diff --git a/nginx/extra.d/.keep b/nginx/extra.d/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/nginx/http.d/.keep b/nginx/http.d/.keep deleted file mode 100644 index e69de29b..00000000 From 5e55182b90bb59fd97d0928cd348e44c26a339f4 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Mon, 25 Sep 2017 06:59:01 -0700 Subject: [PATCH 15/19] fix type check as per pull request comment --- admin/manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/manage.py b/admin/manage.py index 97f3f3bf..e6a946a4 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -98,7 +98,7 @@ def config_update(verbose=False, delete_objects=False): localpart=alias_config['localpart'] domain_name=alias_config['domain'] pre_destination=alias_config['destination'] - if type(pre_destination) == type(""): + if type(pre_destination) is str: destination = pre_destination.split(',') else: destination = pre_destination From ce2ad32efc02dbdd03f90653872b803d772c2822 Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Tue, 26 Sep 2017 13:20:33 -0700 Subject: [PATCH 16/19] add manager/domain configuration sync --- admin/manage.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/admin/manage.py b/admin/manage.py index e6a946a4..e905c993 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -19,7 +19,6 @@ def admin(localpart, domain_name, password): db.session.add(user) db.session.commit() - @manager.command def user(localpart, domain_name, password, hash_scheme=app.config['PASSWORD_SCHEME']): """ Create a user @@ -37,6 +36,13 @@ def user(localpart, domain_name, password, hash_scheme=app.config['PASSWORD_SCHE db.session.add(user) db.session.commit() +@manager.command +def domain(domain_name, max_users=0, max_aliases=0, max_quota_bytes=0): + domain = models.Domain.query.get(domain_name) + if not domain: + domain = models.Domain(name=domain_name) + db.session.add(domain) + db.session.commit() @manager.command def user_import(localpart, domain_name, password_hash, hash_scheme=app.config['PASSWORD_SCHEME']): @@ -65,7 +71,31 @@ def config_update(verbose=False, delete_objects=False): import yaml, sys new_config=yaml.load(sys.stdin) # print new_config - users=new_config['users'] + domains=new_config.get('domains',[]) + tracked_domains=set() + for domain_config in domains: + if verbose: + print(str(domain_config)) + domain_name = domain_config['name'] + max_users=domain_config.get('max_users',0) + max_aliases=domain_config.get('max_aliases',0) + max_quota_bytes=domain_config.get('max_quota_bytes',0) + tracked_domains.add(domain_name) + domain = models.Domain.query.get(domain_name) + if not domain: + domain = models.Domain(name=domain_name, + max_users=max_users, + max_aliases=max_aliases, + max_quota_bytes=max_quota_bytes) + db.session.add(domain) + else: + domain.max_users = max_users + domain.max_aliases = max_aliases + domain.max_quota_bytes = max_quota_bytes + db.session.add(domain) + + + users=new_config.get('users',[]) tracked_users=set() for user_config in users: if verbose: @@ -81,6 +111,7 @@ def config_update(verbose=False, delete_objects=False): db.session.add(domain) user = models.User.query.get(email) tracked_users.add(email) + tracked_domains.add(domain_name) if not user: user = models.User( localpart=localpart, @@ -90,7 +121,7 @@ def config_update(verbose=False, delete_objects=False): user.set_password(password_hash, hash_scheme=hash_scheme, raw=True) db.session.add(user) - aliases=new_config['aliases'] + aliases=new_config.get('aliases',[]) tracked_aliases=set() for alias_config in aliases: if verbose: @@ -109,6 +140,7 @@ def config_update(verbose=False, delete_objects=False): db.session.add(domain) alias = models.Alias.query.get(email) tracked_aliases.add(email) + tracked_domains.add(domain_name) if not alias: alias = models.Alias( localpart=localpart, @@ -119,6 +151,18 @@ def config_update(verbose=False, delete_objects=False): else: alias.destination = destination db.session.add(alias) + + managers=new_config.get('managers',[]) + # tracked_managers=set() + for manager_config in managers: + if verbose: + print(str(manager_config)) + domain_name = manager_config['domain'] + user_name = manage_config['user'] + domain = models.Domain.query.get(domain_name) + manageruser = models.User.query.get(user_name + '@' + domain_name) + domain.managers.append(manageruser) + db.session.add(domain) if delete_objects: for user in db.session.query(models.User).all(): @@ -127,6 +171,9 @@ def config_update(verbose=False, delete_objects=False): for alias in db.session.query(models.Alias).all(): if not ( alias.email in tracked_aliases ): db.session.delete(alias) + for domain in db.session.query(models.Domain).all(): + if not ( domain.name in tracked_domains ): + db.session.delete(domain) db.session.commit() @manager.command From 1ee4f5db15443cffbc5ca1368647ff8584cecc1d Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Tue, 26 Sep 2017 14:18:37 -0700 Subject: [PATCH 17/19] fix domain command invocation --- admin/manage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin/manage.py b/admin/manage.py index e905c993..1a400d61 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -36,7 +36,10 @@ def user(localpart, domain_name, password, hash_scheme=app.config['PASSWORD_SCHE db.session.add(user) db.session.commit() -@manager.command +@manager.option('-n','--domain_name',dest='domain_name') +@manager.option('-u','--max_users',dest='max_users') +@manager.option('-a','--max_aliases',dest='max_aliases') +@manager.option('-q','--max_quota_bytes',dest='max_quota_bytes') def domain(domain_name, max_users=0, max_aliases=0, max_quota_bytes=0): domain = models.Domain.query.get(domain_name) if not domain: From b64582b456c7ada5f23e9640492448e82ccb724d Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Wed, 27 Sep 2017 07:28:39 -0700 Subject: [PATCH 18/19] retracting dovecot cipher settings --- dovecot/conf/dovecot.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dovecot/conf/dovecot.conf b/dovecot/conf/dovecot.conf index 3260393a..faa41bf7 100644 --- a/dovecot/conf/dovecot.conf +++ b/dovecot/conf/dovecot.conf @@ -65,8 +65,7 @@ ssl_dh_parameters_length = 2048 # TLS hardening is based on the following documentation: # https://bettercrypto.org/static/applied-crypto-hardening.pdf ssl_protocols=!SSLv3 !SSLv2 -# ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA -ssl_cipher_list = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:EDH+aRSA:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS +ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA ssl_prefer_server_ciphers = yes ssl_options = no_compression From 2ffd7793243d619b6904126ef0d98ecdc878b9ea Mon Sep 17 00:00:00 2001 From: Dmytro Makovey Date: Wed, 27 Sep 2017 11:04:19 -0700 Subject: [PATCH 19/19] add some fail-safe for empty passwords --- admin/manage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/manage.py b/admin/manage.py index 1a400d61..13b7b7a0 100644 --- a/admin/manage.py +++ b/admin/manage.py @@ -105,8 +105,8 @@ def config_update(verbose=False, delete_objects=False): print(str(user_config)) localpart=user_config['localpart'] domain_name=user_config['domain'] - password_hash=user_config['password_hash'] - hash_scheme=user_config['hash_scheme'] + password_hash=user_config.get('password_hash',None) + hash_scheme=user_config.get('hash_scheme',None) domain = models.Domain.query.get(domain_name) email='{0}@{1}'.format(localpart,domain_name) if not domain: