1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-22 22:31:40 +00:00

Add jinja2 filters urlencode and escape_quotes

This commit is contained in:
FreddleSpl0it
2025-05-31 21:48:36 +02:00
parent e8d155d7e0
commit 744aa5d137
8 changed files with 40 additions and 32 deletions

View File

@@ -13,6 +13,7 @@ import hashlib
import json import json
import psutil import psutil
import signal import signal
from urllib.parse import quote
from pathlib import Path from pathlib import Path
import dns.resolver import dns.resolver
import mysql.connector import mysql.connector
@@ -89,17 +90,19 @@ class BootstrapBase:
def prepare_template_vars(self, overwrite_path, extra_vars = None): def prepare_template_vars(self, overwrite_path, extra_vars = None):
""" """
Loads and merges environment variables for Jinja2 templates from multiple sources. Loads and merges environment variables for Jinja2 templates from multiple sources, and registers custom template filters.
This method combines: This method combines variables from:
1. System environment variables 1. System environment variables
2. Key/value pairs from the MySQL `service_settings` table 2. The MySQL `service_settings` table (filtered by service type if defined)
3. An optional dictionary of extra_vars 3. An optional `extra_vars` dictionary
4. A JSON file with overrides (if the file exists) 4. A JSON overwrite file (if it exists at the given path)
Also registers custom Jinja2 filters.
Args: Args:
overwrite_path (str or Path): Path to a JSON file containing key-value overrides. overwrite_path (str or Path): Path to a JSON file containing key-value overrides.
extra_vars (dict, optional): A dictionary of additional variables to include. extra_vars (dict, optional): Additional variables to merge into the environment.
Returns: Returns:
dict: A dictionary containing all resolved template variables. dict: A dictionary containing all resolved template variables.
@@ -108,10 +111,15 @@ class BootstrapBase:
Prints errors if database fetch or JSON parsing fails, but does not raise exceptions. Prints errors if database fetch or JSON parsing fails, but does not raise exceptions.
""" """
# 1. Load env vars # 1. setup filters
self.env.filters['sha1'] = self.sha1_filter
self.env.filters['urlencode'] = self.urlencode_filter
self.env.filters['escape_quotes'] = self.escape_quotes_filter
# 2. Load env vars
env_vars = dict(os.environ) env_vars = dict(os.environ)
# 2. Load from MySQL # 3. Load from MySQL
try: try:
cursor = self.mysql_conn.cursor() cursor = self.mysql_conn.cursor()
@@ -129,11 +137,11 @@ class BootstrapBase:
except Exception as e: except Exception as e:
print(f"Failed to fetch DB service settings: {e}") print(f"Failed to fetch DB service settings: {e}")
# 3. Load extra vars # 4. Load extra vars
if extra_vars: if extra_vars:
env_vars.update(extra_vars) env_vars.update(extra_vars)
# 4. Load overwrites # 5. Load overwrites
overwrite_path = Path(overwrite_path) overwrite_path = Path(overwrite_path)
if overwrite_path.exists(): if overwrite_path.exists():
try: try:
@@ -810,3 +818,9 @@ class BootstrapBase:
def sha1_filter(self, value): def sha1_filter(self, value):
return hashlib.sha1(value.encode()).hexdigest() return hashlib.sha1(value.encode()).hexdigest()
def urlencode_filter(self, value):
return quote(value, safe='')
def escape_quotes_filter(self, value):
return value.replace('"', r'\"')

View File

@@ -45,10 +45,6 @@ class BootstrapDovecot(BootstrapBase):
"ENV_VARS": dict(os.environ) "ENV_VARS": dict(os.environ)
} }
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars) self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
# Escape DBPASS
self.env_vars['DBPASS'] = self.env_vars['DBPASS'].replace('"', r'\"')
# Set custom filters
self.env.filters['sha1'] = self.sha1_filter
print("Set Timezone") print("Set Timezone")
self.set_timezone() self.set_timezone()

View File

