diff --git a/core/admin/mailu/debug.py b/core/admin/mailu/debug.py index c45f4ae7..4d63f3c5 100644 --- a/core/admin/mailu/debug.py +++ b/core/admin/mailu/debug.py @@ -1,11 +1,10 @@ -#Note: Currently flask_debugtoolbar is not compatible with flask. -#import flask_debugtoolbar +import flask_debugtoolbar from werkzeug.middleware.profiler import ProfilerMiddleware # Debugging toolbar -#toolbar = flask_debugtoolbar.DebugToolbarExtension() +toolbar = flask_debugtoolbar.DebugToolbarExtension() # Profiler diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index 824ee971..2cad7afb 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -14,6 +14,7 @@ import passlib.context import passlib.hash import passlib.registry import time +import logging import os import smtplib import idna @@ -30,6 +31,10 @@ from werkzeug.utils import cached_property from mailu import dkim, utils +# silence AttributeError: module 'bcrypt' has no attribute '__about__' +logging.getLogger('passlib').setLevel(logging.ERROR) + + db = flask_sqlalchemy.SQLAlchemy() @@ -159,13 +164,6 @@ class Base(db.Model): flag_modified(self, 'updated_at') -# Many-to-many association table for domain managers -managers = db.Table('manager', Base.metadata, - db.Column('domain_name', IdnaDomain, db.ForeignKey('domain.name')), - db.Column('user_email', IdnaEmail, db.ForeignKey('user.email')) -) - - class Config(Base): """ In-database configuration values """ @@ -180,6 +178,10 @@ def _save_dkim_keys(session): if isinstance(obj, Domain): obj.save_dkim_key() +def _get_managers(): + return managers + + class Domain(Base): """ A DNS domain that has mail addresses associated to it. """ @@ -187,7 +189,7 @@ class Domain(Base): __tablename__ = 'domain' name = db.Column(IdnaDomain, primary_key=True, nullable=False) - managers = db.relationship('User', secondary=managers, + managers = db.relationship('User', secondary=_get_managers, backref=db.backref('manager_of'), lazy='dynamic') max_users = db.Column(db.Integer, nullable=False, default=-1) max_aliases = db.Column(db.Integer, nullable=False, default=-1) @@ -790,6 +792,13 @@ class Fetch(Base): ) +# Many-to-many association table for domain managers +managers = db.Table('manager', Base.metadata, + db.Column('domain_name', IdnaDomain, db.ForeignKey(Domain.name)), + db.Column('user_email', IdnaEmail, db.ForeignKey(User.email)) +) + + class MailuConfig: """ Class which joins whole Mailu config for dumping and loading diff --git a/core/admin/mailu/sso/views/base.py b/core/admin/mailu/sso/views/base.py index 33d4d4f4..b347d3cb 100644 --- a/core/admin/mailu/sso/views/base.py +++ b/core/admin/mailu/sso/views/base.py @@ -9,8 +9,7 @@ import flask import flask_login import secrets import ipaddress -from urllib.parse import urlparse, urljoin -from werkzeug.urls import url_unquote +from urllib.parse import urlparse, urljoin, unquote @sso.route('/login', methods=['GET', 'POST']) def login(): @@ -120,8 +119,7 @@ def _has_usable_redirect(is_proxied=False): if 'homepage' in flask.request.url and not is_proxied: return None if url := flask.request.args.get('url'): - url = url_unquote(url) - target = urlparse(urljoin(flask.request.url, url)) + target = urlparse(urljoin(flask.request.url, unquote(url))) if target.netloc == urlparse(flask.request.url).netloc: return target.geturl() return None diff --git a/core/admin/mailu/utils.py b/core/admin/mailu/utils.py index 9f75c233..13522d79 100644 --- a/core/admin/mailu/utils.py +++ b/core/admin/mailu/utils.py @@ -412,8 +412,8 @@ class MailuSessionInterface(SessionInterface): # save session and update cookie if necessary if session.save(): response.set_cookie( - app.config['SESSION_COOKIE_NAME'], - session.sid, + app.config['SESSION_COOKIE_NAME'], + session.sid.decode('ascii'), expires=datetime.now()+timedelta(seconds=app.config['PERMANENT_SESSION_LIFETIME']), httponly=self.get_cookie_httponly(app), domain=self.get_cookie_domain(app), diff --git a/core/base/requirements-dev.txt b/core/base/requirements-dev.txt index be4d9a31..6ac3daac 100644 --- a/core/base/requirements-dev.txt +++ b/core/base/requirements-dev.txt @@ -16,7 +16,7 @@ Flask-Login flask-marshmallow Flask-Migrate Flask-RESTX -Flask-SQLAlchemy<3 +Flask-SQLAlchemy Flask-WTF gunicorn idna diff --git a/core/base/requirements-prod.txt b/core/base/requirements-prod.txt index 2d5b0002..1883b906 100644 --- a/core/base/requirements-prod.txt +++ b/core/base/requirements-prod.txt @@ -1,68 +1,64 @@ aiodns==3.1.1 -aiohttp==3.8.6 +aiohttp==3.9.1 aiosignal==1.3.1 -alembic==1.12.1 +alembic==1.13.1 aniso8601==9.0.1 -async-timeout==4.0.3 -attrs==23.1.0 -Babel==2.13.1 -bcrypt==4.0.1 -blinker==1.6.3 -certifi==2023.7.22 +attrs==23.2.0 +Babel==2.14.0 +bcrypt==4.1.2 +blinker==1.7.0 +certifi==2023.11.17 cffi==1.16.0 -charset-normalizer==3.3.1 +charset-normalizer==3.3.2 click==8.1.7 colorclass==2.2.2 -cryptography==41.0.5 +cryptography==41.0.7 defusedxml==0.7.1 Deprecated==1.2.14 -dnspython==2.4.2 -dominate==2.8.0 +dnspython==2.5.0 +dominate==2.9.1 easygui==0.98.3 email-validator==2.1.0.post1 -Flask==2.3.3 +Flask==3.0.1 flask-babel==4.0.0 Flask-Bootstrap==3.3.7.1 -#Flask-DebugToolbar is not compatible with Flask 2.3.3+ -#Flask-DebugToolbar==0.13.1 +Flask-DebugToolbar==0.14.1 Flask-Login==0.6.3 -flask-marshmallow==0.15.0 +flask-marshmallow==1.1.0 Flask-Migrate==4.0.5 -flask-restx==1.1.0 -Flask-SQLAlchemy==2.5.1 -# >2.5.1 bug with parsing models.py. Could otherwise be 3.0.5 +flask-restx==1.3.0 +Flask-SQLAlchemy==3.1.1 Flask-WTF==1.2.1 -frozenlist==1.4.0 -greenlet==3.0.1 +frozenlist==1.4.1 +greenlet==3.0.3 gunicorn==21.2.0 -idna==3.4 -importlib-resources==6.1.0 +idna==3.6 +importlib-resources==6.1.1 infinity==1.5 intervals==0.9.2 itsdangerous==2.1.2 -Jinja2==3.1.2 -jsonschema==4.19.2 -jsonschema-specifications==2023.7.1 -limits==3.6.0 -Mako==1.2.4 -MarkupSafe==2.1.3 -marshmallow==3.20.1 -marshmallow-sqlalchemy==0.29 -msoffcrypto-tool==5.1.1 +Jinja2==3.1.3 +jsonschema==4.21.1 +jsonschema-specifications==2023.12.1 +limits==3.7.0 +Mako==1.3.0 +MarkupSafe==2.1.4 +marshmallow==3.20.2 +marshmallow-sqlalchemy==0.30.0 +msoffcrypto-tool==5.3.1 multidict==6.0.4 -mysql-connector-python==8.2.0 -olefile==0.46 +mysql-connector-python==8.3.0 +olefile==0.47 oletools==0.60.1 packaging==23.2 passlib==1.7.4 pcodedmp==1.2.6 podop @ file:///app/libs/podop postfix-mta-sts-resolver==1.4.0 -protobuf==4.21.12 psycopg2-binary==2.9.9 pycares==4.4.0 pycparser==2.21 -Pygments==2.16.1 +Pygments==2.17.2 pyparsing==2.4.7 python-dateutil==2.8.2 python-magic==0.4.27 @@ -70,24 +66,24 @@ pytz==2023.3.post1 PyYAML==6.0.1 Radicale==3.1.8 redis==5.0.1 -referencing==0.30.2 +referencing==0.32.1 requests==2.31.0 -rpds-py==0.10.6 +rpds-py==0.17.1 six==1.16.0 socrate @ file:///app/libs/socrate -SQLAlchemy==1.4.50 +SQLAlchemy==2.0.25 srslib==0.1.4 tabulate==0.9.0 tenacity==8.2.3 -typing_extensions==4.8.0 -urllib3==2.0.7 +typing_extensions==4.9.0 +urllib3==2.1.0 validators==0.22.0 visitor==0.1.3 vobject==0.9.6.1 watchdog==3.0.0 -Werkzeug===2.3.7 -wrapt==1.15.0 -WTForms==3.1.1 +Werkzeug==3.0.1 +wrapt==1.16.0 +WTForms==3.1.2 WTForms-Components==0.10.5 xmltodict==0.13.0 -yarl==1.9.2 +yarl==1.9.4