@@ -1,5 +1,5 @@
{% set QUOTA_TABLE = "quota2" if MASTER|lower in ["y", "yes"] else "quota2replica" %} {% set QUOTA_TABLE = "quota2" if MASTER|lower in ["y", "yes"] else "quota2replica" %}
connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS }}" connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS | escape_quotes }}"
map { map {
pattern = priv/quota/storage pattern = priv/quota/storage
table = {{ QUOTA_TABLE }} table = {{ QUOTA_TABLE }}

View File

@@ -1,4 +1,4 @@
connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS }}" connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS | escape_quotes }}"
map { map {
pattern = priv/sieve/name/$script_name pattern = priv/sieve/name/$script_name
table = sieve_after table = sieve_after

View File

@@ -1,4 +1,4 @@
connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS }}" connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS | escape_quotes }}"
map { map {
pattern = priv/sieve/name/$script_name pattern = priv/sieve/name/$script_name
table = sieve_before table = sieve_before

View File

@@ -1,4 +1,4 @@
driver = mysql driver = mysql
connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS }}" connect = "host=/var/run/mysqld/mysqld.sock dbname={{ DBNAME }} user={{ DBUSER }} password={{ DBPASS | escape_quotes }}"
user_query = SELECT CONCAT(JSON_UNQUOTE(JSON_VALUE(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%n/{{ MAILDIR_SUB }}:VOLATILEDIR=/var/volatile/%u:INDEX=/var/vmail_index/%u') AS mail, '%s' AS protocol, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND (active = '1' OR active = '2') user_query = SELECT CONCAT(JSON_UNQUOTE(JSON_VALUE(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%n/{{ MAILDIR_SUB }}:VOLATILEDIR=/var/volatile/%u:INDEX=/var/vmail_index/%u') AS mail, '%s' AS protocol, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND (active = '1' OR active = '2')
iterate_query = SELECT username FROM mailbox WHERE active = '1' OR active = '2'; iterate_query = SELECT username FROM mailbox WHERE active = '1' OR active = '2';

View File

@@ -3,7 +3,7 @@
<plist version="0.9"> <plist version="0.9">
<dict> <dict>
<key>OCSAclURL</key> <key>OCSAclURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_acl</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_acl</string>
<key>SOGoIMAPServer</key> <key>SOGoIMAPServer</key>
<string>imap://{{ DOVECOT_HOST }}:143/?TLS=YES&amp;tlsVerifyMode=none</string> <string>imap://{{ DOVECOT_HOST }}:143/?TLS=YES&amp;tlsVerifyMode=none</string>
<key>SOGoSieveServer</key> <key>SOGoSieveServer</key>
@@ -15,19 +15,19 @@
<key>SOGoEncryptionKey</key> <key>SOGoEncryptionKey</key>
<string>{{RAND_PASS}}</string> <string>{{RAND_PASS}}</string>
<key>OCSAdminURL</key> <key>OCSAdminURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_admin</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_admin</string>
<key>OCSCacheFolderURL</key> <key>OCSCacheFolderURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_cache_folder</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_cache_folder</string>
<key>OCSEMailAlarmsFolderURL</key> <key>OCSEMailAlarmsFolderURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_alarms_folder</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_alarms_folder</string>
<key>OCSFolderInfoURL</key> <key>OCSFolderInfoURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_folder_info</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_folder_info</string>
<key>OCSSessionsFolderURL</key> <key>OCSSessionsFolderURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_sessions_folder</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_sessions_folder</string>
<key>OCSStoreURL</key> <key>OCSStoreURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_store</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_store</string>
<key>SOGoProfileURL</key> <key>SOGoProfileURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/sogo_user_profile</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/sogo_user_profile</string>
<key>SOGoTimeZone</key> <key>SOGoTimeZone</key>
<string>{{TZ}}</string> <string>{{TZ}}</string>
<key>domains</key> <key>domains</key>
@@ -69,7 +69,7 @@
<key>prependPasswordScheme</key> <key>prependPasswordScheme</key>
<string>YES</string> <string>YES</string>
<key>viewURL</key> <key>viewURL</key>
<string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST }}/{{ DBNAME }}/_sogo_static_view</string> <string>mysql://{{ DBUSER }}:{{ DBPASS }}@{{ DB_HOST | urlencode }}/{{ DBNAME }}/_sogo_static_view</string>
</dict> </dict>
{% if IAM_SETTINGS.authsource == "ldap" and domain.ldap_gal %} {% if IAM_SETTINGS.authsource == "ldap" and domain.ldap_gal %}
<dict> <dict>

View File

@@ -233,7 +233,7 @@ services:
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS} - REDISPASS=${REDISPASS}
- DB_HOST=${DB_HOST:-%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock} - DB_HOST=${DB_HOST:-/var/run/mysqld/mysqld.sock}
- SOGO_HOST=${SOGO_HOST:-172.22.1.248} - SOGO_HOST=${SOGO_HOST:-172.22.1.248}
- DOVECOT_HOST=${DOVECOT_HOST:-172.22.1.250} - DOVECOT_HOST=${DOVECOT_HOST:-172.22.1.250}
- POSTFIX_HOST=${POSTFIX_HOST:-172.22.1.253} - POSTFIX_HOST=${POSTFIX_HOST:-172.22.1.253}
@@ -243,8 +243,7 @@ services:
volumes: volumes:
- ./data/hooks/sogo:/hooks:Z - ./data/hooks/sogo:/hooks:Z
- ./data/conf/sogo:/service_config:z - ./data/conf/sogo:/service_config:z
- ./data/conf/sogo/cron.creds:/etc/sogo/cron.creds:z - ./data/conf/sogo:/etc/sogo:z
- ./data/conf/sogo/sieve.creds:/etc/sogo/sieve.creds:z
- ./data/web/inc/init_db.inc.php:/init_db.inc.php:z - ./data/web/inc/init_db.inc.php:/init_db.inc.php:z
- ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z
- ./data/conf/sogo/custom-shortlogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-compact.svg:z - ./data/conf/sogo/custom-shortlogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-compact.svg:z
@@ -373,8 +372,7 @@ services:
volumes: volumes:
- ./data/hooks/postfix:/hooks:Z - ./data/hooks/postfix:/hooks:Z
- ./data/conf/postfix:/service_config:z - ./data/conf/postfix:/service_config:z
- ./data/conf/postfix/postscreen_access.cidr:/opt/postfix/conf/postscreen_access.cidr:z - ./data/conf/postfix:/opt/postfix/conf:z
- ./data/conf/postfix/extra.cf:/opt/postfix/conf/extra.cf:z
- ./data/assets/ssl:/etc/ssl/mail/:ro,z - ./data/assets/ssl:/etc/ssl/mail/:ro,z
- postfix-vol-1:/var/spool/postfix - postfix-vol-1:/var/spool/postfix
- crypt-vol-1:/var/lib/zeyple - crypt-vol-1:/var/lib/zeyple