Compare commits

...

1955 Commits

Author SHA1 Message Date
FreddleSpl0it
8d211ea767 Set HOST env vars 2025-06-02 15:54:16 +02:00
FreddleSpl0it
4cc463a728 Set HOST env vars 2025-06-02 15:53:39 +02:00
FreddleSpl0it
909eb8a63a [Postfix] Add extra.cf via jinja2 include 2025-06-02 15:52:59 +02:00
FreddleSpl0it
4c4a440cdf Use consistent naming for host-related env vars 2025-05-31 22:31:08 +02:00
FreddleSpl0it
743bfcec60 Check if mysql has been initialized before trying to upgrade 2025-05-31 21:50:49 +02:00
FreddleSpl0it
744aa5d137 Add jinja2 filters urlencode and escape_quotes 2025-05-31 21:48:36 +02:00
FreddleSpl0it
e8d155d7e0 Set SOGo related hosts from env var 2025-05-30 20:46:49 +02:00
FreddleSpl0it
6382e3128d Remove backslash escape from jinja2 templates 2025-05-30 20:01:03 +02:00
FreddleSpl0it
bc11aed753 Change config overwrites.json path 2025-05-30 19:59:54 +02:00
FreddleSpl0it
a6e13daa8c [MySQL] Remove container startup delay 2025-05-23 09:50:28 +02:00
FreddleSpl0it
eb7d2628ac Optimize python bootstrapper 2025-05-23 09:49:08 +02:00
FreddleSpl0it
5f93ff04a9 Add psutil module for bootstrapping 2025-05-23 09:47:25 +02:00
FreddleSpl0it
f35def48cb restructure configuration directories 2025-05-22 15:37:15 +02:00
FreddleSpl0it
dba9675a9b Use config.json to render multiple Jinja2 templates 2025-05-22 14:07:39 +02:00
FreddleSpl0it
13b4f86d29 Add support for custom_templates folder to override Jinja2 templates 2025-05-22 13:42:17 +02:00
FreddleSpl0it
3eb17a5f78 [Dovecot] Suppress doveconf -P output on startup 2025-05-22 13:35:18 +02:00
FreddleSpl0it
c38a4c203e Set Jinja2 template folder to absolute path 2025-05-22 13:24:35 +02:00
FreddleSpl0it
f329549c2e [PHP-FPM] use python bootstrapper to start PHP-FPM container 2025-05-22 13:06:35 +02:00
FreddleSpl0it
767d746419 [MySQL] Check if MySQL supports timezone conversion on startup 2025-05-22 12:59:37 +02:00
FreddleSpl0it
9174a05af3 [MySQL] Optimize mysql upgrade logic 2025-05-22 08:28:03 +02:00
FreddleSpl0it
faf8fa8c2c [Mysql] use python bootstrapper to start MYSQL container 2025-05-22 07:54:29 +02:00
FreddleSpl0it
55d90afee4 [Clamd] add hooks volume 2025-05-21 14:04:04 +02:00
FreddleSpl0it
669f75182d [Clamd] use python bootstrapper to start CLAMD container 2025-05-21 14:02:49 +02:00
FreddleSpl0it
5a39ae45cb [Postfix] gitignore main.cf 2025-05-21 10:38:14 +02:00
FreddleSpl0it
8baa3c9fb5 [Dovecot] gitignore dovecot.conf 2025-05-21 10:32:04 +02:00
FreddleSpl0it
b8888521f1 [Rspamd] use python bootstrapper to start RSPAMD container 2025-05-21 09:40:38 +02:00
FreddleSpl0it
2efea9c832 [Dovecot] use python bootstrapper to start DOVECOT container 2025-05-21 07:56:28 +02:00
FreddleSpl0it
5a097ed5f7 [Postfix] use python bootstrapper to start POSTFIX container 2025-05-19 13:13:40 +02:00
FreddleSpl0it
cde2ba4851 [Nginx] use python bootstrapper to start NGINX container 2025-05-19 09:45:00 +02:00
FreddleSpl0it
1d482ed425 [SOGo] use python bootstrapper to start SOGo container 2025-05-16 13:40:26 +02:00
FreddleSpl0it
d3185c3c68 Add python bootstrapper for containers 2025-05-16 13:37:49 +02:00
FreddleSpl0it
03d979c089 [Web] Fix get custom_login 2025-05-13 10:14:58 +02:00
FreddleSpl0it
ffa2933873 increase Olefy, Rspamd and Watchdog docker images 2025-05-13 09:49:53 +02:00
FreddleSpl0it
7f47a3f00e Merge pull request #6530 from mailcow/feat/auto-create-user-option
[Web] Add identity_provider option to disable auto-creation of users …
2025-05-12 13:24:34 +02:00
FreddleSpl0it
1bcab9a9a5 Merge pull request #6518 from seclution/patch-2
fix: typo in default_template
2025-05-12 13:08:07 +02:00
FreddleSpl0it
1b2f424edc [Web] Add identity_provider option to disable auto-creation of users on login 2025-05-12 12:20:23 +02:00
krzsztf1
486b297409 Fix typo in rspamd rule in composites.conf (#6515)
Co-authored-by: Krzysztof Nowak <k.nowak@intalio.pl>
2025-05-09 18:33:19 +02:00
FreddleSpl0it
75d7f06b25 Merge pull request #6521 from mailcow/feat/login-quicklinks
[Web] Add quick links to other login pages and mailcow login toggle
2025-05-09 15:24:36 +02:00
FreddleSpl0it
ea0944d743 [Web] Add quick links to other login pages and option to disable mailcow login form 2025-05-09 15:13:44 +02:00
Kai Biebel
cb6ffe65c8 fix: typo in default_template 2025-05-09 11:24:49 +02:00
FreddleSpl0it
580dabd276 Merge pull request #6509 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2025-05-09 10:02:50 +02:00
FreddleSpl0it
846862aa80 Merge pull request #6506 from mrclschstr/staging
[Fix] Moving mails by functions.quarantine.inc.php to inbox failed
2025-05-09 10:00:56 +02:00
FreddleSpl0it
e7a1f24c78 Merge pull request #6483 from PseudoResonance/oauth2-redirect-extra-domain
Allow additional domains in OAuth2 redirect URLs
2025-05-09 09:48:08 +02:00
FreddleSpl0it
8ff0e029f0 Merge pull request #6398 from marvinruder/feat/skip-olefy
feat(olefy): Allow disabling Olefy
2025-05-08 15:34:51 +02:00
FreddleSpl0it
0680b21938 Merge pull request #6342 from mailcow/fix/6339
rspamd: remove .info from fishy tlds (default)
2025-05-08 14:36:39 +02:00
FreddleSpl0it
0c8e7bfeca Merge pull request #6376 from NickBouwhuis/staging
feat/replace bgp.he.net with bgp.tools
2025-05-08 14:31:57 +02:00
FreddleSpl0it
badcd27b93 Merge pull request #6485 from Habetdin/fix/update-legacy-links
Update legacy admin dashboard links
2025-05-08 14:16:44 +02:00
FreddleSpl0it
7d3ef3d67f Merge pull request #6487 from mailcow/fix/6469
[Web] Fix force password update at next login
2025-05-08 14:04:56 +02:00
FreddleSpl0it
5b89e253a6 Merge remote-tracking branch 'origin/staging' into fix/6469 2025-05-08 13:50:50 +02:00
FreddleSpl0it
a90f4c2a2e Merge pull request #6495 from Kuehn-Andreas/fix/redirection-after-login-with-skip-SOGo
Check if skip_sogo is not set before redirecting to SOGo
2025-05-08 11:53:47 +02:00
FreddleSpl0it
db7b917944 Merge pull request #6488 from mailcow/fix/6470
[Dovecot] Fix EAS login issue with app passwords and improve auth cache handling in Dovecot
2025-05-08 11:49:55 +02:00
FreddleSpl0it
401b744808 [Dovecot] return PASSDB_RESULT_PASSWORD_MISMATCH instead of PASSDB_RESULT_INTERNAL_FAILURE 2025-05-08 11:38:29 +02:00
milkmaker
0c83255573 update postscreen_access.cidr 2025-05-01 00:21:11 +00:00
Marcel Schuster
d55f0fc366 Update functions.quarantine.inc.php
Fix regex for quarantine release functions
2025-04-29 22:14:43 +02:00
milkmaker
06b3ba91a0 [Web] Updated lang.zh-cn.json (#6502)
Co-authored-by: Easton Man <me@eastonman.com>
2025-04-27 18:47:08 +02:00
DerLinkman
aa4125fe62 sogo: enabled SOGoEnableMailCleaning per default 2025-04-23 15:13:52 +02:00
Andreas Kühn
d8c6ed9191 Check if skip_sogo is not set before redirecting to SOGo 2025-04-22 14:23:33 +02:00
FreddleSpl0it
cb47fa406f [Web] Fix force password update at next login 2025-04-15 13:48:13 +02:00
FreddleSpl0it
c4d0f35008 [Dovecot] Fix EAS login and improve logging 2025-04-15 10:49:56 +02:00
Habetdin
0d3e8dd738 Update legacy admin dashboard links 2025-04-13 16:09:47 +03:00
PseudoResonance
692355a08a Allow additional domains in OAuth2 redirect URLs 2025-04-12 06:24:37 -07:00
renovate[bot]
a370499aaa Update dependency Imagick/imagick to v3.8.0 (#6480) 2025-04-11 08:30:54 +02:00
milkmaker
84f67d6608 Translations update from Weblate (#6478)
* [Web] Updated lang.de-de.json

Co-authored-by: Jonas Leiner <jonas.leiner.123@gmail.com>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>

---------

Co-authored-by: Jonas Leiner <jonas.leiner.123@gmail.com>
Co-authored-by: Neuronnexion <support@nnx.com>
2025-04-10 17:16:44 +02:00
milkmaker
4ac839cf49 Translations update from Weblate (#6463)
* [Web] Updated lang.hu-hu.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Added lang.bg-bg.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.tr-tr.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.zh-cn.json

Co-authored-by: Easton Man <me@eastonman.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Easton Man <me@eastonman.com>
2025-04-10 17:11:30 +02:00
FreddleSpl0it
b96a5b1efd [Web] Fix AJAX urls to absolute path 2025-04-09 08:07:46 +02:00
FreddleSpl0it
766c5e8580 [Dovecot] Ignore app passwords protocol access on SOGo request 2025-04-09 08:02:30 +02:00
FreddleSpl0it
3ddad9dee8 Merge pull request #6460 from mailcow/ui/improve-ldap-ssl-labels
[Web] Improve clarity of LDAP SSL/TLS settings
2025-04-07 08:58:19 +02:00
FreddleSpl0it
2c10c39bc4 [Web] Update 2FA Info tooltip 2025-04-07 08:06:43 +02:00
FreddleSpl0it
0eb8f38792 [Web] Update LDAP SSL/TLS tooltips 2025-04-07 07:59:43 +02:00
FreddleSpl0it
402bf53a5c [Web] Improve clarity of LDAP SSL/TLS settings 2025-04-04 13:18:42 +02:00
FreddleSpl0it
428a59dd3f Merge branch 'fix/dovecot-lua-timeout' into staging 2025-04-03 14:18:33 +02:00
FreddleSpl0it
153890b283 Merge pull request #6439 from mailcow/fix/6430
[SOGo] Use JS for mailcow logout
2025-04-03 12:57:24 +02:00
FreddleSpl0it
a741c2ba4a Merge pull request #6426 from sardaukar/fix/typo-on-backup-and-restore-script
Fix tiny typo
2025-04-03 12:41:46 +02:00
FreddleSpl0it
741e5c719f Merge pull request #6438 from mailcow/fix/6405
[Netfilter] Downgrade to 1.61
2025-04-03 12:39:48 +02:00
FreddleSpl0it
34e4f93db9 Merge pull request #6451 from mailcow/fix/6437
[Web] Fix transport routing test
2025-04-03 12:38:43 +02:00
FreddleSpl0it
3758135dc3 Merge pull request #6450 from mailcow/fix/sasl_logs
Fix sasl_logs
2025-04-03 12:38:13 +02:00
FreddleSpl0it
6794e6ff43 [Dovecot] Add service for authentication cache_key 2025-04-03 12:31:43 +02:00
FreddleSpl0it
62f816e64a [Web] Check app password before user password on web login 2025-04-03 12:19:04 +02:00
FreddleSpl0it
e65478076b [Web] Prevent user sync for mismatched authsource 2025-04-03 11:58:35 +02:00
FreddleSpl0it
ceeabded73 [Web] Fix transport routing test 2025-04-03 10:29:47 +02:00
FreddleSpl0it
805634f9a9 Fix sasl_logs 2025-04-03 10:19:30 +02:00
DerLinkman
a92832d115 update README.md to include first 50 and 100$ monthly sponsors 2025-04-02 14:39:24 +02:00
milkmaker
4c5f485587 update postscreen_access.cidr (#6443) 2025-04-01 22:00:11 +02:00
FreddleSpl0it
db3a577ae3 [Web] Fix password reset 2025-04-01 16:39:15 +02:00
FreddleSpl0it
e452917de9 [SOGo] Show mailcow Settings Button to SOGoSuperUsers 2025-03-31 12:14:43 +02:00
FreddleSpl0it
f37961b7d0 [SOGo] Use JS for mailcow logout 2025-03-31 11:32:01 +02:00
FreddleSpl0it
0157cbddaf [Netfilter] Downgrade to 1.61 2025-03-31 10:36:20 +02:00
Bruno Antunes
65d872cc14 Fix tiny typo 2025-03-27 20:21:25 +00:00
FreddleSpl0it
4ad2422810 [Dovecot] Increase Timeout for HTTP Login Request 2025-03-27 16:52:15 +01:00
FreddleSpl0it
9b41b24522 Merge pull request #6402 from marvinruder/fix/long-dropdown-label
fix(ui): Swap translations for oversized dropdown
2025-03-27 08:07:51 +01:00
FreddleSpl0it
1c9d80f554 Merge pull request #6406 from mailcow/fix/6392
[Web] Fix SOGo access after Passwordless auth
2025-03-27 07:42:07 +01:00
FreddleSpl0it
7172cad257 Merge pull request #6407 from mailcow/fix/6396
[Web] Fix oauth2 redirect after user login
2025-03-27 07:41:08 +01:00
FreddleSpl0it
b550c6f88e Merge pull request #6408 from mailcow/fix/6373
[Swagger] Fix type property for /api/v1/add/bcc endpoint
2025-03-27 07:40:19 +01:00
FreddleSpl0it
5baf9eb375 Merge pull request #6409 from mailcow/fix/6372
[Web] Check if mailbox is active before renaming
2025-03-27 07:40:03 +01:00
FreddleSpl0it
4eb89f67ed Merge pull request #6410 from mailcow/fix/6395
[Web] Use absolute paths for flag SVGs
2025-03-27 07:39:34 +01:00
FreddleSpl0it
efdc798238 Merge pull request #6411 from mailcow/fix/6340
[Nginx] Move conf.d include before SNI vhosts
2025-03-27 07:39:06 +01:00
Marvin A. Ruder
8408b82e9c Add new option with description to existing configuration files during next update
* Remove Olefy settings file from rspamd configuration
* Have rspamd container generate Olefy settings file at startup if not disabled

Signed-off-by: Marvin A. Ruder <signed@mruder.dev>
2025-03-26 17:17:13 +01:00
FreddleSpl0it
65fb4c2aa8 [Nginx] Move conf.d include before SNI vhosts 2025-03-26 13:04:43 +01:00
FreddleSpl0it
a5ca3353da [Web] Use absolute paths for flag SVGs 2025-03-26 10:59:56 +01:00
FreddleSpl0it
95aa35e133 [Web] Check if mailbox is active before renaming 2025-03-26 10:10:22 +01:00
FreddleSpl0it
21b11ed999 [Swagger] Fix type property for /api/v1/add/bcc endpoint 2025-03-26 09:24:03 +01:00
FreddleSpl0it
348107dae8 [Web] Fix oauth2 redirect after user login 2025-03-26 09:13:05 +01:00
FreddleSpl0it
fcb1b29c89 [Web] Fix SOGo access after Passwordless auth 2025-03-26 08:32:34 +01:00
Marvin A. Ruder
05fc4f7aba fix(ui): Swap translations for oversized dropdown
* Fix other typos
* Fixes #6400

Signed-off-by: Marvin A. Ruder <signed@mruder.dev>
2025-03-25 21:24:22 +01:00
Marvin A. Ruder
cd3b1ab828 Allow disabling Olefy
* Fixes #6389

Signed-off-by: Marvin A. Ruder <signed@mruder.dev>
2025-03-25 20:24:33 +01:00
FreddleSpl0it
d584dd387e Merge pull request #6390 from mailcow/nightly
Nightly 2025-03 to staging
2025-03-25 07:36:20 +01:00
FreddleSpl0it
986b0afbfa ldap-sync: Fix template selection 2025-03-24 15:33:42 +01:00
FreddleSpl0it
59d139bc63 Merge branch 'nightly' into staging 2025-03-24 13:39:43 +01:00
FreddleSpl0it
ad5f07f077 update.sh: add 2025-03 as major version 2025-03-24 11:47:27 +01:00
FreddleSpl0it
cf2d3c1b4e Merge branch 'staging' into nightly 2025-03-24 11:38:59 +01:00
FreddleSpl0it
91c82e8a67 Merge pull request #6384 from mailcow/feat/update-components-alp-3.21
os: updated alpine containers to 3.21
2025-03-24 11:30:58 +01:00
FreddleSpl0it
ba7437a8f3 Merge pull request #6380 from mailcow/feat/legacy-switch
Add Legacy Updates
2025-03-20 14:25:13 +01:00
FreddleSpl0it
684256b66e update.sh: Fix legacy typo 2025-03-20 14:23:28 +01:00
FreddleSpl0it
70ba361583 update.sh: Fix text in legacy update prompt 2025-03-20 14:15:15 +01:00
FreddleSpl0it
94d4817ecb [Web] Add default_template parameter to edit/identity-provider documentation 2025-03-20 13:38:27 +01:00
FreddleSpl0it
72ced70e33 [Web] Fix mailbox authsource selection 2025-03-20 13:08:42 +01:00
FreddleSpl0it
887b7114a8 Add default template for IdP attribute mapping 2025-03-19 14:35:32 +01:00
Nick Bouwhuis
ceebc56e62 feat/replace bgp.he.net with bgp.tools 2025-03-18 10:08:08 +00:00
FreddleSpl0it
8910135f02 [Web] Add edit/identity-provider Api Documentation 2025-03-17 13:21:28 +01:00
DerLinkman
463e3ab78c rspamd: update rspamd to 3.11.1 (#6374) 2025-03-14 12:18:59 +01:00
FreddleSpl0it
2a15914324 Fix major update prompt 2025-03-14 11:22:57 +01:00
FreddleSpl0it
e21696ff27 Add error message when mailbox creation fails 2025-03-14 09:36:40 +01:00
FreddleSpl0it
5a7275843a Add error message when mailbox creation fails 2025-03-14 09:30:33 +01:00
FreddleSpl0it
c93106f9d6 [Web] Fix redirect after renaming mailbox 2025-03-14 09:29:02 +01:00
FreddleSpl0it
43c1597051 [Web] Check if authsource is configured before adding or updating a mailbox 2025-03-14 09:19:39 +01:00
FreddleSpl0it
c3aa4f7418 [Web] Add authsource property to mailbox API Documentation 2025-03-14 09:17:51 +01:00
FreddleSpl0it
cb08132a74 [Web] Fix authentication when mailbox or domain is deactivated 2025-03-13 14:39:03 +01:00
FreddleSpl0it
2596b9d386 [Web] Improve auth logging and language strings 2025-03-12 11:42:14 +01:00
Marvin A. Ruder
062539b7d7 dkim: Add support for 3072 and 4096 bit RSA keys (#6365)
* dkim: Add support for 3072 and 4096 bit RSA keys

Signed-off-by: Marvin A. Ruder <signed@mruder.dev>

* php: added missing ; in dkim function

* php: make 4096 DKIM default

* db: update schema to set dkim 4096 as default

* Revert "db: update schema to set dkim 4096 as default"

This reverts commit 790b40a695.

* Revert "php: make 4096 DKIM default"

This reverts commit 7e643376c7.

---------

Signed-off-by: Marvin A. Ruder <signed@mruder.dev>
Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2025-03-11 15:30:46 +01:00
DerLinkman
18acbc7a4c cold-standby: changed texts + removed --no-parallel for pull 2025-03-11 12:35:13 +01:00
DerLinkman
2f93f1d0c5 os: fixes for newer mariadb-client versions (especially on alpine 3.21) 2025-03-10 16:45:57 +01:00
DerLinkman
0860a7503e os: updated alpine containers to 3.21 2025-03-10 11:56:12 +01:00
renovate[bot]
86df78255d chore(deps): update dependency composer/composer to v2.8.6 (#5719)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-10 11:39:19 +01:00
FreddleSpl0it
aac0a900ce [Web] Fix JSON parsing issue for api requests 2025-03-10 10:49:27 +01:00
milkmaker
03565df48d [Web] Updated lang.ko-kr.json (#6356)
Co-authored-by: dongsu8142 <dongsu8142@naver.com>
2025-03-07 21:37:31 +01:00
FreddleSpl0it
5f15475b55 [Rspamd] Remove redis.conf from tracking 2025-03-07 15:18:42 +01:00
FreddleSpl0it
25d34b5acf [Web] Remove default ui help text 2025-03-07 14:52:08 +01:00
FreddleSpl0it
6b165887d8 Merge branch 'staging' into nightly 2025-03-07 13:21:57 +01:00
FreddleSpl0it
82eb3c64cd [Web] Use SQL password only when authsource is mailcow 2025-03-07 13:15:27 +01:00
FreddleSpl0it
bc21e7fe50 [Web] Separate FIDO2 logins 2025-03-07 13:12:48 +01:00
FreddleSpl0it
6f9c8deab7 [Web] Support old style app links 2025-03-07 09:56:20 +01:00
FreddleSpl0it
8761d8fc47 [Web] Fix app layout issue 2025-03-07 09:54:35 +01:00
milkmaker
0435766c17 [Web] Updated lang.ko-kr.json (#6353)
Co-authored-by: dongsu8142 <dongsu8142@naver.com>
2025-03-05 17:43:37 +01:00
renovate[bot]
79f4cf4021 chore(deps): update docker/build-push-action action to v6 (#6334) 2025-03-05 16:35:46 +01:00
milkmaker
81803836f0 [Web] Updated lang.ko-kr.json (#6350)
Co-authored-by: dongsu8142 <dongsu8142@naver.com>
2025-03-03 22:49:23 +01:00
milkmaker
4bd267515a update postscreen_access.cidr (#6345) 2025-03-01 13:32:21 +01:00
DerLinkman
70190e5230 rspamd: remove .info from fishy tlds (default) 2025-02-28 15:38:05 +01:00
DerLinkman
5296085189 update.sh: corrected typos inside update.sh 2025-02-27 11:47:08 +01:00
DerLinkman
a4c2cf4c67 scripts: adapted new docker image names to docker_garbage function + removed dup 2025-02-27 11:44:52 +01:00
Peter
3c9d0c9d57 use ghcr.io for backupimage (#6333)
* use ghcr.io for backup image

* backup script: use renamed script + improved build of image

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2025-02-27 10:58:23 +01:00
FreddleSpl0it
35a6f81d0d [Redis] use 7.4.2-alpine image 2025-02-27 09:28:52 +01:00
FreddleSpl0it
4b31c04e3e Merge pull request #6330 from mailcow/feat/major-update-prompt
Prompt user before applying major updates
2025-02-27 08:15:21 +01:00
FreddleSpl0it
3d9cc2f6dd add 2025-02 to major versions 2025-02-27 08:14:34 +01:00
DerLinkman
704dd50262 compose: use ghcr.io for new/current mailcow docker images instead of docker hub (#6332) 2025-02-26 15:20:57 +01:00
FreddleSpl0it
8d0c03b2fc small adjustment for legacy version 2025-02-26 10:39:41 +01:00
FreddleSpl0it
c4a0e370b7 Merge pull request #6155 from PseudoResonance/fix2752
Fix #2752 - Allow domain recipients for address rewrite
2025-02-26 10:01:03 +01:00
FreddleSpl0it
b77ff2f51c Add switch to legacy version 2025-02-26 09:47:59 +01:00
FreddleSpl0it
787fa49d0c prompt user before applying major updates 2025-02-25 12:08:21 +01:00
DerLinkman
a6c38590ca rspamd: upgraded rspamd to 3.11.0-2 (incl. NIXSPAM Removal) (#6328) 2025-02-25 09:23:10 +01:00
PseudoResonance
e52323bf1d Fix @ prefixing domain rewrite and update localization 2025-02-24 22:36:17 -08:00
PseudoResonance
f15ee39b63 Fix #2752: Domain recipient for address rewrite
(cherry picked from commit 40f6d691d8774d6f813153974f8fe462a8db9ab3)
2025-02-24 22:07:23 -08:00
FreddleSpl0it
fcebe98557 Merge branch 'staging' into nightly 2025-02-24 15:09:36 +01:00
FreddleSpl0it
6ec5e88793 Merge pull request #6309 from mailcow/fix/6308
[Dovecot][Netfilter] Fix dovecot failed login regex
2025-02-24 11:26:06 +01:00
FreddleSpl0it
7d35646342 [Netfilter] adjust dovecot failed login regex 2025-02-24 09:20:41 +01:00
FreddleSpl0it
321965adee [Netfilter] Fix dovecot password mismatch regex 2025-02-18 15:05:59 +01:00
Peter
7bce5d836b Move sed cmd to remove discontinued DNSBLs (#6315)
* Move sed cmd to remove discontinued DNSBLs

* compose: bump postfix version

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2025-02-18 11:20:03 +01:00
FreddleSpl0it
351f4ce787 [Redis] Add support for masterauth via env var 2025-02-18 11:16:06 +01:00
FreddleSpl0it
a567d5dc31 [Nginx] Add support for trusted proxies via env var 2025-02-18 11:03:34 +01:00
DerLinkman
4ac541f671 [Mariadb] Update to 10.11 (LTS) (#5152)
* [Mariadb] Update to 10.11 (LTS)

* mysql: set default collation to general_ci
2025-02-17 15:48:25 +01:00
Dmitriy Alekseev
f6dc0b463f Update Rspamd to 3.11.0 and enable SMTPUTF8 for outgoing mail (#6216)
* Update Rspamd to 3.11

* Enable SMTPUTF8 and hide it from SMTPD greeting

* Update options.inc

* compose: increased rspamd tag
2025-02-17 14:41:39 +01:00
DerLinkman
16e22e23dc sogo: switched apt source to sogo again (supports aarch64 now) 2025-02-17 14:31:50 +01:00
FreddleSpl0it
d8afa6f393 [Dovecot][Netfilter] Fix dovecot failed login regex 2025-02-14 13:12:12 +01:00
milkmaker
836e3f15b7 [Web] Updated lang.es-es.json (#6307)
Co-authored-by: Julie GINESTIERE <julien.ginestiere+git@gmail.com>
2025-02-13 19:32:39 +01:00
FreddleSpl0it
aaa7e4a184 [Web] Fix incorrect session lifetime in sogo-auth.php 2025-02-13 11:54:55 +01:00
FreddleSpl0it
3912341b32 [SOGo] rename custom logo 2025-02-12 11:31:14 +01:00
FreddleSpl0it
735d5f0e56 Merge pull request #6220 from Babybatrick/staging
Adding lines to docker-compose.yml to allow for simpler SOGo web client UI customisation
2025-02-12 10:54:16 +01:00
FreddleSpl0it
f375794fb7 Merge pull request #6223 from mailcow/ffdhe2048
Ffdhe2048
2025-02-12 10:48:22 +01:00
renovate[bot]
4ed3017a02 chore(deps): update devops-infra/action-pull-request action to v0.6.0 (#6302) 2025-02-12 06:56:10 +01:00
FreddleSpl0it
ef2f5f7be0 [Dovecot] Use Redis ACL user quota_notify with restricted access 2025-02-11 16:59:18 +01:00
FreddleSpl0it
54728bf780 [Dovecot] Fix create sogo-sso.conf 2025-02-11 14:40:38 +01:00
Henry Williams
743e88fd67 Update generate_config.sh version checking for wider compatibility (#6270)
* Update generate_config.sh version checking for wider compatibility 

fix: replace `grep -oP` with `grep -oE` for broader compatibility

The `-P` option (Perl-compatible regex) is not supported in all versions of `grep`, particularly the default BSD `grep` on macOS. This change replaces `-P` with `-E` (extended regex), which is more widely available and ensures compatibility across different environments.

Tested on macOS and Linux.

* Update generate_config.sh to remove use of platform dependent grep

Replaced version checking using free-form text. Instead, uses Docker’s built-in templating instead of parsing free-form text. This gives cross-platform consistency without dependency on particular versions of grep.
2025-02-11 13:55:03 +01:00
DerLinkman
ac2f0c7db1 Merge pull request #6286 from mailcow/fix-workflow-staging
Fix check_prs_if_on_staging workflow
2025-02-11 13:52:44 +01:00
FreddleSpl0it
f64c6aa1d4 Merge pull request #6269 from mailcow/staging
Automatic PR to nightly from 2025-01-27T10:00:26Z
2025-02-07 15:10:10 +01:00
FreddleSpl0it
e2cf22ff9e Merge pull request #6268 from mailcow/feat/nightly-separated-login
[Web] Separate Login pages
2025-02-07 15:09:39 +01:00
FreddleSpl0it
55dcae4a01 [Web] Fix Generic-OIDC connection test 2025-02-07 15:05:43 +01:00
FreddleSpl0it
f0016eeecd [Web] Add german translation for idp settings 2025-02-07 14:19:20 +01:00
FreddleSpl0it
3544a2246e [Nginx] fix ADDITIONAL_SERVER_NAMES array 2025-02-04 13:30:00 +01:00
FreddleSpl0it
97890b71f1 [Nginx] Invert SKIP container condition 2025-02-03 12:22:13 +01:00
FreddleSpl0it
e645f931dc [Nginx] Add env var for HTTP to HTTPS redirection 2025-02-03 12:05:08 +01:00
FreddleSpl0it
bbdec0960a Merge pull request #6290 from mailcow/fix/nginx-vhosts
[Nginx] Use vhosts for additional server names
2025-02-03 11:35:09 +01:00
milkmaker
41ba7d97fa update postscreen_access.cidr (#6287) 2025-02-01 17:06:07 +01:00
Peter
83fc2c6387 It's github-token now 2025-01-31 17:20:28 +01:00
DerLinkman
aac4c6b5f4 postfix: added master.pid removal and startsecs to supervisord (#6284) 2025-01-31 12:49:39 +01:00
FreddleSpl0it
3c0f775e2f Merge pull request #6281 from mailcow/fix/6275
[Nginx] Fix
2025-01-31 10:49:21 +01:00
FreddleSpl0it
3a81b84cf7 [Nginx] Fix #6275 2025-01-30 14:49:18 +01:00
FreddleSpl0it
a2e87e0880 [Web] Add validation for server_name against allow list 2025-01-30 11:47:55 +01:00
DerLinkman
2407aa7895 Merge branch 'feat/clamd-rebuild' into staging 2025-01-29 14:01:39 +01:00
FreddleSpl0it
0ad327bbe5 [Nginx] Use separate vhosts for additional server names 2025-01-29 09:51:45 +01:00
DerLinkman
1a087bb2c8 clamd: cleanup dockerfile 2025-01-28 14:49:11 +01:00
DerLinkman
65bc581fab clamd: remove exposed ports from buildfile 2025-01-28 14:36:43 +01:00
DerLinkman
60a2270d1e clamd: update to 1.4.2 + build from source instead using alpine packages 2025-01-28 14:25:56 +01:00
FreddleSpl0it
cb5cae3e44 Merge branch 'nightly' into feat/nightly-separated-login 2025-01-27 16:37:09 +01:00
FreddleSpl0it
8ed51e500f Merge pull request #6260 from mailcow/manitu
Remove discontinued Nixspam DNSBL
2025-01-27 16:21:29 +01:00
FreddleSpl0it
aca01c8aa2 [Web] Separate Login pages 2025-01-27 15:59:50 +01:00
FreddleSpl0it
45d14254f2 [Postfix] Remove discontinued Nixspam DNSBL from existing dns_blocklists.cf 2025-01-24 10:06:50 +01:00
FreddleSpl0it
de6bd222fc [Web] increase db_version 2025-01-24 09:25:19 +01:00
Michael Kuron
04116982a5 Remove discontinued Nixspam DNSBL 2025-01-23 22:16:54 +01:00
FreddleSpl0it
36d4fcbf39 Merge pull request #6255 from mailcow/staging
Automatic PR to nightly from 2025-01-23T11:01:42Z
2025-01-23 15:21:39 +01:00
FreddleSpl0it
04058ab06e [Nginx] move conf.d include to end of nginx.conf 2025-01-23 14:54:28 +01:00
FreddleSpl0it
9d791d0c4f Merge branch 'staging' into nightly 2025-01-23 12:06:47 +01:00
FreddleSpl0it
da02e26172 [Web] Delete old session_id after regenerate 2025-01-23 11:59:01 +01:00
DerLinkman
43f945fe01 dovecot: fix index timeout seconds 2025-01-23 11:51:41 +01:00
DerLinkman
e76c0ba9a6 Merge branch 'staging' 2025-01-23 11:31:01 +01:00
DerLinkman
d83111568e update.sh: remove accidentally added exit at end of solr volume removal 2025-01-23 11:30:05 +01:00
FreddleSpl0it
1b578caabb Merge pull request #6251 from mailcow/staging
2025-01
2025-01-23 11:16:38 +01:00
FreddleSpl0it
1e77f8d8a1 Merge pull request #6250 from mailcow/staging
Automatic PR to nightly from 2025-01-22T19:10:32Z
2025-01-23 11:01:55 +01:00
FreddleSpl0it
5f45f8ae34 [Web] Fix mailbox datatable search 2025-01-23 09:18:45 +01:00
DerLinkman
1dac8f1f66 scripts: changed SKIP_FTS text to warn on lower threaded systems 2025-01-23 08:42:22 +01:00
DerLinkman
5a04942d89 update.sh: changed SKIP_FTS default to y instead n for updates 2025-01-23 08:38:14 +01:00
DerLinkman
a30f6696a3 update.sh: fixed --force for solr-removal + code optimization 2025-01-23 08:30:48 +01:00
FreddleSpl0it
d430b595c1 Merge branch 'staging' into nightly 2025-01-23 08:11:45 +01:00
FreddleSpl0it
1fca328266 [Nginx] Disable IPv6 listener for Rspamd dynmaps when DISABLE_IPv6=y 2025-01-22 15:11:46 +01:00
FreddleSpl0it
7bcd61ecb5 [Nginx] Generate includes for custom configs 2025-01-22 14:30:47 +01:00
renovate[bot]
ee7a8624fc chore(deps): update actions/stale action to v9.1.0 (#6247)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 06:38:13 +01:00
DerLinkman
4708b1398b update.sh: fix mailcow fts update versioning 2025-01-20 15:41:48 +01:00
DerLinkman
746915cbdd fts: change autoindex to occur on mailboxes of receiving 20 or more mails daily 2025-01-20 14:21:15 +01:00
Alyx
36db68677c Reduce sa rules download retry limit to 5 (#6225)
Reduces the retry limit for the sa rules download to a more reasonable 5 retries to prevent running in a timeout condition.
2025-01-20 14:10:29 +01:00
gwelch-contegix
08599c1960 Fix community support url (#6245) 2025-01-20 14:09:31 +01:00
DerLinkman
31e001ebee flatcurve: change default amount of processes to 1 2025-01-16 11:37:15 +01:00
FreddleSpl0it
1e70a20188 [SOGo] Add mailcow Buttons to SOGo navbar 2025-01-15 16:15:25 +01:00
FreddleSpl0it
8048e0a53c [Web] Fix permission exception in IdP actions 2025-01-15 12:48:10 +01:00
FreddleSpl0it
8fea9fc21f Merge pull request #6211 from jan-oratowski/patch-1
Fix missing property in Create Sync Job request
2025-01-14 12:18:29 +01:00
FreddleSpl0it
2f1884e94b Merge pull request #6205 from PhoenixPeca/master
Improve the existing validation flow for sieve filter
2025-01-14 12:08:56 +01:00
FreddleSpl0it
24b3d8f850 Merge pull request #6001 from marekfilip/feat/temp-email-aliases
add temporary email description
2025-01-14 11:52:44 +01:00
FreddleSpl0it
d280025b51 [Web] Regenerate session_id on successful login 2025-01-14 11:30:41 +01:00
FreddleSpl0it
abd789f629 [Web] Escape mailbox name before querying aliases 2025-01-14 11:18:20 +01:00
milkmaker
69f6a82905 [Web] Updated lang.fr-fr.json (#6238)
Co-authored-by: Neuronnexion <support@nnx.com>
2025-01-09 06:51:42 +01:00
milkmaker
10328981b6 Translations update from Weblate (#6235)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>

* [Web] Updated lang.zh-cn.json

Co-authored-by: Easton Man <me@eastonman.com>

---------

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Easton Man <me@eastonman.com>
2025-01-05 15:25:45 +01:00
Filip Marek
150b2bbd9d Merge branch 'mailcow:master' into feat/temp-email-aliases 2025-01-03 11:40:01 +01:00
milkmaker
40a8bc808a update postscreen_access.cidr (#6232) 2025-01-01 03:26:18 +01:00
Dmitriy Alekseev
d92aa4b15d Update dhparams.pem
Use https://ssl-config.mozilla.org/ffdhe2048.txt due to better security of the key
2024-12-20 15:39:41 +01:00
milkmaker
2d2dacb70e [Web] Updated lang.fr-fr.json (#6221)
[Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Peter <magic@kthx.at>
2024-12-19 17:10:43 +01:00
Amin
ade20d79d4 Uploading of the necessary files, after new volumes were added to docker-compose.yml (sogo-mailcow container)
After new volumes were added to docker-compose.yml in the sogo-mailcow container, it is necessary to include the specified files in the path, in order for docker to correctly start after running `docker compose up` command, otherwise error will appear, as necessary files would be missing.
The files uploaded are original SOGo UI elements, obtained from the sogo-mailcow container. Whenever users will need to change the UI elements, they would just need to change these files. Hence simplifying the process.
2024-12-19 22:13:27 +08:00
Amin
65bc8f0972 Update docker-compose.yml (sogo-mailcow)
This commit includes the addition of 3 lines, in the volumes part of the sogo-mailcow container, to allow for better customisation of the user interface on the web client page.
2024-12-19 21:59:05 +08:00
Jan Oratowski
c6f6eda0bf Fix missing property in Create Sync Job request
In example there was property called "user1", but it was missing from request definition.

This resulted in nswagger generating incorrect C# API code.
2024-12-14 15:27:37 +01:00
milkmaker
357a4d7fb3 [Web] Updated lang.fr-fr.json (#6209)
Co-authored-by: Neuronnexion <support@nnx.com>
2024-12-13 12:21:12 +01:00
DerLinkman
1c6684a539 compose: fix dovecot tagging 2024-12-12 17:02:21 +01:00
DerLinkman
de80c120c9 update.sh: added silent fix for removing old fts.conf in order to update properly 2024-12-12 16:57:32 +01:00
Niklas Meyer
3e8bb06a37 dovecot: replace solr fts with flatcurve (xapian) (#5680)
* fts-flatcurve: inital implementation

* fts: removed solr from compose.yml

* flatcurve: added heap and proc logic to dovecot

* added logic for update.sh & generate for Flatcurve

* delete old iteration of fts-flatcurve.conf

* updated default fts.conf

* updated .gitignore to exclude fts.conf for further git updates

* Remove autogeneration of fts.conf (disable override)

* cleanup all left solr stuff

* renamed SKIP_FLATCURVE to SKIP_FTS

* cleanup leftovers solr in lang files

* moved lazy_expunge plugin only to mail_plugins

* added fts timeout value

* compose: remove dev image of dovecot

* updated japanese translation
2024-12-12 16:44:42 +01:00
milkmaker
b087ac9e27 Translations update from Weblate (#6206)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Neuronnexion <support@nnx.com>

* [Web] Updated lang.si-si.json

Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>

---------

Co-authored-by: Neuronnexion <support@nnx.com>
Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>
2024-12-11 18:10:51 +01:00
Phoenix Eve Aspacio
d09e4ff020 Convert AJAX to POST request
This AJAX request sends form data in $_GET request query. This is problematic and unreliable when validating superrrr loooooong conditions, especially in environments that use reverse-proxy.

Been having this problem and this PR solves it. :)
2024-12-11 10:06:10 +08:00
Phoenix Eve Aspacio
f065842402 Updated to $_REQUEST.
tested from my end.
2024-12-11 10:03:47 +08:00
Niklas Meyer
3875e8377a sogo: added SOGoDisableOrganizerEventCheck value to sogo.conf (#6204) 2024-12-10 15:59:02 +01:00
Christian 🦄
7c8e5c10ca Add create command to prevent external: true warnings (#6203)
This is related to https://github.com/mailcow/mailcow-dockerized/issues/5970 and https://community.mailcow.email/d/2126-backup-restore/2

It adds `docker compose create` to the script which gets executed directly after the sync of the mailcow-dockerized directory. This way the Docker daemon on the remote side creates everything and we get rid of the warning "volume "XYZ" already exists but was not created by Docker Compose. Use `external: true` to use an existing volume"

This is helpful if you use the create-cold-standby.sh script to migrate your mailcow installation to another server and don't want to get those warnings after migration.

Co-authored-by: Niklas Meyer <niklas.meyer@servercow.de>
2024-12-10 09:25:29 +01:00
Filip Marek
1a8e1a2677 add escape html for description 2024-12-09 23:07:43 +01:00
Filip Marek
0d635e2658 increase migrations verion 2024-12-09 23:07:43 +01:00
Filip Marek
60ca25026d add temporary email description 2024-12-09 23:07:02 +01:00
FreddleSpl0it
69b03791a2 Add missing Redis authentication 2024-12-09 13:54:44 +01:00
Peter
ed2837edd8 Remove legacy Nextcloud settings (#6050) 2024-12-09 13:49:24 +01:00
FreddleSpl0it
fa3b789fbb [Web] fix issue #6185 2024-12-09 13:07:00 +01:00
FreddleSpl0it
49e05f5120 [Web] fix oauth2 redirect after login 2024-12-09 11:36:05 +01:00
FreddleSpl0it
24453993f3 Merge pull request #6186 from h3ssan/feat/search-mailbox-by-full-name
Implement search mailboxes by fullname
2024-12-09 10:21:39 +01:00
FreddleSpl0it
8853e2c44a [Nginx] Use SOGo IPv4 for upstream 2024-12-09 09:50:16 +01:00
FreddleSpl0it
c9dd102741 [Dovecot] use auth_cache 2024-12-06 12:55:44 +01:00
Tatsuya Yokota
d1af52b4e7 Add initial Japanese language files (#6198)
* Add initial Japanese language files

* Reordered language list: moved Japanese (日本語) below Italian (Italiano)

---------

Co-authored-by: Tatsuya Yokota <git@acoustype.com>
2024-12-06 09:44:16 +01:00
FreddleSpl0it
bbddfc3eab [Web] rearrange login buttons 2024-12-05 15:21:07 +01:00
FreddleSpl0it
a41bb55c83 Merge remote-tracking branch 'origin/staging' into nightly 2024-12-05 14:33:41 +01:00
FreddleSpl0it
b6174fae23 Merge pull request #6194 from mailcow/feat/nightly-enhancements
[Nightly] Enhancements
2024-12-05 13:18:39 +01:00
FreddleSpl0it
1d6513ffba [Web] fix idp login alerts and updates 2024-12-04 14:49:31 +01:00
i-curve
6e8e13cebc fix: check docker version fail in generate_config.sh #6187 (#6188)
close #6187

Signed-off-by: i-curve <i-curve@qq.com>
Co-authored-by: Niklas Meyer <niklas.meyer@servercow.de>
2024-12-04 12:28:14 +01:00
FreddleSpl0it
896a9638d6 Fix mailcowauth 2024-12-02 14:16:43 +01:00
FreddleSpl0it
83e53eb524 [Web] fix incomplete session on broken logins 2024-12-02 11:55:17 +01:00
FreddleSpl0it
f36184df64 [Web] update mailbox on idp login 2024-12-02 10:35:45 +01:00
FreddleSpl0it
6fa1c9f63d [Web] protect /get/identity-provider 2024-12-02 10:24:15 +01:00
milkmaker
f3060b37a6 update postscreen_access.cidr (#6189) 2024-12-01 17:49:28 +01:00
milkmaker
59c68f2603 Translations update from Weblate (#6190) 2024-12-01 17:49:10 +01:00
FreddleSpl0it
ccc8595665 [SOGo] redirect to /user if unauthenticated 2024-12-01 16:51:56 +01:00
FreddleSpl0it
45c13c687b [Web] update user based on template after login 2024-12-01 16:36:16 +01:00
FreddleSpl0it
d61a08c2a9 [Web] hide auth heading for external managed users 2024-11-30 14:39:05 +01:00
FreddleSpl0it
c8c4cfd939 [Web] add ignore ssl option for keycloak and generic-oidc provider 2024-11-30 14:37:07 +01:00
FreddleSpl0it
ec4b9b088c [Web] support multiple ldap hosts separated by comma 2024-11-29 18:59:07 +01:00
FreddleSpl0it
b2db8e6b31 [Dovecot] init identity provider before user login 2024-11-29 16:52:34 +01:00
FreddleSpl0it
05e4bd7602 [Web] use global vars for iam_provider and iam_settings 2024-11-29 15:50:35 +01:00
Hassan A Hashim
31185e3de1 Implement search mailboxes by fullname 2024-11-27 14:47:57 +03:00
Habetdin
4dbfd3abad Update lang.ru-ru.json (#6184) 2024-11-25 16:01:17 +01:00
FreddleSpl0it
b4e6002bcf Merge pull request #6076 from Habetdin/staging
Only show active protocols on "last login" in mailbox overview
2024-11-21 10:24:41 +01:00
FreddleSpl0it
6af907cff0 Merge pull request #6182 from mailcow/fix/4518
[Web] allow dots in dkim selectors
2024-11-20 13:11:34 +01:00
FreddleSpl0it
ba282233ea [Web] allow dots in dkim selectors 2024-11-20 13:05:02 +01:00
FreddleSpl0it
6f4c2b3361 Merge pull request #6181 from mailcow/fix/5703
[Web] Add additional columns to _sogo_static_view
2024-11-20 11:15:35 +01:00
FreddleSpl0it
d08b9aec32 [Web] Add additional columns to _sogo_static_view 2024-11-20 11:09:49 +01:00
FreddleSpl0it
bb310600b2 Merge pull request #6180 from mailcow/fix/6046
[Web] add missing translation for ratelimit in templates overview
2024-11-20 10:02:34 +01:00
FreddleSpl0it
fe7211f27f [Web] add missing translation for ratelimit in templates overview 2024-11-20 09:57:14 +01:00
FreddleSpl0it
8e9a9364a8 Merge pull request #6146 from mailcow/feat/redis-pw
Enable password protection for Redis
2024-11-19 15:32:36 +01:00
FreddleSpl0it
6831f94fdb [Redis] redis-cli suppress auth warning 2024-11-19 15:10:52 +01:00
FreddleSpl0it
b0de756a7c [Redis] Rename docker-entrypoint.sh to redis-conf.sh 2024-11-19 14:54:36 +01:00
FreddleSpl0it
922f8777b0 Merge pull request #6168 from mailcow/fix/f2b-banlist
[Web] remove f2b banlist from json_api.php
2024-11-19 14:32:31 +01:00
FreddleSpl0it
c1903f121d [Redis] set password via docker-entrypoint.sh 2024-11-19 14:25:31 +01:00
FreddleSpl0it
89fb1322c6 Enable password protection for Redis 2024-11-19 14:25:31 +01:00
FreddleSpl0it
852d944cfb [Web] remove f2b banlist from json_api.php 2024-11-19 14:13:37 +01:00
Niklas Meyer
bca4e1a03d update.sh: precaution ask for deletion of dns_blocklists.cf if old format (#6154) 2024-11-19 14:13:37 +01:00
FreddleSpl0it
326a446f8b Merge pull request #6177 from mailcow/feat/jinja2-nginx
[Nginx] Use jinja2 for templating nginx configuration
2024-11-19 14:08:37 +01:00
FreddleSpl0it
70ca5fde95 [Nginx] Use jinja2 for templating nginx configuration 2024-11-19 08:39:52 +01:00
DerLinkman
5ad4ab5b60 update.sh: fixed typos 2024-11-15 16:39:06 +01:00
Niklas Meyer
bd9f4ba0a5 Merge pull request #6173 from mailcow/staging
2024-11b
2024-11-15 16:21:17 +01:00
DerLinkman
d10d64dd92 mysql: increased thread_stack to 192k since 10.5.27 2024-11-15 16:18:22 +01:00
FreddleSpl0it
6d1f7482ed [Web] broadcast maildir move to dovecot containers on mailbox_rename 2024-11-15 16:18:21 +01:00
FreddleSpl0it
b9f52df3f1 [Web] update _sogo_static_view on password reset 2024-11-15 16:18:21 +01:00
FreddleSpl0it
dc379267a9 Merge remote-tracking branch 'origin/staging' into nightly 2024-11-12 16:07:55 +01:00
Niklas Meyer
4d688c5500 2024-11a (#6160)
* update.sh: precaution ask for deletion of dns_blocklists.cf if old format (#6154)

* [Web] Updated lang.zh-cn.json (#6151)

[Web] Updated lang.zh-cn.json

Co-authored-by: Easton Man <me@eastonman.com>

* compose: bump sogo version to include 5.11.2 (#6156)

* php: use correct php image + workaround of #6149 (#6159)

* compose: bump php-fpm container to correctly use patched c-ares

* [Web] check $containers_info contains required fields

---------

Co-authored-by: FreddleSpl0it <patschul@posteo.de>

---------

Co-authored-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: Easton Man <me@eastonman.com>
Co-authored-by: FreddleSpl0it <patschul@posteo.de>
2024-11-12 15:57:17 +01:00
Niklas Meyer
b90375b6e5 php: use correct php image + workaround of #6149 (#6159)
* compose: bump php-fpm container to correctly use patched c-ares

* [Web] check $containers_info contains required fields

---------

Co-authored-by: FreddleSpl0it <patschul@posteo.de>
2024-11-12 15:56:23 +01:00
FreddleSpl0it
9542698e95 Merge remote-tracking branch 'origin/staging' into nightly 2024-11-12 15:10:03 +01:00
Niklas Meyer
afe0ba74d2 compose: bump sogo version to include 5.11.2 (#6156) 2024-11-12 11:11:34 +01:00
milkmaker
dc5a28111d [Web] Updated lang.zh-cn.json (#6151)
[Web] Updated lang.zh-cn.json

Co-authored-by: Easton Man <me@eastonman.com>
2024-11-11 21:39:15 +01:00
Niklas Meyer
52f3f93aee update.sh: precaution ask for deletion of dns_blocklists.cf if old format (#6154) 2024-11-11 16:50:14 +01:00
Habetdin
6550f0a3e8 Only show active protocols on "last login" in mailbox overview 2024-11-11 12:44:05 +03:00
FreddleSpl0it
0a58aa293a Merge pull request #6141 from mailcow/staging
2024-11
2024-11-07 11:41:45 +01:00
milkmaker
be79f320d2 Translations update from Weblate (#6140)
* [Web] Updated lang.lv-lv.json

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>

* [Web] Updated lang.tr-tr.json

Co-authored-by: Furkan <furkan43500@gmail.com>

---------

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: Furkan <furkan43500@gmail.com>
2024-11-06 19:08:53 +01:00
Niklas Meyer
6ec1e357c3 fix: broken sogo cron notifications (for appointments etc.) (#6128) 2024-11-05 16:21:14 +01:00
milkmaker
8b2f71f97e update postscreen_access.cidr (#6129) 2024-11-05 16:20:57 +01:00
renovate[bot]
93cf99cc9e chore(deps): update thollander/actions-comment-pull-request action to v3.0.1 (#6130)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 20:38:18 +01:00
FreddleSpl0it
d8c8e4ab1b [DockerApi] Fix IMAP ACL migration issue when renaming mailbox 2024-10-31 11:00:03 +01:00
FreddleSpl0it
2d76ffc88c Merge pull request #6045 from mailcow/feat/rename-mbox
[Web][DockerApi] Add Feature to Rename Email Addresses
2024-10-25 10:49:58 +02:00
FreddleSpl0it
672bb345fd Fix mailbox_rename de-de translation 2024-10-25 10:47:53 +02:00
milkmaker
5c88030b5a Translations update from Weblate (#6123)
* [Web] Updated lang.lv-lv.json

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>

* [Web] Updated lang.zh-tw.json

[Web] Updated lang.zh-tw.json

Co-authored-by: SamWang8891 <g348.8891@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: SamWang8891 <g348.8891@gmail.com>
2024-10-22 21:52:42 +02:00
Niklas Meyer
b106945c73 Feat/rspamd 3.10.2 (#6122)
* rspamd: update to 3.10.2

* rspamd: fix broken archive_extension gz
2024-10-21 16:03:51 +02:00
milkmaker
502a7100ca [Web] Updated lang.zh-cn.json (#6120)
Co-authored-by: SamWang8891 <g348.8891@gmail.com>
2024-10-19 22:24:45 +02:00
Niklas Meyer
ee2791d93a rspamd: update to 3.10.1 (#6115)
* rspamd: upgrade to 3.10.1

* rspamd: adapt 30s task timeout per default now
2024-10-18 15:50:45 +02:00
SamWang8891
399630cf34 Update lang.zh-tw.json (#6114) 2024-10-17 14:50:05 +02:00
Patrik Kernstock
fce93609dd Update mime_types.conf configuration (#6013)
In the last months and years, the default `mime_types.conf` of rspamd has changed and it might be also useful to make some adjustments to the weight of certain file extensions.

This PR is removing all file extensions from `mime_types.conf` which are already in rspamd's default configuration at [rspamd/src/plugins/lua/mime_types.lua](https://github.com/rspamd/rspamd/blob/master/src/plugins/lua/mime_types.lua). If file extension is not present or has a different score compared to rspamd default, it is still in the list.

There are also a few major differences to certain file extensions, which might be useful to discuss and carefully adjust. For example, `.exe` files are rated very 'badly' due to high chance of being malicious, so are other extensions like `bat`, `cmd`, etc.

Current suggestion:
```lua
# Extensions that are treated as 'bad'
# Number is score multiply factor
bad_extensions = {
  apk = 4,
  appx = 4,
  appxbundle = 4,
  bat = 8,
  cab = 20,
  cmd = 8,
  com = 20,
  diagcfg = 4,
  diagpack = 4,
  dmg = 8,
  ex = 20,
  ex_ = 20,
  exe = 20,
  img = 4,
  jar = 8,
  jnlp = 8,
  js = 8,
  jse = 8,
  lnk = 20,
  mjs = 8,
  msi = 4,
  msix = 4,
  msixbundle = 4,
  ps1 = 8,
  scr = 20,
  sct = 20,
  vb = 20,
  vbe = 20,
  vbs = 20,
  vhd = 4,
  py = 4,
  reg = 8,
  scf = 8,
  vhdx = 4,
};

# Extensions that are particularly penalized for archives
bad_archive_extensions = {
  pptx = 0.5,
  docx = 0.5,
  xlsx = 0.5,
  pdf = 1.0,
  jar = 12,
  jnlp = 12,
  bat = 12,
  cmd = 12,
};

# Used to detect another archive in archive
archive_extensions = {
  tar = 1,
  ['tar.gz'] = 1,
};
```

**As a important reminder**: For all remaining and additional file extensions and score weights, please check above default rspamd configuration!
2024-10-17 09:11:55 +02:00
Niklas Meyer
38907b5032 dovecot: activate lazy_expunge plugin per default (unconfigured) (#6112) 2024-10-16 15:56:40 +02:00
Peter
5a0f20b9ea Update dependency twig/twig to v3.14.0 (#6071) 2024-10-16 15:29:16 +02:00
Niklas Meyer
8dcaffe925 php: upgrade to alpine 3.20 (base os) (#6106) 2024-10-16 10:35:54 +02:00
Niklas Meyer
c53bf85480 postfix: add X-Original-To header per default (#6110) 2024-10-16 10:35:39 +02:00
Niklas Meyer
982e823c71 sogo: upgrade to 5.11.1 (#6109) 2024-10-15 16:13:51 +02:00
renovate[bot]
382056ec18 chore(deps): update dependency krakjoe/apcu to v5.1.24 (#6087)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-15 11:24:26 +02:00
renovate[bot]
4c9690e87c chore(deps): update dependency php/pecl-mail-mailparse to v3.1.8 (#6096)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-15 11:09:23 +02:00
renovate[bot]
9a58e5e35a chore(deps): update dependency phpredis/phpredis to v6.1.0 (#6098)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2024-10-15 10:45:32 +02:00
renovate[bot]
932cf453de chore(deps): update dependency nextcloud/server to v28.0.11 (#6101)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-15 10:34:57 +02:00
milkmaker
1538fda71c update postscreen_access.cidr (#6093) 2024-10-15 10:34:39 +02:00
renovate[bot]
54a0d53deb chore(deps): update thollander/actions-comment-pull-request action to v3 (#6102)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-15 10:34:19 +02:00
Niklas Meyer
fda95301ba fix: added tls1.0/1.1 patch for openssl when using older tls versions in override (#6105) 2024-10-15 10:32:08 +02:00
FreddleSpl0it
f9304dcd9b [Web] check if $iam_provider is null on ldap_mbox_login 2024-10-09 12:34:39 +02:00
FreddleSpl0it
1528e8766a [DockerApi] correctly escape user input 2024-09-06 15:59:52 +02:00
FreddleSpl0it
0b9b8c9060 [Web] Ensure correct SOGo SSO password is used after Dovecot restart 2024-09-06 10:05:00 +02:00
Hassan A Hashim
220fdbb168 Add missing Russian translation (#6065) 2024-09-06 07:14:34 +02:00
milkmaker
fe3d08515e [Web] Language file updated by 'Cleanup translation files' addon (#6064) 2024-09-06 07:13:59 +02:00
airon-assustadus
22f7f61ac9 feat/brazilian-translations (#6048)
# What
- Adding some brazilian translations that were missing

Co-authored-by: Airon Teixeira <airon@ymail.com>
2024-09-05 15:09:49 +02:00
FreddleSpl0it
0d2046baeb Merge branch 'staging' into nightly 2024-09-05 14:53:37 +02:00
FreddleSpl0it
29d8cfe2ba [Web] Set min-width and text-align for last login badges 2024-09-05 14:02:04 +02:00
FreddleSpl0it
f2e35dff68 [Web] rename user in sender_acl table 2024-09-05 12:40:30 +02:00
FreddleSpl0it
b1368d29d1 Merge pull request #5724 from q16marvin/master
show last sso login in mailbox table
2024-09-05 12:02:16 +02:00
FreddleSpl0it
0d704a57f5 Merge pull request #6057 from mailcow/fix/sogo-auto-reply
[SOGo] Fix vacation auto reply date shifting
2024-09-05 11:19:40 +02:00
FreddleSpl0it
462137ede7 Merge pull request #6044 from mailcow/feat/redis-session-store
[PHP-FPM] Use redis as session store
2024-09-05 10:55:07 +02:00
Niklas Meyer
bb6f405841 compose: added clamd as depends_on to rspamd (#6062) 2024-09-04 14:42:30 +02:00
renovate[bot]
8b2d67169b chore(deps): update peter-evans/create-pull-request action to v7 (#6059)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 19:42:10 +02:00
Finn Hoffhenke
710cec996c feat: Added check for newer version tags on remote (#6054) 2024-09-02 15:40:29 +02:00
Niklas Meyer
0129f84a32 Merge pull request #6056 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-09-02 15:37:24 +02:00
FreddleSpl0it
ae3653a925 [SOGo] vacation auto reply date shifting #5394 2024-09-02 10:22:51 +02:00
FreddleSpl0it
82fcddb177 [Web] Fix catch block in LDAP connection test 2024-09-02 10:12:51 +02:00
FreddleSpl0it
320bd31d37 [Web] fix LDAP "ignore ssl errors" option 2024-09-02 10:02:10 +02:00
FreddleSpl0it
b307e0a0d5 [PHP-FPM] Add missing space in log message 2024-09-02 09:57:33 +02:00
milkmaker
af0c61b90a update postscreen_access.cidr 2024-09-01 00:19:09 +00:00
milkmaker
7203735532 [Web] Updated lang.it-it.json (#6053)
Co-authored-by: Stefano <stefano.vassena@gmail.com>
2024-08-29 20:27:23 +02:00
FreddleSpl0it
ef238e5332 [LDAP] skip sync user if username_field in LDAP is empty 2024-08-28 11:28:37 +02:00
FreddleSpl0it
4f9e37c0c3 [Web] rename user in bcc_maps, recipient_maps and imapsync table 2024-08-28 11:16:29 +02:00
FreddleSpl0it
d21c1bfa72 [Web] add error handling for get_acl call 2024-08-28 10:48:44 +02:00
FreddleSpl0it
822d9a7de6 [Web] rename goto in alias table 2024-08-27 10:07:07 +02:00
DerLinkman
37beed6ad9 update FUNDING.yml 2024-08-26 09:56:49 +02:00
milkmaker
0066040bdc Translations update from Weblate (#6049)
* [Web] Updated lang.cs-cz.json

Co-authored-by: Kristian Feldsam <feldsam@gmail.com>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Samuel F <20537389+samuelfranzini@users.noreply.github.com>

---------

Co-authored-by: Kristian Feldsam <feldsam@gmail.com>
Co-authored-by: Samuel F <20537389+samuelfranzini@users.noreply.github.com>
2024-08-24 14:09:28 +02:00
DerLinkman
75f18df143 Revert "Before update on 2024-08-20_14_22_10"
This reverts commit 89398c4726.
2024-08-23 09:54:10 +02:00
FreddleSpl0it
8e7b27aae4 [DockerApi] rework doveadm__get_acl function 2024-08-23 09:30:23 +02:00
FreddleSpl0it
c62b467ac4 [PHP-FPM] Use redis as session store 2024-08-22 11:16:01 +02:00
FreddleSpl0it
be5a181be5 [Web][DockerApi] migrate imap acl on mbox rename 2024-08-22 10:10:05 +02:00
FreddleSpl0it
dbf87e99fc [Web] Convert LDAP username_field and attribute_field to lowercase 2024-08-21 10:48:04 +02:00
FreddleSpl0it
10dfd0a443 [Web][DockerApi] Add the ability to rename the local part of a mailbox 2024-08-21 10:10:34 +02:00
milkmaker
cc5138da13 Translations update from Weblate (#6039)
* [Web] Updated lang.fr-fr.json

[Web] Updated lang.fr-fr.json

Co-authored-by: GeistFighter <lorentzjohan1@gmail.com>
Co-authored-by: Samuel F <20537389+samuelfranzini@users.noreply.github.com>

* [Web] Updated lang.fi-fi.json

Co-authored-by: Berttas <mika@tarh.fi>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Habetdin <15926758+Habetdin@users.noreply.github.com>

* [Web] Updated lang.uk-ua.json

Co-authored-by: DRago_Angel <dragoangel@users.noreply.translate.mailcow.email>

* [Web] Updated lang.pt-br.json

Co-authored-by: xmacaba <lixo@macaba.com.br>

---------

Co-authored-by: GeistFighter <lorentzjohan1@gmail.com>
Co-authored-by: Samuel F <20537389+samuelfranzini@users.noreply.github.com>
Co-authored-by: Berttas <mika@tarh.fi>
Co-authored-by: Habetdin <15926758+Habetdin@users.noreply.github.com>
Co-authored-by: DRago_Angel <dragoangel@users.noreply.translate.mailcow.email>
Co-authored-by: xmacaba <lixo@macaba.com.br>
2024-08-20 21:34:04 +02:00
DerLinkman
89398c4726 Before update on 2024-08-20_14_22_10 2024-08-20 14:22:55 +02:00
milkmaker
aeeac63e1f Fix: Escape a ' character in update.sh (#6034) (#6035)
Co-authored-by: Hassan A Hashim <h3ssan@protonmail.com>
2024-08-20 14:22:51 +02:00
DerLinkman
8971b11c49 Merge branch 'staging' 2024-08-20 14:08:57 +02:00
Hassan A Hashim
bb7fd483f7 Fix: Escape a ' character in update.sh (#6034) 2024-08-20 14:08:08 +02:00
Niklas Meyer
439a936fd8 Merge pull request #6033 from mailcow/staging
2024-08a
2024-08-20 13:44:51 +02:00
Niklas Meyer
ffcd242048 Merge pull request #6027 from mailcow/staging
Automatic PR to nightly from 2024-08-19T12:28:50Z
2024-08-20 13:41:54 +02:00
Délano
567ebbc324 Pushover/Quarantine utf 8 fix - fixes #6028 (#6031)
* Decode rspamd-subject for pushover notifications

Fixes #6028

* Apply iconv_mime_decode to the quarantine function as well
This might contain utf-8 encoded text as well

* Moved the iconv_mime_decode "fix" back to pipe.php
2024-08-20 13:39:20 +02:00
Hassan A Hashim
f9a7712025 Replace weird character to the correct ' (#6029)
* Replace weird character to the correct `'`

* Replace final weird character, just found.
2024-08-20 08:08:34 +02:00
Hassan A Hashim
3d62869664 Fix: bash variables are not quoted (#6022)
* Fix: Double quote variables to prevent word splitting

* Fix `update.sh`: Double quote to prevent word splitting

* Refactor: Remove unnecessary white-spaces.
2024-08-19 15:47:55 +02:00
DerLinkman
e21157c10d Merge branch 'staging' into nightly 2024-08-19 11:42:12 +02:00
Niklas Meyer
b70bcd36fb containers: use mariadb-admin instead of deprecated mysqladmin (#6026)
* dockerfiles: use mariadb-admin instead of deprecated mysqladmin command

* compose: bump compose tags
2024-08-19 11:33:28 +02:00
Niklas Meyer
cb50d08605 dovecot: added timeout option when sa-rules cannot be downloaded (#6025)
* dovecot: added timeout option when sa-rules cannot be downloaded

* dovecot: changed sa-rules exit code to 0 to allow dovecot to start afterwards
2024-08-19 11:08:13 +02:00
Hassan A Hashim
f3da8bb85f Refactor/Change Dockerfiles cmd from shell to exec form (#6019)
* Update `dockerapi/Dockerfile` CMD from shell to exec format

* Update `postfix/Dockerfile` CMD from shell to exec format

* Update `sogo/Dockerfile` CMD from shell to exec format

* Update `unbound/Dockerfile` CMD from shell to exec format

* Update `watchdog/Dockerfile` CMD from shell to exec format
2024-08-19 10:42:11 +02:00
Niklas Meyer
12e4d639f0 Merge pull request #6016 from jkrgr0/fix/ParseDockerVersion 2024-08-16 10:50:04 +02:00
Janek
eb3f88fc91 fix: 🚑 Fixed version parsing of docker
Only the first result (the major version) is relevant

Closes #6015
2024-08-16 08:47:03 +02:00
Niklas Meyer
9a729d89bf Merge pull request #6012 from mailcow/staging
2024-08
2024-08-15 14:46:50 +02:00
FreddleSpl0it
fa3c453d6e Use DN instead of DistinguishedName for LDAP login 2024-08-15 12:49:57 +02:00
FreddleSpl0it
962ac39e4a Merge remote-tracking branch 'origin/staging' into nightly 2024-08-15 12:45:52 +02:00
Niklas Meyer
74b4097ee0 Merge pull request #6011 from mailcow/gh/add_pull_request_template
.github: Add pull_request_template.md
2024-08-15 11:51:37 +02:00
DerLinkman
e00d0d5f8d Updated contributing.md 2024-08-15 11:32:28 +02:00
DerLinkman
c5e399ebc2 .github: Add pull_request_template.md 2024-08-15 11:09:37 +02:00
FreddleSpl0it
cb9ca772b1 Merge pull request #6009 from mailcow/feat/pw-reset
[Web] Add a forgot password flow
2024-08-15 11:06:30 +02:00
Niklas Meyer
ebc8e6b838 Merge pull request #6008 from mailcow/staging
Automatic PR to nightly from 2024-08-15T07:42:17Z
2024-08-15 09:53:17 +02:00
Niklas Meyer
162f05ccda Merge pull request #6007 from mailcow/revert-5945-master
Revert "Don't expose SMTP/IMAP if announced "not provided" via SRV"
2024-08-15 09:51:19 +02:00
Niklas Meyer
6c97c4f372 Revert "Don't expose SMTP/IMAP if announced "not provided" via SRV" 2024-08-15 09:50:36 +02:00
DerLinkman
1fc964d72e compose: bump dovecot image to newest nightly (20240814) 2024-08-14 10:12:10 +02:00
DerLinkman
5571d80ae6 Merge branch 'staging' into nightly 2024-08-14 10:10:34 +02:00
Niklas Meyer
6d4fcacd83 Merge pull request #6006 from mailcow/fix/issue-5986
flatcurve-fts: limit tokenizers size in e-mail adress
2024-08-14 10:06:17 +02:00
DerLinkman
1994f706c0 dovecot: optimized dockerfile syntax 2024-08-14 10:03:42 +02:00
DerLinkman
e34afd3fdd flatcurve-fts: limit tokenizers for email adresses 2024-08-14 10:02:59 +02:00
DerLinkman
a6f71faf46 github-actions: compacted auto nightly pr 2024-08-13 16:07:09 +02:00
DerLinkman
3396e1b427 Merge branch 'staging' into nightly 2024-08-13 16:03:30 +02:00
Niklas Meyer
b26ccc2019 unbound: fix healthcheck logging + added fail tolerance to checks (#6004)
* unbound: fix healthcheck logging to stdout + rewrote healthcheck logic

* compose: bump unbound tag

* unbound: fixed healthcheck logic
2024-08-13 15:59:57 +02:00
FreddleSpl0it
58a5a4578c [Web] use cn as fallback ldap login 2024-08-13 12:14:05 +02:00
Niklas Meyer
b1c1e403d2 sogo: update to 5.11.0 + Rebase on Bookworm (#6002)
* sogo: update to 5.11.0

* compose: bump sogo compose tag
2024-08-13 09:43:59 +02:00
FreddleSpl0it
519d95cb8b [Web] extend ldap auth logging 2024-08-13 09:30:54 +02:00
FreddleSpl0it
092d3cd80b [Web] extend ldap auth logging 2024-08-12 10:14:53 +02:00
FreddleSpl0it
c034f4bd27 [Web] fix wrong log type on PDOException 2024-08-12 10:10:33 +02:00
Dmitriy Alekseev
8753ea2be6 [Rspamd] Fix bayes config (#6000)
* [Rspamd] Fix bayes config

Add hint about classifier name, and add missing learn_condition

* Update statistic.conf
2024-08-12 10:05:08 +02:00
milkmaker
9fee568082 Translations update from Weblate (#5999)
* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

---------

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
2024-08-10 20:44:40 +02:00
FreddleSpl0it
73d60eb085 Merge pull request #5997 from mailcow/fix/nightly-tfa
[Web] fix incorrect user role assignment after TFA verification
2024-08-08 17:11:57 +02:00
FreddleSpl0it
b39b7c24a5 [Web] fix incorrect user role assignment after TFA verification 2024-08-08 17:04:56 +02:00
DerLinkman
294a406b91 fix: disabled api call to solr in ui when mailbox deleted but using flatcurve 2024-08-08 09:25:52 +02:00
Niklas Meyer
8b933f1967 Merge pull request #5934 from muhlba91/fix/restore-docker 2024-08-08 08:47:12 +02:00
DerLinkman
d0ecb72e08 Merge branch 'staging' into nightly 2024-08-08 08:44:12 +02:00
Kitof
824a473fea ofelia: limit scope to mailcow project (#5776)
* Filter to limit ofelia scope

See https://github.com/mailcow/mailcow-dockerized/issues/5775

* compose: added ${COMPOSE_PROJECT_NAME} ENV to ofelia container
2024-08-08 08:42:50 +02:00
milkmaker
7f790c5360 [Web] Updated lang.si-si.json (#5995)
Co-authored-by: gomiunik <boris@gomiunik.net>
2024-08-07 18:39:38 +02:00
DerLinkman
52431a3942 compose: bump watchdog image 2024-08-07 14:50:12 +02:00
Niklas Meyer
8017394e9d Merge pull request #5773 from mrclschstr/staging
[Fix] Watchdog: escape subject and body for webhooks
2024-08-07 14:48:11 +02:00
DerLinkman
772d5c51fd Merge branch 'staging' into nightly 2024-08-07 14:21:23 +02:00
Niklas Meyer
76194be7dd Merge pull request #5991 from h3ssan/refactor/update-script-help-exit
Refactor: `update.sh` script with `--help` should exit with status code 0
2024-08-07 14:03:32 +02:00
Niklas Meyer
3b23afa0ff Merge pull request #5661 from mailcow/feat/rspamd-3.8
rspamd: upgrade to rspamd 3.9.1
2024-08-07 14:01:39 +02:00
DerLinkman
6e00d653ce compose: bumped rspamd tag 2024-08-07 14:00:04 +02:00
DerLinkman
b6c036496d rspamd: fixed dqs rbl insertion handling 2024-08-07 14:00:04 +02:00
DerLinkman
5d7c9b20bc rspamd: upgrade to 3.9.1 + upgrade to bookworm 2024-08-07 14:00:04 +02:00
DerLinkman
4b400eadb1 rspamd: Added DQS RBLs when key is set 2024-08-07 13:59:26 +02:00
Niklas Meyer
ab2abda8cc Merge pull request #5967 from Doozy134/fix/curl-hostname
fix: change internal urls for containers using curl on alpine
2024-08-07 13:58:11 +02:00
Hassan A Hashim
2fe21e9641 Refactor: update.sh script with --help should exit with status code 0 2024-08-07 14:57:36 +03:00
Niklas Meyer
b7ed6982d8 Merge pull request #5945 from SailReal/master
Don't expose SMTP/IMAP if announced "not provided" via SRV
2024-08-07 13:51:10 +02:00
Niklas Meyer
fd927853cb Merge pull request #5990 from h3ssan/fix/dockerfile-label-fix
Fix `LABEL` in Dockerfile, should be key=value
2024-08-07 13:49:07 +02:00
Niklas Meyer
c48f4f4ab8 Merge pull request #5989 from h3ssan/fix/update-script-procceding-typo
Fix typo in `update.sh`: word Proceeding
2024-08-07 13:47:57 +02:00
DerLinkman
a4c006828e compose: bump container tags 2024-08-07 09:51:47 +02:00
DerLinkman
b56291f62b adapt scheme to affected curl containers (dirty way... but workaround) 2024-08-07 09:50:57 +02:00
Kasim
0cdf7647c4 Include COMPOSE_PROJECT_NAME in Nginx url 2024-08-07 09:40:08 +02:00
Kasim
8fe1cc4961 change nginx address
#5962
2024-08-07 09:40:04 +02:00
Niklas Meyer
bf050f17c4 Merge pull request #5987 from h3ssan/fix/validate-mailcow-conf-before-source
Bug Fix: Check `mailcow.conf` exists before work with it
2024-08-07 09:33:16 +02:00
Hassan A Hashim
edd85dea8d Fix LABEL in Dockerfile, should be key=value
Refering to the [Official Docker Docs](`https://docs.docker.com/reference/dockerfile/#label`), clearly said the format of LABEL is `LABEL <key>=<value> <key>=<value> <key>=<value> ...`.
2024-08-06 22:44:59 +03:00
Hassan A Hashim
3bf90c1f73 Fix typo for word Potential in update.sh file. 2024-08-06 21:22:30 +03:00
Hassan A Hashim
292306b191 Fix typos and English grammar in update.sh
German is different in using upper-case than English lol
2024-08-06 21:12:20 +03:00
Hassan A Hashim
b3e0a66222 Fix typo: receiving updates from an unsupported branch 2024-08-06 21:03:17 +03:00
Hassan A Hashim
e994cf4d05 Fix typo in update.sh: Proceeding 2024-08-06 20:38:18 +03:00
Hassan A Hashim
cc0dc2eae0 Add color-coded error message for missing mailcow.conf 2024-08-06 17:51:46 +03:00
DerLinkman
a001a0584f update.sh: fix text for min. docker ver 2024-08-06 16:21:28 +02:00
DerLinkman
926af87cfb scripts: adding docker version check to align to docs (24.X) 2024-08-06 16:20:28 +02:00
Hassan A Hashim
b0339372b5 Check mailcow.conf exists before source it 2024-08-06 17:12:54 +03:00
Niklas Meyer
e398cb91e9 Merge pull request #5985 from mailcow/feat/improve-sieve-parser
ui: added enotify and mime as valid options for ui
2024-08-06 15:36:00 +02:00
DerLinkman
6ee0303b0f ui: added enotify and mime as valid options for ui 2024-08-06 15:33:40 +02:00
Niklas Meyer
68616c2d57 Merge pull request #5972 from rallisf1/dovecot-folders-greek
Greek names of dovecot folders
2024-08-06 12:28:23 +02:00
Niklas Meyer
f8de520d29 Merge pull request #5983 from mailcow/fix/sieve-compiling
dovecot: fix precompiling of sieve scripts
2024-08-06 12:27:41 +02:00
Niklas Meyer
10077ece31 Merge pull request #5804 from Ayowel/feat/unattended-install
Allow prompt-less install on low-resource systems
2024-08-06 12:26:51 +02:00
DerLinkman
c918726143 dovecot: fix precompiling of sieve scripts 2024-08-06 12:04:04 +02:00
milkmaker
3885b07a99 [Web] Updated lang.nb-no.json (#5980)
Co-authored-by: Christer Solstrand Johannessen <csjoh@users.noreply.translate.mailcow.email>
2024-08-05 19:36:55 +02:00
FreddleSpl0it
fcf27d640d Merge pull request #5979 from mailcow/staging
2024-07
2024-08-05 08:55:59 +02:00
Marcel Schuster
82fde23cc1 Bump watchdog to v2.03 2024-08-01 19:14:29 +02:00
FreddleSpl0it
9b86ff764e Merge pull request #5975 from mailcow/staging
Automatic PR to nightly from 2024-08-01T03:13:55Z
2024-08-01 11:07:55 +02:00
FreddleSpl0it
cbca306fc1 Merge pull request #5976 from mailcow/fix/get-tfa
2024-07 fixes
2024-08-01 11:04:04 +02:00
Niklas Meyer
6a8986fe4f Merge pull request #5974 from mailcow:update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-08-01 09:06:42 +02:00
milkmaker
ff34eb12e2 update postscreen_access.cidr 2024-08-01 00:16:46 +00:00
FreddleSpl0it
57bc03b878 Merge remote-tracking branch 'origin/staging' into nightly 2024-07-31 10:35:44 +02:00
FreddleSpl0it
fbecd60e56 [Web] add new pw_reset acl to mailbox templates 2024-07-31 09:23:53 +02:00
FreddleSpl0it
c37bf0bb32 [Web] improve error handling for user password resets 2024-07-31 09:22:52 +02:00
FreddleSpl0it
2208d7e6fb [Web] add function to reset user passwords 2024-07-30 14:46:08 +02:00
John Rallis
e426c3a7e7 Greek names of dovecot folders
Names taken from MSO 2016
2024-07-29 16:46:03 +03:00
Niklas Meyer
03fccb28e9 Merge pull request #5971 from mailcow/dragoangel-patch-1
Do not add MAILCOW_WHITE on failed DMARC
2024-07-29 09:51:16 +02:00
Dmitriy Alekseev
8fbfd99dd6 Update composites.conf 2024-07-28 13:20:24 +02:00
Dmitriy Alekseev
7f7a869678 Do not add MAILCOW_WHITE on failed DMARC 2024-07-28 13:19:03 +02:00
DerLinkman
73257151c4 postfix: remove forced helo restrictions from master.cf 2024-07-24 15:29:28 +02:00
FreddleSpl0it
efb2572f0f [Web] escapeHtml in relayhosts table 2024-07-22 15:05:43 +02:00
FreddleSpl0it
66aa28b5de [Web] escapeHtml in api_log table 2024-07-22 15:04:29 +02:00
Niklas Meyer
987a027339 Merge pull request #5957 from mailcow/staging
2024-06c
2024-07-12 16:25:01 +02:00
Niklas Meyer
eea81e21f6 Revert "php: Rebase on Debian 12" (#5956)
* Revert "php: Rebase on Debian 12 (#5951)"

This reverts commit 9b478b3859.

* Revert all before "the storm" in php world
2024-07-12 16:21:53 +02:00
Niklas Meyer
a689109f44 Merge pull request #5955 from mailcow/revert-5875-staging_cml
Revert "Update debug.twig to include a link to the git project URL for the mailcow version tag"
2024-07-12 16:05:01 +02:00
Niklas Meyer
58c0a46459 Revert "Update debug.twig to include a link to the git project URL for the mailcow version tag" 2024-07-12 16:04:19 +02:00
Niklas Meyer
2dbe8bf4ca Merge pull request #5952 from mailcow/staging
2024-06b
2024-07-12 10:17:46 +02:00
Niklas Meyer
ef7ec06947 Merge pull request #5930 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-07-12 10:16:44 +02:00
DerLinkman
fc7ea7a247 web: remove WIP notice for ARM64 from ui 2024-07-12 10:15:06 +02:00
Niklas Meyer
9b478b3859 php: Rebase on Debian 12 (#5951)
* php: rebuild on debian 12

* Restored one build dockerfile

* cleanup Dockerfile
2024-07-12 09:40:10 +02:00
Julian Raufelder
384e5a2e64 Don't expose SMTP/IMAP if announced "not provided" via SRV
Fixes #5944
2024-07-09 19:57:32 +02:00
Niklas Meyer
aadeeb0df3 Merge pull request #5634 from torzech/proper-threads-regex
Enhanced regular expression for THREADS parameter
2024-07-09 10:10:42 +02:00
FreddleSpl0it
f33d82ffc1 [Web] use correct user to fetch TFA authenticators 2024-07-03 15:50:17 +02:00
Daniel Muehlbachler-Pietrzykowski
ffeeb179e1 restore: remove tty requirement from restore process to allow for automated restores 2024-07-03 10:53:37 +02:00
milkmaker
8e2d3a6db5 update postscreen_access.cidr 2024-07-01 00:16:56 +00:00
Niklas Meyer
70126e1f0c Merge pull request #5926 from mailcow/staging
🌙🐄 Moone Update 2024 | Revision A
2024-06-27 18:07:19 +02:00
Niklas Meyer
b9ae174a6a Merge pull request #5925 from mailcow/revert-5912-weblate-translated
Revert "Translations update from Weblate"
2024-06-27 18:04:41 +02:00
Niklas Meyer
9715c57314 Revert "Translations update from Weblate (#5912)"
This reverts commit 1af9c21a50.
2024-06-27 18:03:01 +02:00
Niklas Meyer
b9f8959d92 Update CONTRIBUTING.md
Added language terms
2024-06-27 13:11:19 +02:00
Niklas Meyer
9c814cc182 Merge pull request #5922 from mailcow/staging
2024-06
2024-06-27 11:15:53 +02:00
Niklas Meyer
cf6594220c dovecot: add Flatcurve FTS Engine as EXPERIMENTAL (#5920)
* dovecot: experimental added flatcurve backend + switch

* dovecot: bump docker image
2024-06-26 11:28:18 +02:00
Niklas Meyer
2cf952eb36 [Postfix] Upgrade to Deb12 + PF to 3.7.10 & Drop TLS 1.0/1.1 per default (#5635)
* postfix: removed TLS1.0/1.1 support (natively)

* postfix: upgrade to deb12 + pf to 3.7.9

* compose: increased postfix tag

* postfix: shortened TLS syntax with new format of 3.6+
2024-06-26 10:44:07 +02:00
DerLinkman
6fc86dd7d3 acme: corrected acme-tiny download path 2024-06-24 10:00:30 +02:00
DerLinkman
bf13af9691 increased rspamd image tag 2024-06-24 10:00:16 +02:00
milkmaker
1af9c21a50 Translations update from Weblate (#5912)
* [Web] Updated lang.ca-es.json

[Web] Updated lang.ca-es.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.cs-cz.json

[Web] Updated lang.cs-cz.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.da-dk.json

[Web] Updated lang.da-dk.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.es-es.json

[Web] Updated lang.es-es.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.fi-fi.json

[Web] Updated lang.fi-fi.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.fr-fr.json

[Web] Updated lang.fr-fr.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.hu-hu.json

[Web] Updated lang.hu-hu.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ro-ro.json

[Web] Updated lang.ro-ro.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.it-it.json

[Web] Updated lang.it-it.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ko-kr.json

[Web] Updated lang.ko-kr.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.nl-nl.json

[Web] Updated lang.nl-nl.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.pl-pl.json

[Web] Updated lang.pl-pl.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ru-ru.json

[Web] Updated lang.ru-ru.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.sk-sk.json

[Web] Updated lang.sk-sk.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.sv-se.json

[Web] Updated lang.sv-se.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.zh-cn.json

[Web] Updated lang.zh-cn.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Anonymous <noreply@weblate.org>

* [Web] Updated lang.zh-tw.json

[Web] Updated lang.zh-tw.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.pt-pt.json

[Web] Updated lang.pt-pt.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.si-si.json

[Web] Updated lang.si-si.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.gr-gr.json

[Web] Updated lang.gr-gr.json

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.nb-no.json

Co-authored-by: Anonymous <noreply@weblate.org>

* [Web] Updated lang.lt-lt.json

Co-authored-by: Anonymous <noreply@weblate.org>

---------

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Peter <magic@kthx.at>
2024-06-24 09:07:46 +02:00
realizelol
443941e687 [Rspamd] Delete overriding obsolete rspamd plugin (#5900)
* [Dockerfiles] rspamd: Delete COPY of metadata_exporter.lua plugin

* [Dockerfiles] rspamd: Delete metadata_exporter.lua plugin file

* Dockerfile: changed way of installing rspamd (granular version)

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
2024-06-24 09:07:12 +02:00
renovate[bot]
527577b438 chore(deps): update docker/build-push-action action to v6 (#5910)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 17:38:21 +02:00
milkmaker
9daf2d80c0 Translations update from Weblate (#5908)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Paul FERA <paulfera17@gmail.com>

* [Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

Co-authored-by: Deniss <mailcow@rigaden.me>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>

---------

Co-authored-by: Paul FERA <paulfera17@gmail.com>
Co-authored-by: Deniss <mailcow@rigaden.me>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
2024-06-16 19:21:46 +02:00
Daniel
38b0641742 Remove unnecessary log lines in Postfix's log (#5817)
* Update main.cf

In order to avoid unnecessary log lines, changed:

smtpd_discard_ehlo_keywords = chunking
to this one:

# The non-logging alternative:
smtpd_discard_ehlo_keywords = chunking, silent-discard

Update main.cf to remove unnecessary log lines in Postfix log
2024-06-10 14:51:55 +02:00
Niklas Meyer
f675af5bb0 Merge pull request #5902 from mailcow/feat/nextcloud-deprecation
nextcloud: add deprecation notice once script start
2024-06-10 14:33:53 +02:00
DerLinkman
533c4e7956 nextcloud: add deprecation notice once script start 2024-06-10 14:21:13 +02:00
Niklas Meyer
1b2c2c0037 Merge pull request #5690 from mailcow:renovate/nextcloud-server-28.x
chore(deps): update dependency nextcloud/server to v28.0.6
2024-06-10 13:57:09 +02:00
Niklas Meyer
97768494e1 Merge pull request #5880 from PierrePlt:fix/blocking-last-logins
Fix blocking last logins fetching
2024-06-10 12:40:43 +02:00
Lasagne
4a052da289 Add switch to skip fetching certificates auto{config,discover} subdomains (#5838)
* Add ACME_DONT_FETCH_CERTS_FOR_HTTP_SUBDOMAINS to acme.sh

* Add ACME_DONT_FETCH_CERTS_FOR_HTTP_SUBDOMAINS to docker-compose.yml

* Add ACME_DONT_FETCH_CERTS_FOR_HTTP_SUBDOMAINS to generate_config.sh

* Add ACME_DONT_FETCH_CERTS_FOR_HTTP_SUBDOMAINS to update.sh

* AUTODISCOVER_SAN instead of long string

default on,
default is fetching certs for auto{discover,conf}

* AUTODISCOVER_SAN instead of long string

also flipped

* AUTODISCOVER_SAN instead of long string

flipped default meaning

* fix explanation for AUTODISCOVER_SAN

* AUTODISCOVER_SAN instead of long string

and flipped meaning of the bool

* fix AUTODISCOVER_SAN explanation

* Merge branch 'mailcow:staging' into staging

* update.sh: corrected syntax for mailcow.conf insertion
2024-06-10 12:33:02 +02:00
Niklas Meyer
18d7a55b15 Merge pull request #5901 from mailcow:sorbs
Remove discontinued SORBS DNSBL
2024-06-10 12:18:43 +02:00
Michael Kuron
9ca2fb7ccf Remove discontinued SORBS DNSBL 2024-06-08 12:29:08 +02:00
Niklas Meyer
b4e8355827 Merge pull request #5845 from iamspido:patch-1
remove version from docker-compose.yml
2024-06-06 15:30:15 +02:00
DerLinkman
e0bde1c459 compose: removed all versions declarations (DEPRECATED) 2024-06-06 15:29:34 +02:00
Niklas Meyer
27c007ebd3 Merge pull request #5750 from DocFraggle:staging
Fix unbound healthcheck.sh to log all messages to logfile
2024-06-06 15:27:40 +02:00
FreddleSpl0it
f7ae2a6162 [Nightly][SOGo] Update 5.10.0 2024-06-06 12:12:30 +02:00
Niklas Meyer
8f3ea09732 Merge pull request #5893 from mailcow/feat/base-os
os: updated all Alpine containers to 3.20
2024-06-05 13:10:10 +02:00
DerLinkman
af626d98d3 dovecot: fixed sa-rules download 2024-06-05 13:07:12 +02:00
Niklas Meyer
34b0574e56 Merge pull request #5886 from Thomas2500:patch-1
Switch IP2Country lookup backend to shortened version
2024-06-05 12:37:31 +02:00
Niklas Meyer
49d738809b Merge pull request #5863 from mailcow:update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-06-05 12:32:56 +02:00
Niklas Meyer
2fa3a22eca Merge pull request #5875 from CallMeLeon167:staging_cml
Update debug.twig to include a link to the git project URL for the mailcow version tag
2024-06-05 12:31:33 +02:00
Niklas Meyer
dc5eb6f92e Merge pull request #5883 from mailcow:renovate/alpine-3.x
chore(deps): update alpine docker tag to v3.20
2024-06-05 12:27:28 +02:00
DerLinkman
ba8902f0b1 os: updated all Alpine containers to 3.20 2024-06-05 11:52:48 +02:00
FreddleSpl0it
3080a70287 [Nightly][SOGo] Update to 5.10.0 2024-06-03 09:20:54 +02:00
milkmaker
11e9a77840 update postscreen_access.cidr 2024-06-01 00:15:03 +00:00
Thomas Bella
64cd7e74c5 Switch IP2Country lookup backend to shortened version
Improves performance of #5880
2024-05-28 20:29:05 +02:00
renovate[bot]
cac65d081e chore(deps): update dependency nextcloud/server to v28.0.6
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2024-05-28 12:54:13 +00:00
renovate[bot]
e5ada994be Update alpine Docker tag to v3.20
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2024-05-22 18:17:51 +00:00
Pierre Pelletier
6ba2459645 Fixed blocking last connection fetching 2024-05-18 11:38:41 +00:00
DerLinkman
58f63aad08 [UI] Corrected Sieve Preset 1 (Fixed Regex) 2024-05-13 15:02:41 +02:00
milkmaker
8a8687a63c [Web] Updated lang.zh-cn.json (#5876)
Co-authored-by: Koala Ng <tonghoil@hotmail.com>
2024-05-10 22:38:08 +02:00
Leon Schmidt
f7f93c360d fix formatting of the mailcow version tag link 2024-05-10 19:56:31 +02:00
Leon
c160e1f68e Update debug.twig 2024-05-10 15:57:36 +02:00
Leon Schmidt
47c08ab8d2 Update debug.twig target="_blank" attribute for the mailcow version tag link 2024-05-10 15:17:49 +02:00
Leon Schmidt
cd83ffbaa2 Update debug.twig to include a link to the git project URL for the mailcow version tag 2024-05-10 15:09:27 +02:00
milkmaker
e12981a821 [Web] Updated lang.zh-cn.json (#5873)
Co-authored-by: Koala Ng <tonghoil@hotmail.com>
2024-05-07 17:44:37 +02:00
Ramis
47fd1bb894 Update lang.ru-ru.json (#5865)
Update lang

Co-authored-by: Patrick Schult <75116288+FreddleSpl0it@users.noreply.github.com>
2024-05-03 14:05:43 +02:00
milkmaker
20582b6353 [Web] Updated lang.lv-lv.json (#5862)
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
2024-04-30 18:28:09 +02:00
Patrick Schult
caee770e36 Merge pull request #5850 from mailcow/fix/nightly-autodiscover
[Web] Fix autodiscover fails with external IdP
2024-04-19 20:38:56 +02:00
FreddleSpl0it
95d6eeb37a [Web] revert include prerequisites in autodiscover - include autoload 2024-04-19 20:32:44 +02:00
FreddleSpl0it
eadf70d809 [Web] include prerequisites in autodiscover 2024-04-18 14:23:35 +02:00
IamSpido
c8ff5387c0 remove version from docker-compose.yml
With docker version 25.05 the version 2.1 in docker-compose.yml will be obsolete.
docker-compose.yml: `version` is obsolete
2024-04-16 14:10:44 +02:00
Mitchell van Bijleveld
7cb138d515 Improve Dutch translation (#5840) 2024-04-11 21:36:45 +02:00
milkmaker
3dd4c45fab Translations update from Weblate (#5839)
* [Web] Updated lang.hu-hu.json

Co-authored-by: David Csillag <csillag.david.istvan@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.lv-lv.json

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: David Csillag <csillag.david.istvan@gmail.com>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
2024-04-10 21:55:31 +02:00
polido
549539bec9 Update lang.pt-pt.json (#5832)
Co-authored-by: Patrick Schult <75116288+FreddleSpl0it@users.noreply.github.com>
2024-04-08 17:48:41 +02:00
milkmaker
e449cac464 Translations update from Weblate (#5835)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Quiwy <github@quiwy.ninja>

* [Web] Updated lang.sv-se.json

Co-authored-by: André J <aj@nadox.se>

---------

Co-authored-by: Quiwy <github@quiwy.ninja>
Co-authored-by: André J <aj@nadox.se>
2024-04-08 17:47:43 +02:00
milkmaker
62e458f39b [Web] Updated lang.fr-fr.json (#5824)
Co-authored-by: Quiwy <github@quiwy.ninja>
2024-04-04 19:23:02 +02:00
FreddleSpl0it
b37caaf9e5 [Web] secure container_ctrl.php 2024-04-04 16:30:35 +02:00
FreddleSpl0it
7660ca89ae [Web] break loop if rspamd_map is valid 2024-04-04 16:29:58 +02:00
Patrick Schult
6e9c3e2687 Merge pull request #5821 from mailcow/fix/web-nightly
Fix/web nightly
2024-04-04 09:33:22 +02:00
FreddleSpl0it
cf2fda66e2 [Web] escape html of alert messages 2024-04-04 09:31:20 +02:00
FreddleSpl0it
cd24057f1a [Web] use SEC_FETCH_DEST header to block api requests 2024-04-04 09:31:03 +02:00
FreddleSpl0it
c68a436a22 [Web] fix invalid rspamd map check 2024-04-04 09:30:30 +02:00
Patrick Schult
36b5cccd18 Merge pull request #5819 from mailcow/staging
2024-04
2024-04-04 08:50:58 +02:00
Patrick Schult
9decfa9c31 Merge pull request #5818 from mailcow/fix/web
[Web] fix exception handler and rspamd_maps function
2024-04-04 08:19:58 +02:00
FreddleSpl0it
3aee2b6cf5 [Web] use SEC_FETCH_DEST header instead of Referer to block api requests 2024-04-03 11:43:48 +02:00
Patrick Schult
17d797cee4 Merge pull request #5751 from mailcow/fix/rspamd-rewrite-ct
[Rspamd] milter update Content-Type and Content-Transfer-Encoding header
2024-04-03 10:49:21 +02:00
Patrick Schult
75550eeea3 Merge pull request #5812 from mailcow/limit-local-addrs
[Rspamd] Set local_addrs lo mailcow networks
2024-04-03 10:48:46 +02:00
FreddleSpl0it
0d09c86c12 [Web] fix invalid rspamd map check 2024-04-03 10:08:18 +02:00
FreddleSpl0it
2db8f482db [Web] escape html of alert messages 2024-04-03 10:07:36 +02:00
FreddleSpl0it
00d4b32a1b [Web] deny api calls from sogo 2024-04-03 10:06:43 +02:00
milkmaker
8a82bab1f3 [Web] Updated lang.tr-tr.json (#5815)
Co-authored-by: Uğurcan Albayrak <canalbayrakugur@gmail.com>
2024-04-02 18:04:30 +02:00
milkmaker
237a25e6b0 update postscreen_access.cidr (#5811) 2024-04-02 02:20:31 +02:00
milkmaker
5dc836671d [Web] Updated lang.tr-tr.json (#5813)
[Web] Updated lang.tr-tr.json

Co-authored-by: Uğurcan Albayrak <canalbayrakugur@gmail.com>
Co-authored-by: evrenkoksal <evrenkoksal@gmail.com>
2024-04-01 21:57:15 +02:00
Dmitriy Alekseev
26be1cb602 Set local_addrs in Rspamd 2024-04-01 11:28:06 +03:00
yvan-algoo
dc7a48cbf9 Update French translation (#5805)
* Fix some typo in French translation

* Fix typo error introduced in last commit

* Fixed another typo introduced in my first commit
2024-03-30 01:10:12 +01:00
milkmaker
52455be815 Translations update from Weblate (#5810)
* [Web] Updated lang.lt-lt.json

[Web] Updated lang.lt-lt.json

[Web] Updated lang.lt-lt.json

[Web] Updated lang.lt-lt.json

[Web] Updated lang.lt-lt.json

[Web] Updated lang.lt-lt.json

[Web] Added lang.lt-lt.json

Co-authored-by: Ari Archer <ari@ari.lt>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

[Web] Updated lang.lv-lv.json

Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: Edgars Počs <edgars.pocs@dna.lv>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

[Web] Updated lang.tr-tr.json

Co-authored-by: evrenkoksal <evrenkoksal@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* Add lt-lt in vars.inc.php

---------

Co-authored-by: Ari Archer <ari@ari.lt>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
Co-authored-by: Edgars Počs <edgars.pocs@dna.lv>
Co-authored-by: evrenkoksal <evrenkoksal@gmail.com>
2024-03-30 01:09:22 +01:00
Ayowel
5c851f2935 Allow prompt-less install on low-resource systems 2024-03-26 08:19:24 +01:00
Niklas Meyer
bbbdcfb625 Merge pull request #5743 from mailcow/fix-5742
Remove one GmbH in Dockerfiles
2024-03-20 09:37:45 +01:00
Niklas Meyer
b054a57e16 Merge pull request #5770 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-03-19 10:19:54 +01:00
aaadddfgh
fd73b3ad88 Update lang.zh-cn.json (#5789)
Change a better translation
2024-03-13 15:53:37 +01:00
FreddleSpl0it
0807c122f6 [Web] set default LDAP options on get 2024-03-08 15:11:49 +01:00
FreddleSpl0it
e0bda6ca6a [Web] prevent multiple dual-logins 2024-03-08 14:05:37 +01:00
FreddleSpl0it
2ba64e93f9 [Web] allow SSL / TLS connections for LDAP 2024-03-08 13:50:20 +01:00
FreddleSpl0it
e1c3ad9fe8 [Web] return idp instance after init 2024-03-08 13:15:35 +01:00
milkmaker
8c0637b556 [Web] Updated lang.lv-lv.json (#5777)
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
2024-03-05 17:57:55 +01:00
Marcel Schuster
914a8204d4 Watchdog: escape subject and body for webhooks 2024-03-01 23:07:05 +01:00
DerLinkman
d92ffe8fc7 helper: remove old SOGo repo to not break builds on ARM64 2024-03-01 11:41:11 +01:00
milkmaker
e0eb3a4f13 update postscreen_access.cidr 2024-03-01 00:14:54 +00:00
Niklas Meyer
1fb0060a73 Merge pull request #5765 from mailcow/feat/sogo-5.10
sogo: upgrade to 5.10.0
2024-02-27 08:22:19 +01:00
DerLinkman
d7430bf516 sogo: add new options to sogo.conf for update 5.10.0 2024-02-26 17:17:34 +01:00
DerLinkman
35f039a119 sogo: update to 5.10.0 2024-02-26 16:55:13 +01:00
FreddleSpl0it
ffbf1758e0 [Web] fix identity_provider ArgumentCountError 2024-02-26 13:40:34 +01:00
Patrick Schult
a3af2d8392 Merge pull request #5764 from mailcow/fix/nightly-issues
Fix nightly issues with new ldap provider
2024-02-26 13:33:44 +01:00
FreddleSpl0it
39a4b115ed [SOGo] fix plist_ldap.sh example 2024-02-26 13:14:08 +01:00
FreddleSpl0it
881c2d6e02 [SOGo] remove custom logout from toolbar 2024-02-26 13:13:50 +01:00
FreddleSpl0it
d237157c0b init identity_provider only after all conditions are met 2024-02-26 13:12:44 +01:00
FreddleSpl0it
6928eb632e [Dovecot] move sogo sso to mailcowauth.php 2024-02-26 13:10:08 +01:00
milkmaker
79432a40d7 Translations update from Weblate (#5762)
* [Web] Updated lang.es-es.json

Co-authored-by: Fernando Dilland <fernandodilland@gmail.com>

* [Web] Updated lang.nb-no.json

Co-authored-by: Christer Solstrand Johannessen <csjoh@users.noreply.translate.mailcow.email>

---------

Co-authored-by: Fernando Dilland <fernandodilland@gmail.com>
Co-authored-by: Christer Solstrand Johannessen <csjoh@users.noreply.translate.mailcow.email>
2024-02-25 19:51:57 +01:00
FreddleSpl0it
010d898786 [Web] apply LDAP filter 2024-02-23 10:01:56 +01:00
FreddleSpl0it
766c270b1f [SOGo] fix custom html elements and wrong redirection 2024-02-23 09:12:17 +01:00
FreddleSpl0it
916d0fd46a [Web] catch all exceptions on ldap connect 2024-02-23 08:12:06 +01:00
Patrick Schult
9561526f33 Merge pull request #5754 from mailcow/feat/idp-ldap2
[Nightly] add LDAP as direct IdP
2024-02-20 15:33:58 +01:00
FreddleSpl0it
45811bc2dc [Web] fix mailbox datatable search 2024-02-20 15:00:06 +01:00
FreddleSpl0it
132e37bfec [SOGo] use bash script for ldap plist template 2024-02-20 12:42:37 +01:00
FreddleSpl0it
b3e26e14ef [Ofelia] add ldap sync cronjob 2024-02-20 12:01:08 +01:00
FreddleSpl0it
a3bb889def [Web] fix set_tfa for ldap users 2024-02-20 11:41:02 +01:00
FreddleSpl0it
3a1dcb3aaf [Web] fix set_tfa for ldap users 2024-02-20 11:34:01 +01:00
FreddleSpl0it
d22cafacc8 [Web] fix ldap filter if empty 2024-02-20 11:21:25 +01:00
FreddleSpl0it
78e7266368 [Web] add LDAP query filter 2024-02-20 10:46:23 +01:00
FreddleSpl0it
a06c78362a [Web] add ldap idp 2024-02-20 10:31:14 +01:00
FreddleSpl0it
d479d18507 [Web] update directorytree/ldaprecord 2024-02-20 10:30:11 +01:00
FreddleSpl0it
98cdb95bc0 [Rspamd] milter update Content-Type and Content-Transfer-Encoding header after need_rewrite_ct 2024-02-19 11:20:19 +01:00
Hailer, Christian
02a55ce9db Fix unbound healthcheck.sh to log all messages to logfile 2024-02-19 09:26:29 +01:00
renovate[bot]
6f4720e1ea chore(deps): update thollander/actions-comment-pull-request action to v2.5.0 (#5747) 2024-02-17 11:42:30 +01:00
Peter
6a807b7799 Remove one GmbH 2024-02-15 17:43:01 +01:00
Patrick Schult
8d4ef147d2 Merge pull request #5741 from mailcow/staging
2024-02
2024-02-15 11:27:09 +01:00
milkmaker
8ed6217d1c Translations update from Weblate (#5740)
* [Web] Language file updated by 'Cleanup translation files' addon

[Web] Updated lang.it-it.json

ui: fixed broken Links to docs

ui: fix wrong docs links

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
2024-02-14 20:11:51 +01:00
milkmaker
7dae4a976d Translations update from Weblate (#5732)
* ui: fix wrong docs links

* ui: fixed broken Links to docs

* [Web] Updated lang.nb-no.json

[Web] Updated lang.nb-no.json

[Web] Updated lang.nb-no.json

[Web] Added lang.nb-no.json

Co-authored-by: Christer Solstrand Johannessen <csjoh@users.noreply.translate.mailcow.email>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

[Web] Updated lang.fr-fr.json

Co-authored-by: Alix ANNERAUD <alix.anneraud@outlook.fr>
Co-authored-by: William Blondel <contact@williamblondel.fr>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.it-it.json

Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.zh-tw.json

Co-authored-by: BallBill <BallBill@users.noreply.translate.mailcow.email>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.pt-br.json

[Web] Updated lang.pt-br.json

[Web] Updated lang.pt-br.json

[Web] Updated lang.pt-br.json

Co-authored-by: Abner Santana <abnerss@outlook.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* Add Norwegian in vars.inc.php

---------

Co-authored-by: DerLinkman <niklas.meyer@servercow.de>
Co-authored-by: Christer Solstrand Johannessen <csjoh@users.noreply.translate.mailcow.email>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Alix ANNERAUD <alix.anneraud@outlook.fr>
Co-authored-by: William Blondel <contact@williamblondel.fr>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: BallBill <BallBill@users.noreply.translate.mailcow.email>
Co-authored-by: Abner Santana <abnerss@outlook.com>
2024-02-14 20:09:10 +01:00
FreddleSpl0it
3b83949ba3 [Netfilter] Update to 1.58 2024-02-14 13:58:07 +01:00
Patrick Schult
d8baadb991 Merge pull request #5679 from Habetdin/staging
[Netfilter] respect ban time limits
2024-02-14 11:37:24 +01:00
Patrick Schult
7d3f9fa407 Merge pull request #5727 from mailcow/fix/domain-wide-footer
[Rspamd] apply domain wide footer to alias domains
2024-02-14 09:43:04 +01:00
Patrick Schult
705d144a85 Merge pull request #5729 from mailcow/feat/readable-domainnames
[Web] display human readable domainnames instead of punycode
2024-02-14 09:36:20 +01:00
Patrick Schult
ff05cff36c Merge pull request #5730 from mailcow/fix/add-domain-gal
[Web] fix setting unchecked checkboxes on domain adding
2024-02-14 09:34:21 +01:00
Patrick Schult
861fa7b145 Merge pull request #5728 from mailcow/fix/debug-tz
[Web] fix blank /debug page with invalid timezone
2024-02-14 09:32:17 +01:00
FreddleSpl0it
d65a0bba44 [ClamAV] Update to 1.2.2 2024-02-13 09:16:38 +01:00
FreddleSpl0it
dac1bd88dc [Web] fix setting unchecked checkboxes 2024-02-09 15:17:02 +01:00
FreddleSpl0it
288dbfa37c [Web] display human readable domainnames instead of punycode 2024-02-09 15:13:45 +01:00
FreddleSpl0it
a0e55cb9b1 [Web] fix blank /debug page with invalid timezone 2024-02-09 15:08:21 +01:00
FreddleSpl0it
86ba019ca0 [Rspamd] apply domain wide footer to alias domains 2024-02-09 14:59:14 +01:00
q16marvin
19deda31bc Update functions.mailbox.inc.php 2024-02-09 11:23:47 +01:00
q16marvin
4f47534824 Update mailbox.js 2024-02-09 11:23:09 +01:00
DerLinkman
3cb9c2ece5 ui: fix wrong docs links
ui: fixed broken Links to docs
2024-02-09 08:11:20 +01:00
Habetdin
1787c53d98 [Netfilter] respect ban time limits 2024-02-09 01:57:09 +03:00
Niklas Meyer
8ae762a8c8 Merge pull request #5717 from mailcow/staging
2024-01e
2024-02-08 15:58:47 +01:00
DerLinkman
63426c3cd0 unbound: remove netcat check & package 2024-02-08 15:55:26 +01:00
DerLinkman
e184713c67 added action for support label in issues 2024-02-08 13:06:02 +01:00
DerLinkman
40146839ef docker-compose: bumped versions 2024-02-08 12:42:36 +01:00
DerLinkman
448f85abe8 Remove unused files 2024-02-08 12:42:36 +01:00
FreddleSpl0it
9a4b79a629 [Web] fix idp mailbox login 2024-02-08 12:42:35 +01:00
DerLinkman
058b79ed5c dovecot: corrected dockerfile inside nightly 2024-02-08 12:42:35 +01:00
FreddleSpl0it
216398355b fix functions.inc.php, update sogo and dovecot nightly image 2024-02-08 12:42:35 +01:00
Geert Hauwaerts
1cda16523d Fixed SQL query for retrieving SSO users. 2024-02-08 12:42:34 +01:00
FreddleSpl0it
2f1e1438e9 [Web] add log messages to verify-sso function 2024-02-08 12:42:34 +01:00
FreddleSpl0it
9039ab4e12 [Web] add missing file to autodiscover.php 2024-02-08 12:42:34 +01:00
DerLinkman
db47696ba7 Updated Dovecot Image to use OpenSSL 3.0 fix 2024-02-08 12:42:33 +01:00
FreddleSpl0it
eb9e3b8391 [Web] add configurable client scopes for generic-oidc 2024-02-08 12:42:33 +01:00
FreddleSpl0it
ba32f1131e [Web] dont rtrim generic-oidc urls 2024-02-08 12:42:32 +01:00
DerLinkman
27ef04baa0 Update Dovecot to reuse lz4 compression 2024-02-08 12:42:32 +01:00
DerLinkman
b3a94e79e3 Use dedicated nightly images on nightly branch + updates of images itself 2024-02-08 12:42:32 +01:00
FreddleSpl0it
3a4c0c84a3 fix keycloak mailpassword flow 2024-02-08 12:42:31 +01:00
Mirko Ceroni
73a044ec14 Update sogo-auth.php 2024-02-08 12:42:31 +01:00
Mirko Ceroni
389eb99c10 Update sogo-auth.php
initialize db before validating credentials
2024-02-08 12:42:31 +01:00
FreddleSpl0it
597d98e1d7 Fixes #5408 2024-02-08 12:42:30 +01:00
FreddleSpl0it
981307a1c6 [Web] add missing break 2024-02-08 12:42:30 +01:00
FreddleSpl0it
2d51881ae3 [Web] fix user protocol badges 2024-02-08 12:42:30 +01:00
FreddleSpl0it
788f03e993 [Dovecot] remove passwd-verify.lua generation 2024-02-08 12:42:29 +01:00
DerLinkman
81024b8c12 Clamd using Alpine Packages instead self compile 2024-02-08 12:42:29 +01:00
DerLinkman
89c5064213 Rebased Dovecot on Alpine + fixed logging 2024-02-08 12:42:29 +01:00
DerLinkman
4b18a99e55 Small fixes for CLAMD Health Check 2024-02-08 12:42:28 +01:00
DerLinkman
92d2cca7c3 Added missing Labels to Dockerfiles 2024-02-08 12:42:28 +01:00
DerLinkman
466e36ecbb Optimized Build Process for Dovecot 2024-02-08 12:42:28 +01:00
DerLinkman
7ec7bd21cb Changed Dovecot Base to Bullseye again (Self compile) 2024-02-08 12:42:27 +01:00
DerLinkman
38db7226a8 Optimized CLAMAV Builds to match exact version instead of Repo 2024-02-08 12:42:27 +01:00
DerLinkman
60f9412bb8 Switched to Alpine Edge (for IMAPSYNC Deps) 2024-02-08 12:42:26 +01:00
DerLinkman
737c0502ac Rebased Dovecot on Alpine 3.17 instead Bullseye (ARM64 Support) 2024-02-08 12:42:26 +01:00
DerLinkman
6da41b1027 Removed Test self compiled SOGo Dockerfile 2024-02-08 12:42:26 +01:00
DerLinkman
2bd46ae0fd Changed Maintainer to tinc within Dockerfiles 2024-02-08 12:42:25 +01:00
DerLinkman
c15ab10b1b Updated Clamd Building to be x86 and ARM Compatible 2024-02-08 12:42:25 +01:00
DerLinkman
ddaeebc822 [Rspamd] Update to 3.6 (Ratelimit fix) 2024-02-08 12:42:25 +01:00
FreddleSpl0it
e64293c82f [Web] minor fixes 2024-02-08 12:42:24 +01:00
FreddleSpl0it
ccc17e4a20 [SOGo] deny direct login on external users 2024-02-08 12:42:24 +01:00
FreddleSpl0it
a53ef2ed7a [SOGo] remove sogo_view and triggers 2024-02-08 12:42:24 +01:00
FreddleSpl0it
185c36cdfe [Web] catch update_sogo exceptions 2024-02-08 12:42:23 +01:00
FreddleSpl0it
9beb47c067 [Web] fix malformed_username check 2024-02-08 12:42:23 +01:00
FreddleSpl0it
3d486678ae [Web] remove keycloak sync disabled warning 2024-02-08 12:42:23 +01:00
FreddleSpl0it
04e2494af8 deny changes on identity provider if it's in use 2024-02-08 12:42:22 +01:00
FreddleSpl0it
7b47159478 rework auth - move dovecot sasl log to php 2024-02-08 12:42:22 +01:00
FreddleSpl0it
17b6ac3313 [Web] allow mailbox authsource to be switchable 2024-02-08 12:42:22 +01:00
FreddleSpl0it
43600cd127 [Web] fix identity-provider settings layout 2024-02-08 12:42:21 +01:00
FreddleSpl0it
6d3a32c1d9 [Web] trim CRON_LOG 2024-02-08 12:42:21 +01:00
FreddleSpl0it
21fa3c8458 [Web] remove unnecessary if block 2024-02-08 12:42:21 +01:00
FreddleSpl0it
6df663825a [Web] add curl timeouts to oidc requests 2024-02-08 12:42:20 +01:00
FreddleSpl0it
8ce4600562 [Web] update lang files 2024-02-08 12:42:20 +01:00
FreddleSpl0it
3179c0e712 [Dovecot] mailcowauth minor fixes 2024-02-08 12:42:19 +01:00
FreddleSpl0it
37254738e2 [Web] improve identity-provider template 2024-02-08 12:42:19 +01:00
FreddleSpl0it
a4cce147aa [Web] improve attribute sync performance & make authsource editable 2024-02-08 12:42:19 +01:00
FreddleSpl0it
b176585a9c [Web] add crontasks logs 2024-02-08 12:42:18 +01:00
FreddleSpl0it
f8647bb15e [Web] add keycloak sync crontask 2024-02-08 12:42:18 +01:00
FreddleSpl0it
85368971fd [Web] handle fatal errors on getAccessToken 2024-02-08 12:42:18 +01:00
FreddleSpl0it
e4284b8e19 [Web] fix attribute mapping list 2024-02-08 12:42:17 +01:00
FreddleSpl0it
5545d8a56c [Web] hide auth settings for external users 2024-02-08 12:42:17 +01:00
FreddleSpl0it
4dc3222f03 [Web] fix bug on mailbox login 2024-02-08 12:42:17 +01:00
FreddleSpl0it
7cf6a9d808 [Web] update lang.en-gb.json 2024-02-08 12:42:16 +01:00
FreddleSpl0it
95a15d18a7 [Web] update guzzlehttp/psr7 2024-02-08 12:42:16 +01:00
FreddleSpl0it
cee771a3fb [Web] update stevenmaguire/oauth2-keycloak and firebase/php-jwt 2024-02-08 12:42:16 +01:00
FreddleSpl0it
a805d3b2e3 [Web] add league/oauth2-client 2024-02-08 12:42:15 +01:00
FreddleSpl0it
b251c58b23 update gitignore 2024-02-08 12:42:15 +01:00
FreddleSpl0it
cc7516685f [Web] functions.auth.inc.php corrections 2024-02-08 12:42:15 +01:00
FreddleSpl0it
ad19ff5429 [Web] remove ropc flow 2024-02-08 12:42:14 +01:00
FreddleSpl0it
e784c98a5a [Web] add "add mailbox_from_template" function 2024-02-08 12:42:14 +01:00
FreddleSpl0it
28679eb916 [Web] add generic-oidc provider 2024-02-08 12:42:13 +01:00
FreddleSpl0it
c8fec24da3 [Web] add "edit mailbox_from_template" function 2024-02-08 12:42:13 +01:00
FreddleSpl0it
0c1e2ed6f2 [Web] revert configurable authsource 2024-02-08 12:42:13 +01:00
FreddleSpl0it
90476ae057 [Web] rename var for tab-config-identity-provider.twig 2024-02-08 12:42:12 +01:00
FreddleSpl0it
3b6a1d50bd [Web] add generic-oidc provider 2024-02-08 12:42:12 +01:00
FreddleSpl0it
1ab1505c88 [Web] remove sso login alertbox 2024-02-08 12:42:12 +01:00
FreddleSpl0it
593e581cf3 [Web] move iam sso functions 2024-02-08 12:42:11 +01:00
FreddleSpl0it
e202d00beb [Dovecot] group auth files 2024-02-08 12:42:11 +01:00
FreddleSpl0it
dca5f1baab [Web] move /process/login to internal endpoint 2024-02-08 12:42:11 +01:00
FreddleSpl0it
f0689e08d9 [Web] iam - add switch for direct login flow 2024-02-08 12:42:10 +01:00
FreddleSpl0it
5bbb12b53e [Dovecot] fix wrong lua syntax 2024-02-08 12:42:10 +01:00
FreddleSpl0it
c6a56e0748 [Web] add IAM delete button & fix add mbox modal 2024-02-08 12:42:10 +01:00
FreddleSpl0it
3c62a7fd9f [Web] IAM - add delete option & fix test connection 2024-02-08 12:42:09 +01:00
FreddleSpl0it
61ab17d8a1 [Web] fix iam attribute mapping ui 2024-02-08 12:42:09 +01:00
FreddleSpl0it
d4ae616460 replace ropc flow with keycloak rest api flow 2024-02-08 12:42:09 +01:00
FreddleSpl0it
b7a18255fe [Web] rename role mapping to attribute mapping 2024-02-08 12:42:08 +01:00
FreddleSpl0it
1c73a16ca0 new dovecout lua auth - use https 2024-02-08 12:42:08 +01:00
FreddleSpl0it
1aeb36d40e [Web] create ratelimit acl on iam mbox creation 2 2024-02-08 12:42:07 +01:00
FreddleSpl0it
f251c9826e [Web] create ratelimit acl on iam mbox creation 2024-02-08 12:42:07 +01:00
FreddleSpl0it
204063819c [Web] fix broken sogo-sso 2024-02-08 12:42:07 +01:00
FreddleSpl0it
13f8882616 [Web] fix app_pass ignore_access 2024-02-08 12:42:06 +01:00
FreddleSpl0it
eba1d469c8 [Web] keycloak auth functions 2024-02-08 12:42:06 +01:00
FreddleSpl0it
6e9980bf0f [Web] add manage identity provider 2024-02-08 12:42:06 +01:00
FreddleSpl0it
67c9c5b8ed [Web] remove u2f lib from prerequisites 2024-02-08 12:42:05 +01:00
FreddleSpl0it
cd3660a96d [Web] add oauth2-keycloak lib 2024-02-08 12:42:05 +01:00
FreddleSpl0it
9d8c1a01ac [Web] remove u2f lib 2024-02-08 12:42:05 +01:00
FreddleSpl0it
0a77cad2dd [Web] limit identity_provider function better 2024-02-08 12:42:04 +01:00
FreddleSpl0it
f6869da3a0 [Web] manage keycloak identity provider 2024-02-08 12:42:04 +01:00
FreddleSpl0it
6adad79e5c [Web] organize auth functions+api auth w/ dovecot 2024-02-08 12:42:04 +01:00
FreddleSpl0it
50d4d59626 [Web] update de-de + en-gb lang 2024-02-08 12:42:03 +01:00
FreddleSpl0it
56a9f1a411 [Web] organize user landing 2024-02-08 12:42:03 +01:00
FreddleSpl0it
84ff6ff2c5 [Web] fix user login history 2024-02-08 12:42:03 +01:00
FreddleSpl0it
6e35574c72 [Web] add app hide option 2024-02-08 12:42:02 +01:00
FreddleSpl0it
415c1d0574 [Web] add seperate link for logged in users 2024-02-08 12:42:02 +01:00
FreddleSpl0it
cfce7086a5 [Web] few style changes 2024-02-08 12:42:01 +01:00
FreddleSpl0it
c90d637a48 [Web] redirect to sogo after failed sogo-auth 2024-02-08 12:42:01 +01:00
Niklas Meyer
1926625297 Merge pull request #5711 from amorfo77/master
[Netfilter] set IP check more relaxed on NFTables.py
2024-02-08 12:36:03 +01:00
DerLinkman
63bb8e8cef unbound: increase check interval to 30s 2024-02-08 12:23:46 +01:00
DerLinkman
583c5b48a0 dovecot: bump to docker image 1.28.1 2024-02-07 17:29:36 +01:00
DerLinkman
d08ccbce78 dovecot: fix wrong timestamps inside logs 2024-02-07 17:28:49 +01:00
DerLinkman
5a9702771c [SOGo] Fixed SOGo crash on older kernels < 5.10.0-X 2024-02-07 17:18:20 +01:00
vicente
eb91d9905b fix typpo in chain order message 2024-02-07 15:48:49 +01:00
vicente
38cc85fa4c set strict=False 2024-02-07 15:36:04 +01:00
FreddleSpl0it
77e6ef218c [Netfilter] Update to 1.57 2024-02-05 09:54:16 +01:00
FreddleSpl0it
464b6f2e93 [Netfilter] fix redis logs 2024-02-05 09:47:19 +01:00
Niklas Meyer
20c90642f9 Merge pull request #5700 from mailcow/staging
[Netfilter] fix mailcow isolation rule for iptables
2024-02-02 17:49:49 +01:00
FreddleSpl0it
57e67ea8f7 [Netfilter] fix mailcow isolation rule for iptables 2024-02-02 17:40:44 +01:00
Niklas Meyer
c9e9628383 Merge pull request #5699 from mailcow/staging
2024-01d
2024-02-02 17:08:45 +01:00
DerLinkman
909f07939e dovecot: bump version for repl fix 2024-02-02 17:06:31 +01:00
FreddleSpl0it
a310493485 [Dovecot] fix repl_health.sh 2024-02-02 16:52:41 +01:00
Niklas Meyer
1e09df20b6 Merge pull request #5689 from mailcow/staging
2024-01c
2024-02-02 15:52:33 +01:00
Patrick Schult
087481ac12 Merge pull request #5696 from mailcow/fix/netfilter
[Netfilter] add mailcow isolation rule to MAILCOW chain
2024-02-02 14:33:01 +01:00
FreddleSpl0it
c941e802d4 [Netfilter] only perform cleanup at exit if SIGTERM was recieved 2024-02-02 12:57:21 +01:00
FreddleSpl0it
39589bd441 [Netfilter] only perform cleanup at exit if SIGTERM was recieved 2024-02-02 12:46:50 +01:00
DerLinkman
2e57325dde docker-compose.yml: Bump dovecot + netfilter version 2024-02-02 11:27:46 +01:00
FreddleSpl0it
2072301d89 [Netfilter] only perform cleanup at exit if SIGTERM was recieved 2024-02-02 11:08:44 +01:00
FreddleSpl0it
b236fd3ac6 [Netfilter] add mailcow isolation rule to MAILCOW chain
[Netfilter] add mailcow rule to docker-user chain

[Netfilter] add mailcow isolation rule to MAILCOW chain

[Netfilter] add mailcow isolation rule to MAILCOW chain

[Netfilter] set mailcow isolation rule before redis

[Netfilter] clear bans in redis after connecting

[Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft

[Netfilter] stop container after mariadb, redis, dovecot, solr

[Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft

[Netfilter] add exception for mailcow isolation rule for HA setups

[Netfilter] add exception for mailcow isolation rule for HA setups

[Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE

[Netfilter] fix wrong var name

[Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE to update and generate_config sh
2024-02-02 10:10:11 +01:00
Niklas Meyer
b968695e31 Merge pull request #5686 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-02-01 08:58:35 +01:00
Niklas Meyer
694f1d1623 Merge pull request #5688 from mailcow/fix/sogo-authenticated-users
sogo: fix ACL allow authenticated users + rebuild on Bookworm
2024-02-01 08:42:53 +01:00
DerLinkman
93e4d58606 sogo: fix ACL allow authenticated users + rebuild on Bookworm 2024-02-01 08:41:11 +01:00
milkmaker
cc77caad67 update postscreen_access.cidr 2024-02-01 00:13:56 +00:00
renovate[bot]
f74573f5d0 chore(deps): update peter-evans/create-pull-request action to v6 (#5683)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-31 16:14:42 +01:00
DerLinkman
deb6f0babc issue: added architecture as dropdown 2024-01-23 08:46:06 +01:00
Niklas Meyer
cb978136bd Merge pull request #5663 from mailcow/staging
2024-01b
2024-01-22 11:50:41 +01:00
Niklas Meyer
1159450cc4 Merge pull request #5662 from mailcow/fix/rollback-curl-bug
fix: rollback curl bug
2024-01-22 11:39:27 +01:00
DerLinkman
a0613e4b10 fix: rollback of Alpine 3.19 were possible 2024-01-22 11:26:26 +01:00
Niklas Meyer
68989f0a45 Merge pull request #5647 from Candinya/patch-1
fix: watchdog webhook body variables injector
2024-01-22 10:34:06 +01:00
DerLinkman
7da5e3697e compose: bump watchdog version 2024-01-22 10:32:01 +01:00
Nya Candy
6e7a0eb662 fix: watchdog webhook body variables injector 2024-01-22 10:32:01 +01:00
Niklas Meyer
b25ac855ca Merge pull request #5660 from luminem/openrc-support
Test for openrc configuration file instead of alpine
2024-01-22 10:27:29 +01:00
Niklas Meyer
3e02dcbb95 Merge pull request #5652 from KagurazakaNyaa/master
Allow user skip unbound healthcheck
2024-01-22 10:25:50 +01:00
DerLinkman
53be119e39 compose: bump unbound version 2024-01-22 10:22:24 +01:00
Luca Barbato
25bdc4c9ed Test for openrc configuration file instead of alpine
This way other distro using openrc can be supported.
2024-01-22 09:50:24 +01:00
KagurazakaNyaa
9d4055fc4d add parameter SKIP_UNBOUND_HEALTHCHECK to old installations 2024-01-19 00:07:51 +08:00
KagurazakaNyaa
d2edf359ac update config comment 2024-01-18 23:53:08 +08:00
KagurazakaNyaa
aa1d92dfbb add SKIP_UNBOUND_HEALTHCHECK to docker-compose.yml 2024-01-18 23:50:26 +08:00
KagurazakaNyaa
b89d71e6e4 change variable name 2024-01-18 23:48:59 +08:00
KagurazakaNyaa
ed493f9c3a Allow user skip unbound healthcheck 2024-01-18 23:28:03 +08:00
Niklas Meyer
76f8a5b7de Merge pull request #5650 from mailcow/staging
unbound: increased healthcheck timeout
2024-01-18 11:56:09 +01:00
DerLinkman
cb3bc207b9 unbound: increased healthcheck timeout 2024-01-18 11:55:01 +01:00
Niklas Meyer
b5db5dd0b4 Merge pull request #5642 from mailcow/staging
2024-01
2024-01-17 13:51:40 +01:00
FreddleSpl0it
90a7cff2c9 [Rspamd] check if footer.skip_replies is not 0 2024-01-17 12:05:51 +01:00
FreddleSpl0it
cc3adbe78c [Web] fix datatables ssp queries 2024-01-17 12:04:01 +01:00
Niklas Meyer
bd6a7210b7 Merge pull request #5523 from FELDSAM-INC/feldsam/datatables-ssp
Implemented Server Side processing for domains and mailboxes datatables
2024-01-17 10:23:05 +01:00
Niklas Meyer
905a202873 Merge pull request #5587 from mailcow/feat/arm64
mailcow Multiarch (x86 and ARM64) support
2024-01-17 10:18:06 +01:00
DerLinkman
accedf0280 Updated mailcow Components to be ARM64 compatible 2024-01-17 10:14:36 +01:00
FreddleSpl0it
99d9a2eacd [Web] fix mailbox and domain creation 2024-01-17 09:52:43 +01:00
Kristian Feldsam
ac4f131fa8 Domains and Mailboxes datatable - server side processing - filtering by tags
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2024-01-16 15:03:28 +01:00
FreddleSpl0it
7f6f7e0e9f [Web] limit logo file upload 2024-01-15 16:34:47 +01:00
Niklas Meyer
43bb26f28c Merge pull request #5639 from mailcow/feat/unbound-healthcheck-rewrite
unbound: rewrote of healthcheck
2024-01-15 15:57:18 +01:00
DerLinkman
b29dc37991 unbound: rewrote healthcheck to be more detailed
unbound: added comments to rewritten healthcheck
2024-01-15 15:17:28 +01:00
DerLinkman
cf9f02adbb ui: fix alignment secondary 2024-01-10 14:43:59 +01:00
Tomasz Orzechowski
6dc0bdbfa3 Proper number of threads regex. 2024-01-09 22:03:24 +01:00
DerLinkman
b5a1a18b04 lang: fixed totp langs 2024-01-09 12:20:30 +01:00
Niklas Meyer
b4eeb0ffae Merge pull request #5522 from mailcow/renovate/krakjoe-apcu-5.x
chore(deps): update dependency krakjoe/apcu to v5.1.23
2024-01-09 12:06:12 +01:00
Niklas Meyer
48549ead7f Merge pull request #5549 from mailcow/renovate/phpredis-phpredis-6.x
chore(deps): update dependency phpredis/phpredis to v6.0.2
2024-01-09 12:04:41 +01:00
Niklas Meyer
01b0ad0fd9 Merge pull request #5550 from mailcow/renovate/tianon-gosu-1.x
chore(deps): update dependency tianon/gosu to v1.17
2024-01-09 12:04:21 +01:00
Niklas Meyer
2b21501450 Merge pull request #5581 from mailcow/renovate/composer-composer-2.x
chore(deps): update dependency composer/composer to v2.6.6
2024-01-09 12:03:08 +01:00
Niklas Meyer
b491f6af9b Merge pull request #5615 from mailcow/fix/default-values
[Web] use template for default values in mbox and domain creation
2024-01-09 12:01:24 +01:00
Niklas Meyer
942ef7c254 Merge pull request #5592 from mailcow/feat/alpine-3.19
Update Dockerfiles to Alpine 3.19
2024-01-09 11:57:34 +01:00
DerLinkman
1ee3bb42f3 compose: updated image tags 2024-01-09 11:55:32 +01:00
DerLinkman
25007b1963 dockerapi: implemented lifespan function 2024-01-09 11:50:22 +01:00
DerLinkman
f442378377 dockerfiles: updated maintainer 2024-01-09 11:18:55 +01:00
DerLinkman
333b7ebc0c Fix Alpine 3.19 dependencies 2024-01-09 11:17:52 +01:00
Peter
5896766fc3 Update to Alpine 3.19 2024-01-09 11:17:51 +01:00
Niklas Meyer
89540aec28 Merge pull request #5612 from mailcow/feat/domain-wide-footer
[Rspamd] add option to skip domain wide footer on reply e-mails
2024-01-09 11:10:35 +01:00
DerLinkman
b960143045 translation: update de-de.json 2024-01-09 11:09:35 +01:00
DerLinkman
6ab45cf668 db: bumped version to newer timestamp 2024-01-08 14:43:25 +01:00
Niklas Meyer
fd206a7ef6 Merge pull request #5621 from mailcow/align-ehlo-keywords-to-fuctions
[Postfix] Remove pipeling from ehlo keywords as we block it in data
2024-01-08 09:52:28 +01:00
Niklas Meyer
1c7347d38d Merge pull request #5616 from FELDSAM-INC/feldsam/fix-form-dark-mode
Fixed bg color of form elements in dark mode
2024-01-08 09:51:48 +01:00
Niklas Meyer
7f58c422f2 Merge pull request #5625 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2024-01-08 09:51:27 +01:00
Niklas Meyer
0a0e2b5e93 Merge pull request #5624 from mthld/patch-2
Add new SOGoMailHideInlineAttachments option to sogo.conf
2024-01-08 09:47:50 +01:00
milkmaker
de00c424f4 update postscreen_access.cidr 2024-01-01 00:15:27 +00:00
Mathilde
a249e2028d Add new SOGoMailHideInlineAttachments option to sogo.conf
SOGoMailHideInlineAttachments = YES; will allow to hide inline (body and footer) images being shown as attachments.
2023-12-30 10:16:25 +01:00
Dmitriy Alekseev
68036eeccf Update main.cf 2023-12-29 22:06:18 +02:00
Patrick Schult
cb0b0235f0 Merge pull request #5623 from mailcow/staging
🛷 🐄 Moocember 2023 Update Revision A | Postfix CVE-2023-51764 Security Update
2023-12-29 20:35:20 +01:00
FreddleSpl0it
6ff6f7a28d [Postfix] set smtpd_forbid_bare_newline = yes 2023-12-29 20:19:26 +01:00
milkmaker
0b628fb22d Translations update from Weblate (#5622)
* [Web] Updated lang.zh-tw.json

Co-authored-by: BallBill <xxx@billtang.ddns.net>

* [Web] Updated lang.pt-br.json

Co-authored-by: Abner Santana <abnerss@outlook.com>

---------

Co-authored-by: BallBill <xxx@billtang.ddns.net>
Co-authored-by: Abner Santana <abnerss@outlook.com>
2023-12-29 19:22:19 +01:00
Dmitriy Alekseev
b4bb11320f Update main.cf 2023-12-29 16:04:52 +02:00
Dmitriy Alekseev
c61938db23 [Postfix] Remove pipeling from ehlo keywords as we block it in data restrictions 2023-12-29 15:59:16 +02:00
Patrick Schult
acf9d5480c Merge pull request #5504 from FELDSAM-INC/feldsam/do-not-remove-x-mailer
[Postfix] Do not remove X-Mailer header
2023-12-27 18:40:19 +01:00
milkmaker
a1cb7fd778 [Web] Updated lang.zh-tw.json (#5617)
Co-authored-by: BallBill <xxx@billtang.ddns.net>
2023-12-27 18:03:24 +01:00
Kristian Feldsam
c24543fea0 [Web] Fixed form fields bg color in dark mode
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-12-27 17:33:12 +01:00
Kristian Feldsam
100e8ab00d [Postfix] Do not remove X-Mailer header
some providers, like seznam.cz use X-Mailer in DKIM signatures

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-12-27 16:32:50 +01:00
FreddleSpl0it
38497b04ac [Web] use template for default values in mbox and domain creation 2023-12-27 14:57:27 +01:00
renovate[bot]
7bd27b920a chore(deps): update dependency nextcloud/server to v28.0.1 (#5614)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-24 18:24:01 +01:00
FreddleSpl0it
efab11720d add option to skip footer on reply e-mails 2023-12-22 10:39:07 +01:00
Patrick Schult
121f0120f0 Merge pull request #5604 from mailcow/staging
🛷 🐄 Moocember 2023 Update | Netfilter NFTables Support and Banlist Endpoint
2023-12-19 10:59:37 +01:00
Niklas Meyer
515b85bb2f Merge pull request #5603 from mailcow/renovate/alpine-3.x
chore(deps): update alpine docker tag to v3.19
2023-12-19 10:06:21 +01:00
renovate[bot]
f27e41d19c chore(deps): update alpine docker tag to v3.19
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-12-19 08:48:40 +00:00
Niklas Meyer
603d451fc9 Merge pull request #5602 from mailcow/feat/bug-reporting-changes
Guideline Improvement + Issue Template adjusting
2023-12-19 09:48:21 +01:00
DerLinkman
89adaabb64 contributing.md: Updated guidelines 2023-12-19 09:47:12 +01:00
DerLinkman
987ca68ca6 issue_templates: corrected links + added premium support link 2023-12-18 16:02:59 +01:00
FreddleSpl0it
71defbf2f9 escapeHtml in qhandler.js 2023-12-18 14:02:05 +01:00
FreddleSpl0it
5c35b42844 Update Netfilter and Watchdog Image 2023-12-18 11:53:30 +01:00
milkmaker
904b37c4be [Web] Updated lang.pt-br.json (#5598)
Co-authored-by: Abner Santana <abnerss@outlook.com>
2023-12-16 19:23:27 +01:00
milkmaker
4e252f8243 [Web] Updated lang.pt-br.json (#5591)
Co-authored-by: Abner Santana <abnerss@outlook.com>
2023-12-13 17:50:13 +01:00
Niklas Meyer
dc3e52a900 Merge pull request #5589 from mailcow/renovate/nextcloud-server-28.x
Update dependency nextcloud/server to v28
2023-12-13 10:56:05 +01:00
milkmaker
06ad5f6652 Translations update from Weblate (#5590)
* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

---------

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
2023-12-12 17:49:29 +01:00
renovate[bot]
c3b5474cbf Update dependency nextcloud/server to v28
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-12-12 13:30:18 +00:00
Patrick Schult
69e3b830ed Merge pull request #5453 from smarsching/watchdog-no-notify-on-startup
Allow suppressing watchdog start notification
2023-12-12 11:16:37 +01:00
Patrick Schult
96a5891ce7 Merge branch 'staging' into watchdog-no-notify-on-startup 2023-12-12 11:14:29 +01:00
FreddleSpl0it
66b9245b28 fix WATCHDOG_NOTIFY_WEBHOOK env vars 2023-12-12 11:10:10 +01:00
DerLinkman
f38ec68695 [SOGo] Update to 5.9.1 2023-12-12 11:00:16 +01:00
Patrick Schult
996772a27d Merge pull request #4968 from felixoi/staging
Watchdog: Allow sending notifications via webhooks
2023-12-11 16:29:52 +01:00
Patrick Schult
7f4e9c1ad4 Merge branch 'staging' into staging 2023-12-11 16:28:05 +01:00
FreddleSpl0it
218ba69501 [Watchdog] add curl verbose & use | as sed delimiter 2023-12-11 15:44:11 +01:00
Patrick Schult
c2e5dfd933 Merge pull request #5313 from mailcow/feat/f2b-banlist
[Web] add f2b_banlist endpoint
2023-12-11 12:36:06 +01:00
FreddleSpl0it
3e40bbc603 Merge remote-tracking branch 'origin/staging' into feat/f2b-banlist 2023-12-11 12:27:14 +01:00
Patrick Schult
3498d4b9c5 Merge pull request #5585 from mailcow/feat/nftables
[Netfilter] add nftables support
2023-12-11 11:54:01 +01:00
FreddleSpl0it
f4b838cad8 [Netfilter] update image & delete old server.py 2023-12-11 11:51:28 +01:00
FreddleSpl0it
86fa8634ee [Netfilter] do not ignore RETRY_WINDOW 2023-12-11 11:38:48 +01:00
milkmaker
8882006700 Translations update from Weblate (#5583)
* [Web] Updated lang.cs-cz.json

Co-authored-by: Kristian Feldsam <feldsam@gmail.com>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.sk-sk.json

Co-authored-by: Kristian Feldsam <feldsam@gmail.com>

* [Web] Updated lang.pt-br.json

[Web] Updated lang.pt-br.json

Co-authored-by: Abner Santana <abnerss@outlook.com>
Co-authored-by: xmacaba <lixo@macaba.com.br>

---------

Co-authored-by: Kristian Feldsam <feldsam@gmail.com>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Abner Santana <abnerss@outlook.com>
Co-authored-by: xmacaba <lixo@macaba.com.br>
2023-12-10 18:07:28 +01:00
renovate[bot]
40fdf99a55 Update dependency composer/composer to v2.6.6
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-12-08 20:07:11 +00:00
renovate[bot]
0257736c64 Update actions/stale action to v9 (#5579)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-07 15:57:53 +01:00
Niklas Meyer
2024cda560 Merge pull request #5578 from mailcow/staging
2023-11a
2023-12-07 12:52:32 +01:00
DerLinkman
03aaf4ad76 Update Rspamd Image to 1.94 2023-12-07 12:50:10 +01:00
DerLinkman
550b88861f [UI] Fixed showing of "disabled" placeholder for ratelimits in domains 2023-12-07 12:10:04 +01:00
Niklas Meyer
02ae5fa007 Merge pull request #5577 from mailcow/fix/rspamd-ratelimiting
[Rspamd] Fixed Ratelimit forced by global ratelimits
2023-12-07 12:07:58 +01:00
DerLinkman
d81f105ed7 [Rspamd] Added customizable global ratelimit file (disabled by default) 2023-12-07 12:04:45 +01:00
DerLinkman
d3ed225675 [Rspamd] Removed global ratelimit override 2023-12-07 12:04:06 +01:00
Kristian Feldsam
efcca61f5a Mailboxes datatable - server side processing ordering
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-12-04 14:52:17 +01:00
Kristian Feldsam
4dad0002cd Domains datatable - server side processing ordering
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-12-04 14:15:57 +01:00
Niklas Meyer
9ffc83f0f6 Merge pull request #5570 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2023-12-04 10:50:23 +01:00
milkmaker
981c7d5974 [Web] Updated lang.pt-br.json (#5573)
Co-authored-by: Abner Santana <abnerss@outlook.com>
2023-12-02 15:22:45 +01:00
milkmaker
5da089ccd7 update postscreen_access.cidr 2023-12-01 00:15:24 +00:00
milkmaker
91e00f7d97 Translations update from Weblate (#5569)
* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

---------

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
2023-11-30 21:14:42 +01:00
milkmaker
3a675fb541 [Web] Updated lang.fi-fi.json (#5567)
Co-authored-by: Mika Ruohomäki <mika.ruohomaki@ix1.fi>
2023-11-28 21:00:59 +01:00
Niklas Meyer
9a5d8d2d22 Merge pull request #5562 from startnow65/master
Detect docker compose version of form v2.x
2023-11-28 08:30:35 +01:00
DerLinkman
de812221ef Implemented improved check in update.sh as well. 2023-11-28 08:29:54 +01:00
FreddleSpl0it
340980bdd0 [Netfilter] set image back to mailcow/netfilter:1.52 2023-11-27 17:32:41 +01:00
Patrick Schult
f68a28fa2b Merge pull request #5555 from mailcow/feat/custom-footer-vars
[Web][Rspamd] domain wide footer improvements and custom mailbox attributes
2023-11-27 17:06:06 +01:00
FreddleSpl0it
7b7798e8c4 [Web] check if mbox exists before excluding it from domain wide footer 2023-11-27 17:04:29 +01:00
FreddleSpl0it
b3ac94115e [Rspamd] fix excluding alias from domain wide footer 2023-11-27 16:20:44 +01:00
DerLinkman
b1a172cad9 Use full mastodon name instead 2023-11-27 14:35:09 +01:00
DerLinkman
f2e21c68d0 Add Mastodon Links 2023-11-27 14:34:56 +01:00
DerLinkman
8b784c0eb1 Use full mastodon name instead 2023-11-27 14:34:15 +01:00
DerLinkman
bc59f32b96 Add Mastodon Links 2023-11-27 14:32:51 +01:00
Josiah Adenegan
a4fa8a4fae Detect docker compose version of form v2.x 2023-11-25 20:36:40 +00:00
Niklas Meyer
f730192c98 Merge pull request #5559 from mailcow/renovate/nextcloud-server-27.x
Update dependency nextcloud/server to v27.1.4
2023-11-24 11:16:00 +01:00
Patrick Schult
f994501296 Merge pull request #5482 from mailcow/feat/get-spam-score
[Web] add /api/v1/get/spam-score endpoint
2023-11-24 09:39:43 +01:00
renovate[bot]
9c3e73606c Update dependency nextcloud/server to v27.1.4
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-23 21:31:24 +00:00
milkmaker
5619e16b70 [Web] Updated lang.cs-cz.json (#5557)
Co-authored-by: Peter <magic@kthx.at>
2023-11-23 19:12:11 +01:00
FreddleSpl0it
d2e3867893 [Web][Rspamd] implement custom mailbox attributes and improve domain wide footer 2023-11-23 16:12:43 +01:00
Niklas Meyer
979f5475c3 Merge pull request #5552 from mailcow/staging
[Update.sh] Fix repo change when running in forced mode
2023-11-21 15:42:25 +01:00
DerLinkman
5a10f2dd7c Fix repo change when running in forced mode 2023-11-21 15:37:53 +01:00
Niklas Meyer
a80b5b7dd0 Merge pull request #5551 from mailcow/staging
2023-11
2023-11-21 10:39:05 +01:00
FreddleSpl0it
392967d664 [Rspamd] domain wide footer check for empty strings 2023-11-21 10:19:00 +01:00
renovate[bot]
d4dd1e37ce Update dependency tianon/gosu to v1.17
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-21 09:03:09 +00:00
renovate[bot]
a8dfa95126 Update dependency phpredis/phpredis to v6.0.2
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-21 09:03:02 +00:00
Niklas Meyer
3b3c2b7141 Merge pull request #5546 from mailcow/fix/domain-wide-footer
Fix: Domain Wide Disclaimer breaks attachments visualization on Gmail and Outlook #5529
2023-11-21 10:01:38 +01:00
Niklas Meyer
f55c3c0887 Merge pull request #5548 from mailcow/fix-5547
[Web] escape quarantine html
2023-11-21 10:01:04 +01:00
FreddleSpl0it
f423ad77f3 [Web] escape quarantine html 2023-11-21 08:49:18 +01:00
FreddleSpl0it
8ba1e1ba9e [Rspamd] workaround - remove "--\x0D\x0A" prefix from rewritten cts 2023-11-20 12:38:37 +01:00
Niklas Meyer
55576084fc Merge pull request #5544 from mailcow/feat/update-renovate 2023-11-18 12:33:12 +01:00
Peter
03311b06c9 Ignore everything in vendor subdirs 2023-11-18 11:40:57 +01:00
milkmaker
b5c3d01834 Translations update from Weblate (#5538)
* [Web] Updated lang.cs-cz.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Quiwy <github@quiwy.ninja>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Quiwy <github@quiwy.ninja>
2023-11-16 17:07:33 +01:00
Niklas Meyer
f398ecbe39 Merge pull request #5487 from artemislena/master
Add a helper script for generating CAA records
2023-11-16 11:42:11 +01:00
Niklas Meyer
8f1ae0f099 Merge pull request #5530 from Quiwy/staging
fix: support utf-8 in password synchronization
2023-11-16 11:21:27 +01:00
Niklas Meyer
c8bee57732 Merge pull request #5521 from raph-topo/fix/impasync-options
Add `--dry` IMAPsync Parameter as Button to select for SyncJobs
2023-11-16 11:19:47 +01:00
DerLinkman
85641794c3 Added f1f2 + sorted whitelist for imapsync 2023-11-16 11:18:50 +01:00
Niklas Meyer
849decaa59 Merge pull request #5532 from mailcow/renovate/actions-cache-3.x
Update actions/cache action to v3
2023-11-16 10:46:28 +01:00
Niklas Meyer
6e88550f92 Merge pull request #5533 from mailcow/renovate/actions-checkout-4.x
Update actions/checkout action to v4
2023-11-16 10:46:03 +01:00
renovate[bot]
7c52483887 Update actions/checkout action to v4
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-16 09:29:22 +00:00
renovate[bot]
0aa520c030 Update actions/cache action to v3
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-16 09:29:15 +00:00
Niklas Meyer
548999f163 Merge pull request #5498 from mailcow:feat/fix-5497
Update nextcloud.conf when updating nextcloud
2023-11-16 10:28:54 +01:00
DerLinkman
63df547306 Tweaked German Translation 2023-11-15 16:45:27 +01:00
DerLinkman
547d2ca308 Add Dry Mode Option for ImapSyncs (Button) 2023-11-15 16:18:18 +01:00
Quiwy
46b995f9e3 fix: support utf-8 in password synchronization 2023-11-14 10:11:25 +01:00
renovate[bot]
4f109c1a94 Update dependency krakjoe/apcu to v5.1.23
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-11-12 17:28:57 +00:00
Niklas Meyer
1fdf704cb4 Merge pull request #5524 from mailcow/feat/fix-renovate 2023-11-12 18:28:42 +01:00
Peter
5ec9c4c750 Fix renovate regex 2023-11-12 18:00:20 +01:00
Kristian Feldsam
28cec99699 Mailboxes datatable - server side processing
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-11-12 10:35:26 +01:00
Kristian Feldsam
3e194c7906 Domains datatable - server side processing
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-11-12 10:35:22 +01:00
Raphael
afed94cc0e Allow --dry IMAPsync 2023-11-09 15:24:16 +01:00
Niklas Meyer
6f48c5ace0 Merge pull request #5513 from mailcow/feat/new-sieve-template
[UI] Added a new Sieve Rule as Template
2023-11-02 17:17:19 +01:00
DerLinkman
9a7e1c2b5a Added new Sieve Template. Thanks to @EricThi 2023-11-02 17:15:10 +01:00
Niklas Meyer
2ef7539d55 Merge pull request #5509 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2023-11-02 17:08:04 +01:00
Burak Buylu
4e52542e33 Update lang.tr-tr.json (#5510)
Every day I will translate :)
2023-11-01 09:26:05 +01:00
milkmaker
a1895ad924 update postscreen_access.cidr 2023-11-01 00:14:31 +00:00
Niklas Meyer
d5a2c96887 Merge pull request #5459 from SecT0uch/patch-1 2023-10-30 21:55:58 +01:00
Niklas Meyer
3f30fe3113 Merge pull request #5508 from BandhiyaHardik/staging 2023-10-30 21:54:29 +01:00
HardikBandhiya
d89f24a1a3 Merge branch 'mailcow:staging' into staging 2023-10-31 02:18:14 +05:30
HardikBandhiya
413354ff29 Update README.md
changed the name of Twitter to 𝕏
2023-10-31 02:07:46 +05:30
FreddleSpl0it
a28ba5bebb [Web] fix broken github links in changelog 2023-10-30 16:07:10 +01:00
milkmaker
b93375b671 [Web] Updated lang.hu-hu.json (#5505)
Co-authored-by: Bence Kócsi <ttcrafttt@gmail.com>
2023-10-30 12:05:10 +01:00
FreddleSpl0it
f39005b72d [Netfilter] add nftables support 2023-10-30 11:54:14 +01:00
Kristian Feldsam
b568a33581 [web] sk and cz translations (#5502)
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-10-30 10:09:22 +01:00
Niklas Meyer
b05ef8edac Merge pull request #5500 from mailcow/renovate/nextcloud-server-27.x 2023-10-28 20:37:13 +02:00
renovate[bot]
015f9b663f Update dependency nextcloud/server to v27.1.3
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-10-28 14:40:08 +00:00
Niklas Meyer
b6167257c9 Merge pull request #5455 from mailcow/feat/rspamd-3.7.1 2023-10-28 16:39:53 +02:00
milkmaker
687fe044b2 [Web] Updated lang.si-si.json (#5499)
Co-authored-by: gomiunik <boris@gomiunik.net>
2023-10-28 15:10:30 +02:00
Peter
cfa47eb873 Update nextcloud.conf 2023-10-27 22:59:46 +02:00
Peter
7079000ee0 Update nextcloud.conf when updating nextcloud 2023-10-27 22:56:51 +02:00
milkmaker
f60c4f39ee [Web] Updated lang.si-si.json (#5494)
Co-authored-by: gomiunik <boris@gomiunik.net>
2023-10-25 19:46:19 +02:00
yvan-algoo
473713219f Update lang.fr-fr.json (#5492)
- Fix typos
- Replace "..." by "…"
2023-10-25 18:38:01 +02:00
artemislena
03ed81dc3f T.: Added a script for generating CAA records 2023-10-23 19:44:28 +02:00
renovate[bot]
53543ccf26 Update thollander/actions-comment-pull-request action to v2.4.3 (#5484)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 12:10:34 +02:00
FreddleSpl0it
3b183933e3 [Web] add api get spam-score endpoint 2023-10-20 10:48:04 +02:00
DerLinkman
6c6fde8e2e Improved docker image pruning 2023-10-19 12:31:13 +02:00
DerLinkman
61e23b6b81 Added Dev Mode option for git diff creation 2023-10-19 12:14:27 +02:00
DerLinkman
6c649debc9 Update DockerAPI to implement CPU load fix 2023-10-18 10:31:49 +02:00
milkmaker
87b0683f77 Translations update from Weblate (#5472)
* [Web] Updated lang.cs-cz.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.sk-sk.json

Co-authored-by: Peter <magic@kthx.at>

---------

Co-authored-by: Peter <magic@kthx.at>
2023-10-14 22:58:28 +02:00
milkmaker
59c1e7a18a [Web] Updated lang.pt-br.json (#5471)
Co-authored-by: Peter <magic@kthx.at>
2023-10-14 14:26:06 +02:00
Pedro Lucca S.C
4f9dad5dd3 pt-br translation (#5470) 2023-10-14 14:16:07 +02:00
DerLinkman
adc6a0054c Updated compose version info color from red to yellow 2023-10-13 15:37:37 +02:00
Sebastian Marsching
5425cca47e Allow suppressing watchdog start notification.
The default behavior is still the old one (send a notifcation when the
watchdog is started), but this notification can now be suppressed by
setting WATCHDOG_NOTIFY_START=n.
2023-10-12 18:34:55 +02:00
milkmaker
8a70cdb48b Translations update from Weblate (#5460)
* [Web] Added lang.pt-br.json

Co-authored-by: Peter <magic@kthx.at>

* Add pt-br in vars.inc.php

---------

Co-authored-by: Peter <magic@kthx.at>
2023-10-12 18:27:04 +02:00
Jordan ERNST
bb4bc11383 Fix for git < v1.7.5
This change should be compatible with all git version.
(get-url available from v1.7.5)
2023-10-12 15:55:53 +02:00
Niklas Meyer
a366494c34 Merge pull request #5458 from mailcow/staging
2023-10a
2023-10-12 15:45:40 +02:00
DerLinkman
99de302ec9 Reverted restart action removal in docker-compose.yml for older 2.X compatibility 2023-10-12 15:38:58 +02:00
DerLinkman
907912046f Fix Clamd Version image in compose 2023-10-12 15:18:19 +02:00
DerLinkman
2c0d379dc5 [Rspamd] Update to 3.7.1 2023-10-12 13:05:27 +02:00
Niklas Meyer
5b8efeb2ba Merge pull request #5454 from mailcow/staging
2023-10
2023-10-12 12:55:01 +02:00
Niklas Meyer
f1c93fa337 Merge pull request #5253 from mailcow/renovate/composer-composer-2.x
Update dependency composer/composer to v2.6.5
2023-10-12 11:39:22 +02:00
Niklas Meyer
a94a29a6ac Merge pull request #5442 from mailcow/renovate/php-pecl-mail-mailparse-3.x
Update dependency php/pecl-mail-mailparse to v3.1.6
2023-10-12 11:38:47 +02:00
Niklas Meyer
7e3d736ee1 Merge pull request #5413 from mailcow/renovate/phpredis-phpredis-6.x
Update dependency phpredis/phpredis to v6
2023-10-12 11:38:34 +02:00
Niklas Meyer
437534556e Merge pull request #5372 from Habetdin:staging
[Postfix] fix extra.cf updating
2023-10-12 11:25:32 +02:00
Niklas Meyer
ce4b9c98dc Merge pull request #5402 from cero1988/staging
enable search in bodies from EAS
2023-10-12 11:13:04 +02:00
DerLinkman
c134078d60 Add comment about experimental thingy 2023-10-12 11:11:50 +02:00
Niklas Meyer
a8bc6aff2e Merge pull request #5451 from mailcow/feat/unbound-healthcheck
[Unbound] Added Healthcheck for Unbound (Dockerfile and Compose)
2023-10-12 10:52:23 +02:00
DerLinkman
0b627017e0 [Compose] Added Healthcheck startup logics 2023-10-11 15:49:00 +02:00
DerLinkman
eb3be80286 [Unbound] Added Healthcheck (nslookup) 2023-10-11 15:48:25 +02:00
DerLinkman
1fda71e4fa Update Images which contains Curl to fix CVEs 2023-10-11 12:16:05 +02:00
DerLinkman
a02bd4beff [Dovecot] Update to 2.3.21 2023-10-11 12:14:47 +02:00
DerLinkman
d7f3ee16aa Update Dovecot Wiki Link for new mailcows 2023-10-10 16:13:28 +02:00
Peter
87e3c91c26 Update Dockerfile 2023-10-08 11:41:39 +02:00
FreddleSpl0it
33a38e6fde [Web] Avoid setting default ACL on create when nothing is selected 2023-10-06 11:31:28 +02:00
renovate[bot]
3d8f45db43 Update dependency composer/composer to v2.6.5
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-10-06 09:17:46 +00:00
Niklas Meyer
40df25dcf0 Merge pull request #5443 from mailcow/fix-generateconfigsh
Change column name in generate_config.sh
2023-10-06 09:41:07 +02:00
Peter
5de151a966 change column name 2023-10-06 00:12:49 +02:00
renovate[bot]
115d0681a7 Update dependency php/pecl-mail-mailparse to v3.1.6
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-10-05 15:20:24 +00:00
Niklas Meyer
1c403a6d60 Merge pull request #5401 from AlexHuebi/master
Improved the FQDN check and Ask before changing Git Repository URL in "update.sh"
2023-10-05 16:27:16 +02:00
DerLinkman
e67ba60863 Added Colors, cause there fancy :) + Added in generate_config.sh 2023-10-05 16:21:57 +02:00
renovate[bot]
0c0ec7be58 Update dependency phpredis/phpredis to v6
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-10-05 14:08:31 +00:00
Niklas Meyer
a72b3689b0 Merge pull request #5436 from mailcow/fix-renovate
Fix renovate to allow version extracts for Dockerfiles
2023-10-05 16:08:06 +02:00
Niklas Meyer
c4c76e0945 Merge pull request #5438 from accolon/master
Update ClamAV to latest LTS version 1.0.3
2023-10-05 16:04:46 +02:00
Niklas Meyer
1a793e0b7e Merge pull request #5441 from mailcow/renovate/nextcloud-server-27.x
Update dependency nextcloud/server to v27.1.2
2023-10-05 16:03:58 +02:00
Niklas Meyer
d0562ddbd9 Merge pull request #5398 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2023-10-05 16:03:45 +02:00
DerLinkman
3851a48ea0 Bumped clamd version in compose.yml 2023-10-05 15:49:19 +02:00
DerLinkman
40dcf86846 Merge branch 'master' into staging 2023-10-05 15:46:22 +02:00
renovate[bot]
257e104d2b Update dependency nextcloud/server to v27.1.2
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-10-05 13:21:58 +00:00
Florian Hillebrand
3f2a9b6973 Update ClamAV to latest LTS version 1.0.3 2023-10-03 20:54:45 +02:00
Peter
ed365c35e7 Fix renovate.json to allow version extracts 2023-10-02 20:22:08 +02:00
milkmaker
24ff70759a update postscreen_access.cidr 2023-10-01 00:15:06 +00:00
milkmaker
c55c38f77b Translations update from Weblate (#5434)
* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
2023-09-30 14:18:55 +02:00
Niklas Meyer
934bc15fae Merge pull request #5433 from mailcow/feat/sogo-5.9.0
[SOGo] Update to 5.9.0
2023-09-29 12:05:41 +02:00
Niklas Meyer
c2c994bfbb Merge pull request #5432 from mailcow/fix-docs-domain
mailcow.github.io -> docs.mailcow.email
2023-09-29 11:56:05 +02:00
Peter
b1c2ffba6e mailcow.github.io -> docs.mailcow.email 2023-09-27 18:34:53 +02:00
milkmaker
b4a56052c5 [Web] Updated lang.nl-nl.json (#5431)
Co-authored-by: Nick Bouwhuis <github@nickbouwhuis.nl>
2023-09-27 17:56:21 +02:00
DerLinkman
69d15df221 [SOGo] Update to 5.9.0 2023-09-27 16:10:10 +02:00
renovate[bot]
e5752755d1 Update dependency nextcloud/server to v27.1.1 (#5426)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-26 20:29:47 +02:00
Niklas Meyer
d98cfe0fc7 Merge pull request #5422 from mailcow/renovate/nextcloud-server-27.x
Update dependency nextcloud/server to v27.1.0
2023-09-18 11:28:27 +02:00
renovate[bot]
1a1955c1c2 Update dependency nextcloud/server to v27.1.0
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-09-16 09:09:40 +00:00
Patrick Schult
0303dbc1d2 Merge pull request #5227 from mailcow/feat/domain-wide-footer
[Rspamd] add domain wide footer
2023-09-13 15:11:33 +02:00
FreddleSpl0it
acee742822 [Web] move domain-wide-footer vars info to lang files 2023-09-13 15:08:07 +02:00
FreddleSpl0it
8d792fbd62 [Rspamd] domain-wide-footer update description 2023-09-13 13:03:46 +02:00
FreddleSpl0it
d132a51a4d Merge remote-tracking branch 'origin/staging' into feat/domain-wide-footer 2023-09-13 12:44:41 +02:00
FreddleSpl0it
2111115a73 [Rspamd] domain-wide-footer add more template vars 2023-09-13 12:42:12 +02:00
renovate[bot]
160c9caee3 Update docker/setup-buildx-action action to v3 (#5417)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:16 +02:00
renovate[bot]
33de788453 Update docker/setup-qemu-action action to v3 (#5418)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:09 +02:00
renovate[bot]
f86f5657d9 Update docker/login-action action to v3 (#5416)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:41:00 +02:00
renovate[bot]
e02a92a0d0 Update docker/build-push-action action to v5 (#5415)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 17:40:44 +02:00
FreddleSpl0it
5ae9605e77 [Rspamd] domain-wide-footer add jinja templating 2023-09-12 12:19:46 +02:00
AlexHuebi
88fbec1e53 fixed remote url override 2023-09-11 21:43:52 +02:00
AlexHuebi
d098e7b9e6 fixed remote url override 2023-09-11 21:42:43 +02:00
AlexHuebi
a8930e8060 fixed remote url override 2023-09-11 21:39:07 +02:00
AlexHuebi
e26501261e "temp" change - removed "git remote set-url" 2023-09-11 20:08:42 +02:00
Christian Schmitt
89bc11ce0f Fix typo in German translation: (#5414)
"gibt Aufschluss darüber"
2023-09-11 15:44:24 +02:00
Patrick Schult
4b096962a9 Merge pull request #5328 from mailcow/feat/backup_action
Update rebuild_backup_image.yml
2023-09-08 16:01:34 +02:00
Patrick Schult
c64fdf9aa3 Merge pull request #4342 from FELDSAM-INC/feldsam/enhancements
[Web] apple config app passwords enhancements + translations
2023-09-08 15:41:25 +02:00
Patrick Schult
9caaaa6498 Merge pull request #5403 from FELDSAM-INC/feldsam/css-fixes
[Web] BS5 styling fixes and enhancements
2023-09-08 15:29:47 +02:00
Patrick Schult
105a7a4c74 Merge pull request #5405 from FELDSAM-INC/feldsam/filter-by-domain
[Web] Filter tables by Domain where possible
2023-09-08 15:01:15 +02:00
Patrick Schult
09782e5b47 Merge pull request #5406 from FELDSAM-INC/feldsam/dark-mode-logo
[Web] dark mode logo support
2023-09-08 14:57:43 +02:00
Mirko Ceroni
8d75b570c8 Update data/conf/sogo/sogo.conf
Co-authored-by: Peter <magic@kthx.at>
2023-09-04 21:43:24 +02:00
milkmaker
21121f9827 Translations update from Weblate (#5410)
* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.en-gb.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Peter <magic@kthx.at>

---------

Co-authored-by: Peter <magic@kthx.at>
2023-09-04 19:56:42 +02:00
renovate[bot]
8e87e76dcf Update actions/checkout action to v4 (#5409)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-04 18:49:38 +02:00
Patrick Schult
2629f3d865 Merge pull request #5404 from FELDSAM-INC/feldsam/datatables-sk-cz-translations
[Web] translated datatables to CZ and SK
2023-09-04 07:59:01 +02:00
Kristian Feldsam
8e5cd90707 [Web] Filter tables by Domain where possible
This feature was standard in Mailcow in pre-BS5 releases

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:55:51 +02:00
Kristian Feldsam
9ffa810054 [Web] Edit Domain/Mailbox - added collapsible tabs for mobile devices
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:41:25 +02:00
Kristian Feldsam
db9562e843 [Web] mailboxes - remove tab dropdown, if not admin
there are no domain and mailbox templates available, so no need to have dropdown in tabs

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 19:05:24 +02:00
Kristian Feldsam
3540075b61 [Web] dark mode logo support
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:49:12 +02:00
Kristian Feldsam
d0ba061f7a [Web] mobile devices - scroll window to opened tab
This feature was in versions before BS5

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:36:39 +02:00
Kristian Feldsam
871ae5d7d2 [Web] mobile devices styling fixes and enhancements
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 18:36:32 +02:00
Kristian Feldsam
633ebe5e8d [Web] fixed add domain save action button group styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
1b7cc830ca [Web] standarize select box dropdown buttons
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
d48193fd0e [Web] edit object - added space after heaading
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
bb69f39976 [Web] domain and alias domain edit - translated dkim “domain”
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
f059db54d0 [Web] edit mailbox template - fixed settigns buttons styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
e4e8abb1b9 [Web] Ratelimit settings as input group
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 14:17:54 +02:00
Kristian Feldsam
1a207f4d88 [Web] translated datatables to CZ and SK
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-03 12:38:50 +02:00
Mirko Ceroni
25d6e0bbd0 enable search in bodies from EAS
enable search in bodies from EAS
2023-09-02 11:34:29 +02:00
Kristian Feldsam
8e5323023a [Web] checkbox styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:45 +02:00
Kristian Feldsam
6d9805109a [Web] styling enhancements
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:39 +02:00
Kristian Feldsam
1822d56efb [Web] fixed new mailbox settings buttons styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>

Fixed input with btn in input group styling

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:33 +02:00
Kristian Feldsam
1e3766e2f1 [Web] revisited dark mode theme, enhanced colors
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-09-02 10:30:25 +02:00
AlexHuebi
718dcb69be improved "FQDN" check 2023-09-02 02:53:55 +02:00
Patrick Schult
372b1c7bbc Merge pull request #5383 from Dexus-Forks/Dexus-patch-1
Update config for nginx >=1.25.1 (http2, server_names_hash_max_size, server_names_hash_bucket_size)
2023-08-29 12:05:44 +02:00
Patrick Schult
9ba5c13702 Merge pull request #5376 from mstilkerich/fix_dockerapi_cpuload
Fix CPU load of dockerapi container
2023-08-28 16:23:27 +02:00
milkmaker
30e241babe Translations update from Weblate (#5390)
* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.es-es.json

Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.hu-hu.json

[Web] Updated lang.hu-hu.json

[Web] Updated lang.hu-hu.json

Co-authored-by: 0xAndrewBlack <0xandrewblack@gmail.com>
Co-authored-by: Kántor Attila <attilalaci300@gmail.com>
Co-authored-by: Mihály Szilágyi <szimih90@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ro-ro.json

Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.gr-gr.json

[Web] Added lang.gr-gr.json

Co-authored-by: Nik Beaver <nik@beavers.forsale>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Adrien Kara <mailcow-translate@iglou.eu>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.en-gb.json

Co-authored-by: Philipp E <ph.ecker@philipp-dev.info>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ca-es.json

Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.it-it.json

Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.uk-ua.json

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.si-si.json

[Web] Updated lang.si-si.json

[Web] Updated lang.si-si.json

[Web] Added lang.si-si.json

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: gomiunik <boris@gomiunik.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* Add Greek + Slovenian

---------

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Marco Truffat <truffatmarco@gmail.com>
Co-authored-by: 0xAndrewBlack <0xandrewblack@gmail.com>
Co-authored-by: Kántor Attila <attilalaci300@gmail.com>
Co-authored-by: Mihály Szilágyi <szimih90@gmail.com>
Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: Nik Beaver <nik@beavers.forsale>
Co-authored-by: Adrien Kara <mailcow-translate@iglou.eu>
Co-authored-by: Philipp E <ph.ecker@philipp-dev.info>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: gomiunik <boris@gomiunik.net>
2023-08-19 21:47:23 +02:00
Niklas Meyer
956b170674 Merge pull request #5385 from mailcow/renovate/nextcloud-server-27.x 2023-08-14 18:11:36 +02:00
renovate[bot]
2c52753adb Update dependency nextcloud/server to v27.0.2
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-08-14 15:21:07 +00:00
Josef Fröhle
095d59c01b Update listen_ssl.template deprecated http2 on listener 2023-08-12 16:59:15 +02:00
Josef Fröhle
1a2f145b28 Update site.conf: server_names_hash_bucket_size 128 2023-08-12 16:58:26 +02:00
Michael Stilkerich
930473a980 Set asyncio timeout to 0 for yielding 2023-08-12 07:20:56 +02:00
DerLinkman
1db8990271 Fixed Branch checkout in generate_config.sh 2023-08-10 13:51:40 +02:00
FreddleSpl0it
025fd03310 [Rspamd] remove X-Moo-Tag header if unnecessary 2023-08-07 14:26:30 +02:00
renovate[bot]
e468c59dfc Update thollander/actions-comment-pull-request action to v2.4.2 (#5379)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-07 06:46:07 +02:00
renovate[bot]
340ef866d2 Update thollander/actions-comment-pull-request action to v2.4.1 (#5377)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-06 16:39:26 +02:00
Michael Stilkerich
533bd36572 Fix CPU load of dockerapi container
Previously the handle_pubsub_messages() loop was executing every 10ms
when there was no message available. Now reading from the redis network
socket will block (the coroutine) for up to 30s before it returns when
no message is available.

Using channel.listen() would be even better, but it lacks the
ignore_subscribe_messages option and I could not figure out how to
filter the returned messages.
2023-08-05 20:58:34 +02:00
Habetdin
5bf29e6ac1 [Postfix] fix extra.cf updating 2023-08-05 00:25:19 +03:00
Patrick Schult
d6c3c58f42 Merge pull request #5360 from mailcow/staging
2023-08 - DQS Hotfixes
2023-08-03 11:36:53 +02:00
FreddleSpl0it
b050cb9864 [Postfix] remove dnsbl_reply.map if not required 2023-08-03 09:00:08 +02:00
Patrick Schult
e176724775 Merge pull request #5357 from DocFraggle/staging
Add postscreen_dnsbl_reply_map to avoid disclosure of DQS key
2023-08-03 08:15:16 +02:00
DocFraggle
8f9ed9e0df Merge branch 'staging' into staging 2023-08-02 20:20:18 +02:00
FreddleSpl0it
003eecf131 [Postfix] remove spamhaus dbl and zrd from postscreen_dnsbl_sites 2023-08-02 17:08:55 +02:00
Patrick Schult
180b9fc8d2 Merge pull request #5359 from mailcow/fix/gen-dnsbl
[Postfix] rework dns_blocklists.cf generation
2023-08-02 16:51:56 +02:00
FreddleSpl0it
5d3491c801 [Postfix] only apply DNSBL if dns_blocklists.cf is not empty 2023-08-02 16:48:22 +02:00
FreddleSpl0it
c45684b986 [Postfix] rework dns_blocklists.cf generation 2023-08-02 16:36:59 +02:00
Patrick Schult
5c886d2f4e Merge pull request #5356 from sriccio/fix-postfix-merge-order
Fix main.cf merging order
2023-08-02 15:17:20 +02:00
Christian Hailer
9f39af46aa Add postscreen_dnsbl_reply_map to avoid disclosure of DQS key with Spamhaus setup 2023-08-01 16:12:44 +02:00
Sébastien RICCIO
7cda9f063f Fix for fix
I did not paid attention to the "User overrides" sed/q
2023-08-01 13:59:23 +02:00
Sébastien RICCIO
5e7583c5e6 Fix main.cf merging order
Now the dnsbl files are merged before extra.cf
2023-08-01 10:49:26 +02:00
Niklas Meyer
a1fb962215 Merge pull request #5350 from mailcow/staging
2023-07a
2023-07-31 14:52:24 +02:00
Niklas Meyer
57d849a51b Merge pull request #5349 from DocFraggle/spamhaus_domains
Fix spamhaus query domains (.net only)
2023-07-31 14:34:01 +02:00
Hailer, Christian
3000da6b88 Fix spamhaus query domains (.net only) 2023-07-31 13:50:36 +02:00
Niklas Meyer
db75cbbcb0 Merge pull request #5347 from mailcow/feat/sogo-5.8.4
Update SOGo to 5.8.4
2023-07-31 12:36:24 +02:00
Niklas Meyer
22acbb6b57 Merge pull request #5267 from mailcow/update/postscreen_access.cidr
[Postfix] update postscreen_access.cidr
2023-07-31 12:06:41 +02:00
milkmaker
31cb0f7db1 update postscreen_access.cidr 2023-07-31 10:06:07 +00:00
DerLinkman
6d17b9f504 Added dns_blocklists.cf for customizations 2023-07-31 12:03:31 +02:00
DerLinkman
0f337971ff Reimplemented option for custom dnsbls 2023-07-31 12:03:07 +02:00
DerLinkman
6cf2775e7e Fix Reponse Code for ASN Checks 2023-07-31 12:01:34 +02:00
Niklas Meyer
dabf9104ed Merge pull request #5342 from DocFraggle/mailcow_spamhaus
dns_blocklists.cf isn't appended to main.cf and therefore ineffective…
2023-07-30 19:02:01 +02:00
Christian Hailer
952ddb18fd dns_blocklists.cf isn't appended to main.cf and therefore ineffective #5340 2023-07-30 18:56:52 +02:00
DerLinkman
34d990a800 Removed obsolete whois package 2023-07-28 20:35:28 +02:00
DerLinkman
020cb21b35 Added remote Bad ASN Check for Spamhaus DNSBL 2023-07-28 20:33:12 +02:00
DerLinkman
525364ba65 Implemented remote Bad AS lookup 2023-07-28 20:27:38 +02:00
DerLinkman
731fabef58 Fixed Syntax error in generate_config.sh 2023-07-28 12:20:47 +02:00
DerLinkman
c10be77a1b Fixed Syntax error in generate_config.sh 2023-07-28 12:13:07 +02:00
DerLinkman
a8bc4e3f37 Merge branch 'staging' 2023-07-28 10:35:17 +02:00
DerLinkman
815572f200 Merge branch 'feat/spamhaus-dqs-asn' into staging 2023-07-28 10:33:34 +02:00
Patrick Schult
23fc54f2cf Merge pull request #5332 from mailcow/staging
2023-07
2023-07-28 10:26:49 +02:00
FreddleSpl0it
11407973b1 [Web] change style of f2b active ban actions 2023-07-27 14:19:18 +02:00
FreddleSpl0it
b9867e3fe0 [Web] change style of f2b active ban actions 2023-07-27 14:16:11 +02:00
FreddleSpl0it
3814c3294f [Web] add edit/cors api endpoint to swagger 2023-07-27 13:45:57 +02:00
FreddleSpl0it
9c44b5e546 [Web] display is_catch_all and aliases_send_as_all if not empty #5320 2023-07-27 12:10:01 +02:00
FreddleSpl0it
cd635ec813 [Dockerapi] Update to 2.05 2023-07-27 11:30:47 +02:00
FreddleSpl0it
03831149f8 [Web] fix visual bug #5322 2023-07-27 11:28:49 +02:00
Peter
d8fd023cdb Update rebuild_backup_image.yml 2023-07-24 17:39:41 +02:00
renovate[bot]
521120a448 Update dependency nextcloud/server to v27.0.1 (#5324)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-24 10:43:00 +02:00
DerLinkman
ec8d298c36 Update postfix.sh to include pbl for dqs 2023-07-13 16:42:59 +02:00
FreddleSpl0it
db2759b7d1 [Web] fix wrong content type + add more http 500 responses 2023-07-12 16:46:32 +02:00
DerLinkman
3c3b9575a2 [Netfilter] Update Compose File to 1.53 2023-07-12 09:42:17 +02:00
Patrick Schult
03580cbf39 Merge pull request #5315 from SnailShea/fix/twig-typos
Fixes several instances of missing </span>, extra role='tabpanel' and…
2023-07-12 08:55:28 +02:00
Niklas Meyer
2b009c71c1 Merge pull request #5316 from mailcow/feat/rspamd-securite-symbols
[Rspamd] Native mailcow Support for Securite ClamAV Signatures
2023-07-12 08:27:20 +02:00
SnailShea
b903cf3888 Fixes several instances of missing </span>, extra role='tabpanel' and misspelled 'collapse' 2023-07-11 19:00:05 -04:00
FreddleSpl0it
987cfd5dae [Web] f2b banlist - add http status codes 2023-07-11 10:31:25 +02:00
FreddleSpl0it
1537fb39c0 [Web] add manage f2b external option 2023-07-11 10:19:32 +02:00
FreddleSpl0it
65cbc478b8 [Web] add manage f2b external option 2023-07-11 10:13:00 +02:00
FreddleSpl0it
e2e8fbe313 [Web] add f2b_banlist endpoint 2023-07-10 13:54:23 +02:00
Patrick Schult
cf239dd6b2 Merge pull request #5215 from goodygh/5136-fix-logger-error-handling
[web] logger pdo exception handling workaround
2023-07-10 10:31:38 +02:00
Patrick Schult
a0723f60d2 Merge pull request #5221 from mailcow/fix/dot-stuffing-bcc
[Rspamd] add dot-stuffing to bcc forwarding
2023-07-10 10:07:31 +02:00
Patrick Schult
da8e496430 Merge pull request #5310 from mailcow/feat/ha-pubsub
[Dockerapi] add redis pubsub handler for broadcasting requests
2023-07-10 10:05:07 +02:00
Patrick Schult
722134e474 Merge pull request #5312 from mailcow/fix/ui-logs
[Web] fix loading rspamd-history
2023-07-10 10:03:29 +02:00
FreddleSpl0it
cb1a11e551 [Web] fix rspamd-history 2023-07-10 09:35:51 +02:00
Patrick Schult
8984509f58 Merge pull request #5213 from mailcow/feat/cors
[Web] add cors to json_api
2023-07-07 14:13:09 +02:00
FreddleSpl0it
0f0d43b253 [Dockerapi] add missing import os 2023-07-07 11:32:28 +02:00
FreddleSpl0it
0f6956572e [Web] add CLUSTERMODE environment variable 2023-07-07 09:58:51 +02:00
Niklas Meyer
29892dc694 Merge pull request #5262 from mailcow/fix-5252
Rspamd returns 401 on unsuccesful logins
2023-06-27 11:16:34 +02:00
Niklas Meyer
14265f3de8 Merge pull request #5263 from mailcow:update-api
[API] Update swagger version to 5.1.0
2023-06-27 10:41:24 +02:00
Niklas Meyer
0863bffdd2 Merge pull request #5283 from superpuffin:master
Update nextcloud heper script to disable SMTP TLS host verification
2023-06-27 10:40:06 +02:00
Niklas Meyer
3b748a30cc Merge pull request #5284 from mailcow:renovate/nextcloud-server-27.x
Update dependency nextcloud/server to v27
2023-06-27 10:39:08 +02:00
DerLinkman
5619175108 Upate SOGo to 5.8.4 2023-06-27 10:36:53 +02:00
DerLinkman
6e9c024b3c Changed weight to score for CLAMD_SPAM 2023-06-27 10:28:52 +02:00
DerLinkman
8cd4ae1e34 Improved Scores 2023-06-23 16:19:37 +02:00
DerLinkman
689856b186 New Symbols defined for Security ClamAV DBs 2023-06-23 16:13:25 +02:00
DerLinkman
7b645303d6 Added Colorful Outputs for the Spamhaus info in PF 2023-06-23 15:54:49 +02:00
DerLinkman
408381bddb Update Postfix image to 1.69 + improvements 2023-06-23 15:48:13 +02:00
DerLinkman
380cdab6fc Removed dnsbl from main.cf 2023-06-23 14:26:17 +02:00
DerLinkman
03b7a8d639 Implemented Postfix Blocklist generation 2023-06-23 14:25:07 +02:00
DerLinkman
bf6a61fa2d Small corrections to update/generate.sh 2023-06-23 14:20:06 +02:00
DerLinkman
1de47072f8 Added DQS Values to update.sh/generate + check of variable 2023-06-23 12:26:57 +02:00
Peter
c0c46b7cf5 [API] Update swagger version 2023-06-19 21:35:10 +02:00
Peter
42a91af7ac [API] Update swagger version 2023-06-15 19:20:09 +02:00
renovate[bot]
6e1ee638ff Update dependency nextcloud/server to v27
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-06-13 14:02:53 +00:00
Yorgos Bos
61c8afa088 Fix smtp settings for nextcloud v26 2023-06-13 10:54:42 +02:00
renovate[bot]
c873a14127 Update thollander/actions-comment-pull-request action to v2.4.0 (#5280)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-12 17:12:59 +02:00
FreddleSpl0it
06cce79806 [Dockerapi] add pubsub handler for broadcasting in ha setup 2023-06-12 16:37:48 +02:00
DerLinkman
0927c5df57 Fixed small typo in update.sh 2023-06-01 15:27:00 +02:00
Niklas Meyer
e691d2c782 Merge pull request #5266 from mailcow/staging
[Dovecot] remove pass return in Dovecot lua auth
2023-05-30 16:57:10 +02:00
FreddleSpl0it
67510adb9e [Dovecot] remove pass return in Dovecot lua auth 2023-05-30 16:47:03 +02:00
Niklas Meyer
490d553dfc Merge pull request #5264 from mailcow/staging
2023-05a
2023-05-30 16:23:26 +02:00
DerLinkman
70aab7568e Changed maintainers to tinc (Dockerfiles) 2023-05-30 16:20:35 +02:00
DerLinkman
f82aba3e26 [Dovecot] Update to 1.24 2023-05-30 16:18:14 +02:00
FreddleSpl0it
f80940efdc [Dovecot] remove pass return in Dovecot lua auth 2023-05-30 09:09:41 +02:00
Peter
6f875398c0 [API] Update swagger version 2023-05-28 23:29:58 +02:00
Peter
7a582afbdc Rspamd returns 401 on unsuccesful logins 2023-05-28 22:43:26 +02:00
renovate[bot]
38cd376228 Update dependency nextcloud/server to v26.0.2 (#5254)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-28 15:48:28 +02:00
Niklas Meyer
74bcec45f1 Merge pull request #5250 from mailcow/staging
2023-05
2023-05-25 16:30:16 +02:00
Niklas Meyer
9700b3251f Merge pull request #5214 from mailcow/feat/gh_actions_postscreen
Add GitHub action update_postscreen_access_list.yml
2023-05-25 15:40:20 +02:00
Niklas Meyer
88b8d50cd5 Merge pull request #4028 from Daniel15/patch-2
Enable maildir_very_dirty_syncs by default
2023-05-24 11:00:38 +02:00
DerLinkman
55b0191050 [PHP] Update to 1.84 2023-05-23 10:46:21 +02:00
Peter
33c97fb318 change domain for docs 2023-05-10 20:32:38 +02:00
Niklas Meyer
23d33ad5a8 Merge pull request #5231 from mailcow/renovate/alpine-3.x
Update alpine Docker tag to v3.18
2023-05-10 08:58:47 +02:00
renovate[bot]
bd6c98047a Update alpine Docker tag to v3.18
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-05-10 01:50:21 +00:00
Patrick Schult
73d6a29ae1 Merge pull request #5205 from mailcow/clean_sasl_log
Clean up old entries from sasl_log
2023-05-09 09:49:40 +02:00
Patrick Schult
173e39c859 Merge pull request #5200 from mailcow/fix/delete-sender-acl
[Web] Fix deleting sender_acl when mbox is deleted
2023-05-08 16:35:42 +02:00
Patrick Schult
c0745c5cde Merge pull request #5197 from mailcow/fix/bcc-validation
[Web] Fix BCC validation
2023-05-08 16:32:12 +02:00
Patrick Schult
1a6f93327e Merge pull request #5203 from mailcow/feat/bad_asn
Add IP Connect Inc to bad_asn.map
2023-05-08 16:01:44 +02:00
Patrick Schult
3c68a53170 Merge pull request #5201 from mailcow/fix/sieve-print
[Dockerapi] Fix typo in dockerapi sieve print
2023-05-08 16:00:22 +02:00
Patrick Schult
e38c27ed67 Merge pull request #5211 from goodygh/5175-fix-mobileconfig-redirect
[web] Fix typo in mobileconfig redirect
2023-05-08 15:55:50 +02:00
Patrick Schult
8eaf8bbbde Merge pull request #5220 from mailcow/fix/bcc-selectpicker
[Web] fix bcc localdest selectpicker
2023-05-08 15:53:53 +02:00
Patrick Schult
e015c7dbca Merge pull request #5202 from mailcow/feat/user-acl-tabs
[Web] hide user tabs if acl is missing
2023-05-08 15:48:52 +02:00
Patrick Schult
58452abcdf Merge pull request #5204 from mailcow/fix/rspamd-table
[Web] fix rspamd table on sm devices
2023-05-08 15:43:58 +02:00
Patrick Schult
2cbf0da137 Merge pull request #5198 from mailcow/fix/sorting-tla
[Web] Fix temporary email aliases sorting
2023-05-08 15:29:32 +02:00
FreddleSpl0it
f295b8cd91 [Rspamd] add domain wide footer 2023-05-08 12:55:38 +02:00
FreddleSpl0it
97a492b891 [Rspamd] add dot-stuffing to bcc forwarding 2023-05-03 15:04:09 +02:00
FreddleSpl0it
aabcd10539 [Web] fix bcc localdest selectpicker 2023-05-03 09:59:49 +02:00
milkmaker
ee607dc3cc Translations update from Weblate (#5218)
* [Web] Updated lang.en-gb.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.cs-cz.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.ro-ro.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.sk-sk.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.zh-cn.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.it-it.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.zh-tw.json

Co-authored-by: Peter <magic@kthx.at>

---------

Co-authored-by: Peter <magic@kthx.at>
2023-05-02 18:29:38 +02:00
DerLinkman
1265302a8e [DockerAPI] Update to 2.04 2023-05-02 18:11:59 +02:00
DerLinkman
b5acf56e20 Added Platform Information on Status Page 2023-05-02 18:11:10 +02:00
goodygh
9752313d24 logger pdo exception handling workaround 2023-04-29 02:39:04 +02:00
FreddleSpl0it
fe4a418af4 [Web] fix rspamd table scan_time on sm devices 2023-04-27 10:45:11 +02:00
Peter
e5f03e8526 Update update_postscreen_whitelist.sh 2023-04-26 18:44:35 +02:00
Peter
fb60c4a150 Add update_postscreen_access_list.yml 2023-04-26 18:43:54 +02:00
FreddleSpl0it
6b82284a41 [Web] cors - add check if origin is valid 2023-04-26 11:19:50 +02:00
FreddleSpl0it
192f67cd41 [Web] add cors to json_api 2023-04-26 10:46:07 +02:00
goodygh
fd203abd47 Fix typo in mobileconfig redirect 2023-04-25 22:11:04 +02:00
milkmaker
6b65f0fc74 [Web] Updated lang.ru-ru.json (#5210)
Co-authored-by: Vakhtang <vakhtang.g.st@gmail.com>
2023-04-25 20:59:05 +02:00
Michael Kuron
856b3b62f2 Clean up old sasl_log entries 2023-04-22 14:16:42 +02:00
FreddleSpl0it
0372a2150d [Web] fix rspamd table on sm devices 2023-04-21 20:14:43 +02:00
Peter
f3322c0577 Add IP Connect Inc 2023-04-21 19:43:20 +02:00
FreddleSpl0it
c2bcc4e086 [Web] hide user tabs if acl is missing 2023-04-21 17:03:40 +02:00
FreddleSpl0it
6e79c48640 [Dockerapi] Fix typo in dockerapi sieve print 2023-04-21 16:15:16 +02:00
FreddleSpl0it
d7dfa95e1b [Web] Fix deleting sender_acl when mbox is deleted 2023-04-21 13:47:13 +02:00
FreddleSpl0it
cf1cc24e33 [Web] Fix temporary email aliases sorting 2023-04-21 12:26:50 +02:00
FreddleSpl0it
6824a5650f [Web] Fix BCC validation 2023-04-21 11:21:43 +02:00
Niklas Meyer
73570cc8b5 Merge pull request #5196 from ewong012/staging 2023-04-21 08:14:24 +02:00
Ethan Wong
959dcb9980 [Update.sh] Fix install docs link
Old link returns 404.
2023-04-20 13:52:46 -07:00
Patrick Schult
8f28666916 Merge pull request #5195 from mailcow/staging
2023-04b
2023-04-20 16:49:17 +02:00
Patrick Schult
3eaa5a626c Merge pull request #5187 from mailcow/fix-5185
Nextcloud helperscript - redo PHP check
2023-04-20 14:20:03 +02:00
Patrick Schult
8c79056a94 Merge pull request #5194 from mailcow/renovate/nextcloud-server-26.x
Update dependency nextcloud/server to v26.0.1
2023-04-20 14:19:19 +02:00
Patrick Schult
ed076dc23e Merge pull request #5186 from goodygh/datatables_sorting
[Web] Datatables sorting
2023-04-20 13:50:57 +02:00
FreddleSpl0it
be2286c11c [Dockerapi] fix maildir cleanup for domains 2023-04-20 13:41:11 +02:00
renovate[bot]
0e24c3d300 Update dependency nextcloud/server to v26.0.1
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-04-20 11:36:01 +00:00
FreddleSpl0it
e1d8df6580 [Web] check mailbox before replacing sogo_static_view 2023-04-20 13:20:51 +02:00
Patrick Schult
04a08a7d69 Merge pull request #5193 from mailcow/feat/update-sogo
[SOGo] update sogo 5.8.2.20230419
2023-04-20 12:32:42 +02:00
FreddleSpl0it
3c0c8aa01f [SOGo] update sogo 5.8.2.20230419 2023-04-20 12:07:21 +02:00
Patrick Schult
026b278357 Merge pull request #5183 from mailcow/fix/add-mbox-performance
[Web] optimizing mailbox add/edit/delete performance
2023-04-20 11:34:41 +02:00
FreddleSpl0it
4121509ceb [Web] optimizing update_sogo_static_view function 2023-04-20 11:28:59 +02:00
Patrick Schult
00ac61f0a4 Merge pull request #5184 from bdwebnet/fix/ui-allowed-protocols
Added dropdown divider to "allowed protocols" selection on mailbox page
2023-04-19 17:31:05 +02:00
Patrick Schult
4bb0dbb2f7 Merge pull request #5191 from shiz0/patch-1
Fix Typo
2023-04-19 17:26:54 +02:00
Patrick Schult
13b6df74af Merge pull request #5174 from bdwebnet/staging
Fix error  "Deprecated: Using ${var} in strings is deprecated, use {$…
2023-04-19 17:23:26 +02:00
FreddleSpl0it
5c025bf865 [Rspamd] rollback to 3.4 2023-04-19 17:03:04 +02:00
Hannes Happle
20fc9eaf84 Fix Typo 2023-04-16 14:32:44 +02:00
Peter
22a0479fab Redo the PHP check grep 2023-04-13 21:11:40 +02:00
goodygh
3510d5617d Fix sorting for active relayhost 2023-04-13 19:18:04 +02:00
goodygh
236d627fbd Fix sorting for active transport map 2023-04-13 19:14:20 +02:00
goodygh
99739eada0 Fix sorting for active fowrardinghoststable 2023-04-13 19:01:03 +02:00
goodygh
7bfef57894 Fix sorting for active and tla on admins 2023-04-13 18:54:59 +02:00
goodygh
d9dfe15253 Fix sorting for active and tla on domain-admins 2023-04-13 18:54:08 +02:00
goodygh
3fe8aaa719 Fix sorting for active tls-policy-map 2023-04-13 18:14:18 +02:00
goodygh
78a8fac6af Fix sorting for active bcc-map and recipient-map 2023-04-13 18:10:21 +02:00
bd
6986e7758f Added dropdown divider to "allowed protocols" selection on mailbox page 2023-04-13 17:33:28 +02:00
BD
b4a9df76b8 Merge branch 'mailcow:staging' into staging 2023-04-13 17:22:13 +02:00
FreddleSpl0it
d9d958356a [Web] optimizing update_sogo_static_view function 2023-04-13 14:35:55 +02:00
goodygh
96f954a4e2 Fix sorting for active syncjobs 2023-04-12 00:36:46 +02:00
goodygh
44585e1c15 Fix sorting datatable in domain aliases 2023-04-12 00:23:53 +02:00
goodygh
c737ff4180 Fix sorting datatable in aliases 2023-04-12 00:21:27 +02:00
goodygh
025279009d Fix sorting for active resources 2023-04-12 00:17:41 +02:00
goodygh
a9dc13d567 Fix sorting datatable in mailbox templates 2023-04-12 00:15:16 +02:00
goodygh
c3ed01c9b5 Fix sorting for active mailboxes 2023-04-11 23:49:50 +02:00
goodygh
bd0b4a521e Fix sorting datatable in domain templates 2023-04-11 23:42:43 +02:00
goodygh
800a0ace71 Fix sorting for active domain in domains table 2023-04-11 23:19:56 +02:00
goodygh
db97869472 Datatable hide sorting value 2023-04-11 23:18:13 +02:00
milkmaker
f681fcf154 [Web] Updated lang.cs-cz.json (#5177)
Co-authored-by: utaxiu <kontakt@malyjakub.cz>
2023-04-11 17:38:39 +02:00
Patrick Schult
db1b5956fc Merge pull request #5133 from FELDSAM-INC/feldsam/bs5-related-fixes
BS5 related fixes
2023-04-11 06:35:41 +02:00
BD
bdb07061ed Fix error "Deprecated: Using ${var} in strings is deprecated, use {$var} instead in /web/sogo-auth.php on line 63" 2023-04-08 17:29:34 +02:00
Niklas Meyer
428b917579 Merge pull request #5166 from mailcow/staging
Hotfix php8.2 nextcloud < 26
2023-04-03 20:15:46 +02:00
Niklas Meyer
469f959e96 Merge pull request #5164 from mailcow/fix-5163
Add a check for PHP>=8.2 errormsg
2023-04-03 20:10:05 +02:00
Peter
b68e189d97 Add a check for PHP>=8.2 errormsg 2023-04-03 19:03:13 +02:00
Niklas Meyer
028ef22878 Merge pull request #5162 from mailcow/staging
Update 2023-04
2023-04-03 14:55:55 +02:00
Kristian Feldsam
80dacc015a [web] fixed mailbox/user settings buttons styling
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>

[web] fixed mailbox/user settings buttons styling

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-03-31 13:19:20 +02:00
Patrick Schult
0194c39bd5 Merge pull request #5158 from mailcow/feat/sogo-5.8.2
[SOGo] Update to 5.8.2
2023-03-31 08:16:57 +02:00
FreddleSpl0it
f53ca24bb0 [SOGo] Update to 5.8.2 2023-03-30 16:00:21 +02:00
Patrick Schult
ae46a877d3 Merge pull request #5157 from mailcow/feat/netfilter-1.52
[Netfilter] Update to 1.52
2023-03-30 09:05:52 +02:00
FreddleSpl0it
400939faf6 [Netfilter] Update to 1.52 2023-03-30 08:44:38 +02:00
Patrick Schult
fd0205aafd Merge pull request #5127 from th-joerger/feature/bantime-increment
[Netfilter] Implemented exponentially incrementing bantime
2023-03-30 07:53:33 +02:00
Patrick Schult
e367a8ce24 Merge pull request #5153 from mailcow/fix/del-vmail-index
[Dockerapi] delete vmail_index on maildir cleanup
2023-03-30 07:52:00 +02:00
Thorbjörn Jörger
096e2a41e9 Push verified options to redis after each check 2023-03-29 17:09:25 +02:00
Thorbjörn Jörger
e010f08143 verify options after loading them, set defaults if options are missing or invalid 2023-03-29 15:24:14 +02:00
Patrick Schult
3d2483ca37 Merge pull request #5093 from brunoleon/fix_snat
Fix SNAT never being added because of exception
2023-03-29 08:13:11 +02:00
Niklas Meyer
535dd23509 Merge pull request #5139 from mailcow/renovate/mailcow-rspamd-1.x
Update mailcow/rspamd Docker tag to v1.93
2023-03-28 11:44:59 +02:00
DerLinkman
4336a99c6a [Nextcloud] Changed default X-Robots Tag behavior 2023-03-28 11:40:00 +02:00
DerLinkman
4cd5f93cdf Fixed broken pipe errors in nextcloud.sh 2023-03-28 11:22:49 +02:00
DerLinkman
67955779b0 Fix broken pipe error in reset-admin.sh 2023-03-28 11:17:59 +02:00
FreddleSpl0it
26c34b484a increase dockerapi image 2023-03-28 11:01:14 +02:00
FreddleSpl0it
4021613059 delete vmail_index when mbox is deleted 2023-03-28 10:59:08 +02:00
Niklas Meyer
e891bf8411 Merge pull request #5138 from th-joerger/feature/pubsub-exception
[netfilter] add pubsub exception
2023-03-27 10:40:40 +02:00
Niklas Meyer
f7798d1aac Merge pull request #5099 from mailcow/feat/phpfpm-8.2
Update to PHP 8.2
2023-03-27 10:13:42 +02:00
Niklas Meyer
d11f00261b Merge pull request #5142 from mailcow/renovate/nextcloud-server-26.x
Update dependency nextcloud/server to v26
2023-03-27 10:12:55 +02:00
renovate[bot]
22cd12f37b Update dependency nextcloud/server to v26
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-03-25 18:48:22 +00:00
Peter
db2fb12837 Install sysvsem for Nextcloud 26 2023-03-24 16:08:19 +01:00
Peter
e808e595eb Update dependency composer/composer to v2.5.5 2023-03-24 16:05:35 +01:00
Niklas Meyer
ce6742c676 Merge pull request #5147 from mailcow/renovate/nextcloud-server-25.x
Update dependency nextcloud/server to v25.0.5
2023-03-23 19:38:23 +01:00
renovate[bot]
cf3dc584d0 Update dependency nextcloud/server to v25.0.5
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-03-23 14:18:29 +00:00
renovate[bot]
62f3603588 Update actions/stale action to v8 (#5143)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-22 15:00:55 +01:00
renovate[bot]
9fd4aa93e9 Update mailcow/rspamd Docker tag to v1.93
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-03-21 10:32:21 +00:00
Thorbjörn Jörger
5bc3d93545 log exception of redis pubsub subscription 2023-03-21 11:14:52 +01:00
Thorbjörn Jörger
c28a6b89f0 Added ban_time_increment and max_ban_time to UI 2023-03-21 11:06:13 +01:00
Thorbjörn Jörger
1233613bea implemented handling of max_bantime and ban_time_increment flag 2023-03-21 11:06:13 +01:00
Thorbjörn Jörger
0206e0886c implemented exponentially incrementing bantime, removed active_window code that did nothing, cleanly initialized dictionary 2023-03-21 11:06:13 +01:00
DerLinkman
f6d135fbad [Update.sh] Fix docker compose detection + added failover 2023-03-20 12:05:11 +01:00
Niklas Meyer
f7da314dcf Merge pull request #5134 from mailcow/fix/generate-config-dev
[Generate.sh] Fixed broken pipe error message
2023-03-20 11:08:11 +01:00
DerLinkman
e6ce5e88f7 [Generate.sh] Fixed broken pipe error message 2023-03-20 10:57:40 +01:00
Kristian Feldsam
e5e6418be8 [web] fixed tooltips in ajax loaded alias table
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-03-20 01:38:34 +01:00
Kristian Feldsam
6507b53bbb [web] fix mailbox badge height
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-03-20 01:38:31 +01:00
Kristian Feldsam
2eafd89412 [web] apple config app passwords enhancements + translations
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-03-18 16:29:11 +01:00
milkmaker
0f59d4952b Translations update from Weblate (#5131)
* [Web] Updated lang.da-dk.json

Co-authored-by: Victor Pahuus Petersen <dibbohh@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

Co-authored-by: UpSilot <alexandre+weblate@kilobit.fr>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Victor Pahuus Petersen <dibbohh@gmail.com>
Co-authored-by: UpSilot <alexandre+weblate@kilobit.fr>
2023-03-17 19:13:49 +01:00
Niklas Meyer
7225bd2f55 Merge pull request #5107 from kaechele:staging
Fix SELinux labelling of init_db.inc.php for SOGo
2023-03-09 14:37:21 +01:00
Niklas Meyer
deb2b80352 Merge pull request #5108 from mailcow:dragoangel-patch-1
[Rspamd] Fix cases of forwarding via freemail
2023-03-09 14:33:48 +01:00
Niklas Meyer
ad9dee92be Merge pull request #5119 from bdwebnet:staging
Fixes Issue #5118 (Bug with load more logs buttons)
2023-03-09 14:30:55 +01:00
BD
f36bc16ca7 Fix Bug with button to load more logs 2023-03-08 10:35:23 +01:00
Niklas Meyer
bda5f0ed4a Merge pull request #5109 from mailcow/dragoangel-patch-2
[SOGo] Disable password change option
2023-03-07 09:07:45 +01:00
milkmaker
cbe1c97a82 Translations update from Weblate (#5114)
* [Web] Updated lang.da-dk.json

[Web] Updated lang.da-dk.json

[Web] Updated lang.da-dk.json

Co-authored-by: Tacaly <frederick@tacaly.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

Co-authored-by: Matthieu Leboeuf <contact@matthieul.dev>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Tacaly <frederick@tacaly.com>
Co-authored-by: Matthieu Leboeuf <contact@matthieul.dev>
2023-03-07 05:39:22 +01:00
Dmitriy Alekseev
81fcbdd104 [SOGo] Disable password change option
It doesn't work with ProxyAuth and in general not honor password policy set via mailcow UI. SOGo also do not provide own settings to provide any password policy. Due to this two issues I think that it's better have it disabled by default. People who need it can turn it back easily. We can update https://docs.mailcow.email/manual-guides/SOGo/u_e-sogo/#disable-password-changing to `enable-password-changin` and explanations of reasons why it is disabled.
2023-03-04 18:06:26 +02:00
Dmitriy Alekseev
1a9294b58f [Rspamd] Fix cases of forwarding via freemail
Excluding FREEMAIL_ENVFROM from the FREEMAIL_POLICY_FAILURE expression will allow forwarding mail via freemail services when the initial sender did not have a DKIM signature.
2023-03-04 17:57:52 +02:00
Felix Kaechele
310c01aac2 Fix SELinux labelling of init_db.inc.php for SOGo
init_db.inc.php is currently labelled as exclusive for SOGo while in
truth it is shared among containers.
This breaks the admin interface but also any of the DAV features of
SOGo.

Signed-off-by: Felix Kaechele <felix@kaechele.ca>
2023-03-03 22:57:10 -05:00
Niklas Meyer
229303c1f8 Merge pull request #5106 from mailcow/staging
2023-03
2023-03-03 17:34:24 +01:00
Niklas Meyer
fc075bc6b7 Merge pull request #5104 from svengo/patch-4
[Helper] Update expiry-dates.sh
2023-03-03 12:44:00 +01:00
DerLinkman
d04f0257c2 Fixed permission for expiry-dates.sh 2023-03-03 12:41:24 +01:00
Sven Gottwald
d11d356803 [Helper] Update expiry-dates.sh
- Use port numbers from `mailcow.conf` instead of fixed port numbers 
- reformat output
2023-03-03 12:34:23 +01:00
Niklas Meyer
c54750ef8b Merge pull request #5085 from kritzl/patch-2
Fix cursor style when hovering 'Aliases' tab
2023-03-03 12:09:14 +01:00
Niklas Meyer
510ef5196b Merge pull request #5097 from rekup/fix/URLHAUS_ABUSE_CH
fix URLHAUS_ABUSE_CH check
2023-03-03 12:04:07 +01:00
FreddleSpl0it
04e46f9f5b [Imapsync] Use pure perl code for XOAUTH2 authmech 2023-03-03 09:57:09 +01:00
milkmaker
6c0a5028c0 [Web] Updated lang.da-dk.json (#5102)
Co-authored-by: Tacaly <frederick@tacaly.com>
2023-03-02 20:02:08 +01:00
Niklas Meyer
791bbeeb39 Merge pull request #5098 from mailcow/feat/fix-raw-attr
Add raw attribute for lang.admin.hash_remove_info
2023-03-01 21:36:40 +01:00
Peter
a5b8f1b7f7 Update to PHP 8.2 2023-02-28 20:08:33 +01:00
Peter
af267ff706 Add raw attribute for lang.admin.hash_remove_info 2023-02-28 19:42:46 +01:00
Reto Kupferschmid
46cc022590 fix URLHAUS_ABUSE_CH check 2023-02-28 14:30:38 +01:00
Bruno Léon
f77c65411d Fix SNAT never being added because of exception
Some firewall rule object (iptc) do not have a parameter
attribute, which results in an exception being triggered,
and the mailcow SNAT rule to never be created.

Firewall rules that trigger such exception are:
- -A POSTROUTING -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN

This commit just verify attribute presence, and skip the rule
properly instead of triggering an exception.
2023-02-27 12:04:32 +01:00
milkmaker
1052e13af8 Translations update from Weblate (#5092)
* [Web] Updated lang.da-dk.json

Co-authored-by: Tacaly <frederick@tacaly.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.pl-pl.json

Co-authored-by: KristopherMackowiak <kkriss75@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

---------

Co-authored-by: Tacaly <frederick@tacaly.com>
Co-authored-by: KristopherMackowiak <kkriss75@gmail.com>
2023-02-25 19:25:24 +01:00
Niklas Meyer
11e1502b12 Merge pull request #5089 from mailcow/renovate/nextcloud-server-25.x 2023-02-24 10:53:12 +01:00
renovate[bot]
02afc45a15 Update dependency nextcloud/server to v25.0.4
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-02-23 20:07:37 +00:00
kritzl
3e1cfe0d08 Fix cursor style when hovering 'Aliases' tab 2023-02-22 00:11:56 +01:00
Felix Kleinekathöfer
a3c5f785e9 Added new env vars to docker compose 2023-02-20 22:34:53 +01:00
Niklas Meyer
d20df7d73e Merge pull request #5068 from mailcow/staging
2022-02a
2023-02-17 15:52:53 +01:00
Niklas Meyer
a8c61daeaf Merge pull request #5070 from mailcow/fix/snat
[Netfilter] Fix IPv4 Subrouting not added properly
2023-02-17 15:44:16 +01:00
Niklas Meyer
1a4f11209a Updated netfilter to 1.51 2023-02-17 13:22:23 +01:00
FreddleSpl0it
04403aaf70 [Netfilter] fix setting SNAT Rule if chain is empty 2023-02-17 13:15:44 +01:00
Niklas Meyer
7f0dd7d0d7 [Nextcloud] Added bzip2 as required package 2023-02-17 12:53:31 +01:00
FreddleSpl0it
cd29ad883e Merge branch 'staging' of https://github.com/mailcow/mailcow-dockerized into staging 2023-02-16 17:12:11 +01:00
FreddleSpl0it
e1cd719a17 [Web] fix mbox percentage sorting 2023-02-16 17:12:03 +01:00
Niklas Meyer
15bb331a7d Merge pull request #5048 from mailcow/renovate/composer-composer-2.x
Update dependency composer/composer to v2.5.4
2023-02-16 17:03:45 +01:00
Niklas Meyer
6f3179bb8d [web] Change FIDO2 login to independent button 2023-02-16 17:03:09 +01:00
Niklas Meyer
29e5b87207 Changed Language strings for clearer button meaning 2023-02-16 16:30:36 +01:00
Niklas Meyer
4403bc2d18 Merge pull request #5064 from mailcow/feat/clamav-1.0.1
[CLAMAV] Update to 1.0.1
2023-02-16 14:59:17 +01:00
Niklas Meyer
63e92e0897 [CLAMAV] Update to 1.0.1 2023-02-16 14:56:56 +01:00
renovate[bot]
aa4d8b1f47 Update dependency composer/composer to v2.5.4
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2023-02-15 13:51:12 +00:00
milkmaker
9054ca18be [Web] Updated lang.lv-lv.json (#5061)
Co-authored-by: Edgars Andersons <Edgars+Mailcow+Weblate@gaitenis.id.lv>
2023-02-14 19:33:12 +01:00
Niklas Meyer
38291d123f [DB] Fix espacing of special db names during upgrade 2023-02-14 10:11:55 +01:00
renovate[bot]
ca64ff2c0b Update devops-infra/action-pull-request action to v0.5.5 (#5060)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 23:56:14 +01:00
Tomy Hsieh
dc85f49961 feat: Change FIDO2 login to independent button 2023-02-11 21:49:21 +08:00
milkmaker
5dca4dac81 [Web] Updated lang.ru-ru.json (#5046)
Co-authored-by: Aleksandr Kliushenok <alex.1501@icloud.com>
2023-02-04 15:00:07 +01:00
Patrick Schult
df8775d4c9 Merge pull request #5040 from mailcow/staging
2023-02
2023-02-02 15:31:34 +01:00
Niklas Meyer
2bc663dcd5 Removed Twitter Action due to Twitter Paid API (soon). Thx Elon! 2023-02-02 14:55:44 +01:00
Patrick Schult
1071bb8230 Merge pull request #4967 from FELDSAM-INC/feldsam/sso
[Web] Implemented SSO for domain admins
2023-02-02 12:12:53 +01:00
Niklas Meyer
e437810eca Merge pull request #5038 from mailcow/fix/sogo-macos-fix
[Fix] SOGo Update Fix for 5.8.0 (macOS fix)
2023-02-02 11:32:35 +01:00
FreddleSpl0it
e8fd34d31f [Web] webauthn add lang strings 2023-02-02 11:28:51 +01:00
Niklas Meyer
6aebb8352e [Fix] SOGo Update Fix for 5.8.0 (macOS fix) 2023-02-02 11:03:51 +01:00
Patrick Schult
d684e0efc0 Merge pull request #5034 from mailcow/fix/skip-sogo
[Web] Skip update_sogo_static_view if sogo is disabled
2023-01-31 11:03:50 +01:00
FreddleSpl0it
64ac6a8891 [Web] Skip update_sogo_static_view if sogo is disabled 2023-01-31 10:54:16 +01:00
FreddleSpl0it
72e8180c6b [Web] datatable adjustment 2023-01-31 10:37:51 +01:00
FreddleSpl0it
d62c275004 [Web] match PAGINATION_SIZE to an existing datatable option 2023-01-31 09:49:18 +01:00
Patrick Schult
aa7f562761 Merge pull request #5011 from realizelol/staging
[BS5] Support for pagination_size + some minor improvements (to quarantine)
2023-01-31 09:43:51 +01:00
renovate[bot]
a1f033e4c1 Update docker/build-push-action action to v4 (#5032)
Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-30 19:58:17 +01:00
milkmaker
58ddc31db6 Translations update from Weblate (#5026)
* [Web] Updated lang.en-gb.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.sk-sk.json

Co-authored-by: Lukáš Matula <lukas@gbely.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Lukáš Matula <lukas@gbely.net>
2023-01-26 20:09:52 +01:00
Kristian Feldsam
5bf62481d5 [Web] Implemented SSO for domain admins
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>

Revert "[Web] Implemented SSO for domain admins"

This reverts commit 6860dc8ebe2c8f53d77df5bca7787f7cb3bb4ee0.

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2023-01-26 15:54:44 +01:00
realizelol
6ff3f3f044 [Web] Set pageLength to pagination_size + repect savedState...
Fix width in quarantine table.
2023-01-25 23:50:39 +01:00
Niklas Meyer
640f535e99 Merge pull request #5019 from mailcow/staging
2023-01a
2023-01-25 16:29:22 +01:00
Niklas Meyer
05d1a974eb Merge pull request #5003 from mailcow/feat/acme-skip-ip-check
[Acme] Implemented IP Check Bypass properly
2023-01-25 16:10:11 +01:00
Niklas Meyer
99e38d81b1 Removed Integration Tests 2023-01-25 16:09:15 +01:00
FreddleSpl0it
ed7b384e24 [Web] fix queue btn showing undefined 2023-01-25 09:34:12 +01:00
FreddleSpl0it
5439ea1010 Merge branch 'staging' of https://github.com/mailcow/mailcow-dockerized into staging 2023-01-25 09:32:27 +01:00
FreddleSpl0it
b719982504 partial rollback of dockerapi 2023-01-25 09:31:22 +01:00
milkmaker
8281d3fa55 [Web] Updated lang.da-dk.json (#5020)
Co-authored-by: osos <osos@openeyes.dk>

Co-authored-by: osos <osos@openeyes.dk>
2023-01-24 20:18:17 +01:00
FreddleSpl0it
9ba65a572e [Web] add missing template var for dadmins 2023-01-24 10:13:30 +01:00
FreddleSpl0it
afddcf7f3b replace nullnull.org with fuzzy.mailcow.email 2023-01-24 09:49:49 +01:00
Niklas Meyer
294569f5c9 Merge pull request #5015 from mailcow/feat/nc-install-fix
Fix nextcloud install
2023-01-22 16:17:18 +01:00
Peter
ef6452cf55 Fix installation of nextcloud 2023-01-22 15:06:36 +01:00
renovate[bot]
9af40eba10 Update dependency nextcloud/server to v25.0.3 (#4996)
Signed-off-by: milkmaker <milkmaker@mailcow.de>

Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-20 15:37:12 +01:00
renovate[bot]
1b3a13ca19 Update alpine Docker tag to v3.17 (#4997)
Signed-off-by: milkmaker <milkmaker@mailcow.de>

Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-20 15:36:52 +01:00
Patrick Schult
71cc607de6 Merge pull request #5006 from mailcow/staging
Revert Docker Compose detection commits
2023-01-19 16:04:50 +01:00
FreddleSpl0it
2ebd8345df Revert "[Generate] Refactor compose version detection using regex"
This reverts commit 4c6f8c4f60.
2023-01-19 15:58:22 +01:00
FreddleSpl0it
f5baeb31c1 Revert "[Update.sh] Implemented optimized Regex Compose Detection"
This reverts commit a76e6b32f7.
2023-01-19 15:57:49 +01:00
DerLinkman
5abda44bc6 Merge branch 'staging' 2023-01-19 14:07:55 +01:00
DerLinkman
520d070081 [Compose] Removed OOMKillDisabled from dockerapi 2023-01-19 14:04:55 +01:00
Niklas Meyer
86beba6f5a Merge pull request #4995 from mailcow/staging
2023-01
2023-01-19 12:25:57 +01:00
Niklas Meyer
f0d9948aee Merge pull request #4991 from mailcow/feat/dovecot-2.3.20
[Dovecot] Update to 2.3.20
2023-01-19 11:31:59 +01:00
DerLinkman
8e3d2f7010 [SOGo] Update to newer 5.8.0 (fix for macOS Caldav Bug) 2023-01-19 11:28:03 +01:00
Niklas Meyer
fc1c5a505d Merge pull request #4992 from mailcow/feat/phpfpm-renovate
Update composer and allow renovate for updating Dockerfiles
2023-01-19 10:54:02 +01:00
Niklas Meyer
18cb06fbc7 Merge pull request #4993 from mailcow/feat/renovate-docker-compose
Update renovate config
2023-01-18 21:22:15 +01:00
Peter
1af785a94f Enable dependencyDashboard
Add label for PRs
Add docker-compose manager
2023-01-18 19:37:09 +01:00
Peter
7626becb38 Add regex for matchstring line in Dockerfiles 2023-01-17 19:48:42 +01:00
Peter
5d5e959729 Add regex for matchstring line in Dockerfiles
Update composer to 2.5.1
2023-01-17 19:45:32 +01:00
Niklas Meyer
49bbdd064e Merge pull request #4989 from mailcow/feat/nextcloud-script-overhaul
[Nextcloud] Updated and improved script (implemented -u and more)
2023-01-17 16:34:58 +01:00
DerLinkman
9279ee2e76 [Dovecot] Update to 2.3.20 2023-01-17 16:23:31 +01:00
DerLinkman
a76e6b32f7 [Update.sh] Implemented optimized Regex Compose Detection 2023-01-16 16:02:56 +01:00
DerLinkman
4c6f8c4f60 [Generate] Refactor compose version detection using regex 2023-01-16 15:54:29 +01:00
FreddleSpl0it
826d32413b Merge branch 'staging' of https://github.com/mailcow/mailcow-dockerized into staging 2023-01-16 15:38:48 +01:00
DerLinkman
b6799d9fcb Feature: Add developer mode option to generate_config.sh 2023-01-16 15:38:42 +01:00
FreddleSpl0it
8782304e8d [Web] show fold/unfold action if child rows exists 2023-01-16 15:38:35 +01:00
DerLinkman
9c55d46bc6 [Nextcloud] Updated and improved script (implemented -u and more) 2023-01-16 14:35:15 +01:00
FreddleSpl0it
099db33e44 [Web] disable datatable default row click listener 2023-01-16 11:41:34 +01:00
DerLinkman
5c57df4669 [Acme] Implemented IP Check Bypass properly 2023-01-16 10:10:20 +01:00
FreddleSpl0it
152431a7d7 [Web] fix Spamfilter flag fwdhosts wrong naming 2023-01-16 09:24:10 +01:00
FreddleSpl0it
36fa5dc633 [Web] fix domain admins cant delete tags 2023-01-16 09:07:28 +01:00
renovate[bot]
814f4aed15 Update thollander/actions-comment-pull-request action to v2.3.1 (#4986)
Signed-off-by: milkmaker <milkmaker@mailcow.de>

Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-14 10:05:55 +01:00
milkmaker
e990856629 [Web] Updated lang.fr-fr.json (#4972)
Co-authored-by: Frederic Ollivier <fredol@me.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Frederic Ollivier <fredol@me.com>
2023-01-09 18:03:41 +01:00
Niklas Meyer
c97afbfa0b Merge pull request #4943 from sivn/staging
[Web] added missing unban action
2023-01-09 12:41:32 +01:00
Niklas Meyer
93b3e0302a Merge pull request #4964 from mailcow/feat/renovate-gosu
Update gosu and allow renovate for updating Dockerfiles
2023-01-09 12:40:57 +01:00
Niklas Meyer
27c87de4ed Merge pull request #4966 from mailcow/fix/bs5
BS5 UI fixes
2023-01-09 12:40:14 +01:00
DerLinkman
028ad4ceb9 changed language string (de) 2023-01-09 10:43:42 +01:00
FreddleSpl0it
e501642b8e [Web] fix mailboxtable sort by quota 2023-01-09 08:04:16 +01:00
Felix Kleinekathöfer
7877215d59 mailcow should be lowercase 2023-01-08 20:02:46 +01:00
Felix Kleinekathöfer
e4347792b8 mailcow should be llow 2023-01-08 20:02:18 +01:00
Felix Kleinekathöfer
50fde60899 Added webhook variables to update script 2023-01-07 16:29:43 +01:00
Felix Kleinekathöfer
38f5e293b0 Webhook variables in config generation 2023-01-07 16:21:11 +01:00
Felix Kleinekathöfer
b6b399a590 Fixed POST to webhook 2023-01-07 16:00:17 +01:00
Felix Kleinekathöfer
b83841d253 Replace placeholders with sed 2023-01-07 15:44:29 +01:00
Felix Kleinekathöfer
3e69304f0f Send webhook 2023-01-06 16:25:18 +01:00
Felix Kleinekathöfer
fe8131f743 Only sent mail if enabled 2023-01-06 15:52:36 +01:00
Felix Kleinekathöfer
9ef14a20d1 Centralized checking of enabled notifications 2023-01-06 15:43:43 +01:00
Felix Kleinekathöfer
5897b97065 Renamed mail notification method for watchdog to be more general 2023-01-06 15:35:06 +01:00
FreddleSpl0it
7966f010a2 [Web] switch table length + filter field positions 2023-01-06 15:03:04 +01:00
FreddleSpl0it
b22f74cb59 [Web] persist table settings + fix quarantine sort 2023-01-06 13:45:52 +01:00
FreddleSpl0it
c928948b15 [Web] use saved password policy for pwgen 2023-01-06 13:18:59 +01:00
FreddleSpl0it
606eaad8f7 [Web] set correct type for routing password input 2023-01-06 12:48:37 +01:00
FreddleSpl0it
c44281f62d [Web] set domain tab default active 2023-01-06 12:43:10 +01:00
FreddleSpl0it
1e98784eee [Web] Opt-In for third party ip_check 2023-01-06 12:09:15 +01:00
FreddleSpl0it
dd9296ffc2 [Web] fix extend_sender_acl issue for domainadmins 2023-01-06 11:07:44 +01:00
FreddleSpl0it
fc0e6b6efb [Web] fix quarantine darkmode style 2023-01-06 09:21:14 +01:00
FreddleSpl0it
68f5fbf65c [Web] remove remote Google fonts from lumen theme 2023-01-06 09:11:51 +01:00
FreddleSpl0it
9727e4084f [Web] load public ip on click and add curl timeout 2023-01-06 08:40:26 +01:00
milkmaker
5c2f48e94c [Web] Updated lang.zh-cn.json (#4965)
Co-authored-by: 雨 <luotianyi@luotianyi.me>

Co-authored-by: 雨 <luotianyi@luotianyi.me>
2023-01-05 17:40:36 +01:00
Peter
cb098df743 Update gosu to 1.16
Change ENV to ARG
Add matchstring line
2023-01-04 19:10:32 +01:00
Peter
b3c54ed07a Add regex for matchstring line in Dockerfiles 2023-01-04 19:09:23 +01:00
Peter
c601eca25d Update thollander/actions-comment-pull-request action to v2.3.0 2023-01-04 18:54:19 +01:00
Patrick Schult
48a13255f3 Merge pull request #4948 from tomudding/fix/sorting-mail-configuration-datatables
Fix sorting of mail configuration DataTables
2023-01-04 13:47:22 +01:00
milkmaker
08f93c7d58 Translations update from Weblate (#4960)
* [Web] Updated lang.zh-cn.json

Co-authored-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: 雨 <luotianyi@luotianyi.me>

* [Web] Updated lang.en-gb.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.de-de.json

Co-authored-by: Peter <magic@kthx.at>

* [Web] Updated lang.it-it.json

Co-authored-by: Stefano <stefano.vassena@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: 雨 <luotianyi@luotianyi.me>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Stefano <stefano.vassena@gmail.com>
2023-01-03 18:12:18 +01:00
Niklas Meyer
e5c9752681 Merge pull request #4956 from mailcow/feat/nextcloud-renovate
Update nextcloud helperscript to use renovate
2023-01-02 14:36:29 +01:00
Peter
afa1ed1eff Add matchstring line for regex
Update nextcloud to 25.0.2
change download URLs
2022-12-31 17:13:38 +01:00
Peter
072cbe62de Enable regex as manager
Add regex for matchstring line
2022-12-31 17:11:16 +01:00
renovate[bot]
9fe8bfadf3 Update actions/stale action to v7 (#4953)
Signed-off-by: milkmaker <milkmaker@mailcow.de>

Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-31 16:49:21 +01:00
renovate[bot]
75e4953070 Update mugi111/tweet-trigger-release action to v1.2 (#4952)
Signed-off-by: milkmaker <milkmaker@mailcow.de>

Signed-off-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-31 16:49:02 +01:00
Tom Udding
de30650dc7 Sort other mailbox DataTables also descending by ID
Also removes the extra non-usable sort option.
2022-12-30 16:38:02 +01:00
Tom Udding
690c34bc1d Sort sync jobs DataTable based on ID
By setting the default column to perform the sort on, the additional
sort option for the first (hidden) column is also removed.
2022-12-30 16:22:52 +01:00
Vincent Simon
4d2e32ee40 [Web] added missing unban action 2022-12-29 18:24:15 +01:00
FreddleSpl0it
02b2988beb [Web] fix typo in SASL table logs 2022-12-27 13:56:09 +01:00
Niklas Meyer
3f1a5af88b Merge pull request #4927 from mailcow/staging
2022-12b
2022-12-27 13:02:44 +01:00
Niklas Meyer
850fd85d4d Merge pull request #4925 from tomudding/fix/datatables-crashing-with-non-english-locale
[WEB] Update DataTables to v1.13.1 and fix crash for non-English locales
2022-12-27 13:01:17 +01:00
milkmaker
24acd42589 Translations update from Weblate (#4926)
* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

[Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: Clément Hampaï <clement.hampai@cypressxt.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Clément Hampaï <clement.hampai@cypressxt.net>
2022-12-26 20:06:49 +01:00
Tom Udding
eaa0dea63b [WEB] Update DataTables to v1.13.1 and fix crash for non-English locales
This newer version of DataTables includes a fix for improper access
to localisation information from `Intl.NumberFormat`. This improper access
lead to datatables not being created.
2022-12-26 17:35:49 +01:00
DerLinkman
dd50bbca9b Merge branch 'staging' 2022-12-26 16:01:31 +01:00
DerLinkman
f3f5471ef7 [Web] Removed double Sender Entry in RSPAMD Logs 2022-12-26 15:56:23 +01:00
Niklas Meyer
516c8ea66c Merge pull request #4923 from mailcow/staging
2022-12a
2022-12-26 14:35:37 +01:00
DerLinkman
48310034e5 [Compose Updater] Corrected syntax errors 2022-12-26 14:33:15 +01:00
Niklas Meyer
be35a88f8c Merge pull request #4916 from tomy0000000/patch-1
[web] 🛠 fix: Locale decision algorithm
2022-12-26 14:15:43 +01:00
Niklas Meyer
e67b512499 Merge pull request #4914 from tomudding/fix/datatables-not-ordering-datetimes-correctly
Fix sorting dates and missing Rspamd attributes in datatables
2022-12-26 14:07:14 +01:00
FreddleSpl0it
0cf59159cd [Web] fix SAL display 2022-12-26 12:03:51 +01:00
FreddleSpl0it
e7a929a947 [Web] add missing </code> tag in edit/mailbox.twig 2022-12-26 11:35:18 +01:00
DerLinkman
dabf4d4383 [UI] Show Restart SOGo only when permission = admin 2022-12-25 14:44:00 +01:00
Tomy Hsieh
13bdd4ad0b 🛠 fix: Locale decision algorithm 2022-12-25 16:56:43 +08:00
DerLinkman
3281b97ea9 [UI] Removed solr informations if container is disabled 2022-12-24 23:25:52 +01:00
DerLinkman
8070db96e9 [UI] Fixed Wrong Table content in Qurantine (sender instead of subject) 2022-12-24 22:25:42 +01:00
Tom Udding
82c80a9682 Make default ordering of Rspamd table consistent 2022-12-24 18:29:46 +01:00
Tom Udding
136cc2e3ff Fix missing score and scan time Rspamd logs 2022-12-24 18:18:28 +01:00
Tom Udding
eefce62f01 Fix incorrect datetime for Rspamd logs 2022-12-24 18:10:57 +01:00
Tom Udding
240b2c63f6 Fix timestamps not sorting in datatables
Timestamps retrieved from the API were always converted to a browser
local format. The format specified for moment.js added in
5160eff294 did not work because of this.

Additionally, the format specified used `dd` which looks for two letter
days, such as "Mo", "Tu", "We", etc. Furthermore, `mm` is used for
minutes, not months.

Because the locale formatted datetime can vary a lot, it is not easy to
get this into moment.js to enable the sorting of datetimes in the
datatables. In other words, there is no conversion from an
`Intl.DateTimeFormat` specifier string to moment.js. Adding many
`$.fn.dataTable.moment(format);` with different `format`s is not useful.

I have fixed this rewriting how the timestamps from the API are added
to the tables. It still uses the locale of the browser, because not
everyone wants to use ISO 8601, but no longer requires moment.js (which
has been removed).

Two data attributes are added to the `td`s of the timestamps:
- `data-order`
- `data-sort`

The values of these are the timestamps as returned by the server, which
are very easily sorted (as they are just UNIX timestamps). Then, when
creating the cell in the table, it will be converted to what the locale
of the browser specified (this has not changed).
2022-12-24 17:35:31 +01:00
Niklas Meyer
355da03fba Merge pull request #4910 from mailcow/staging
2022-12 The Bootstrap 5 Update
2022-12-24 13:49:28 +01:00
milkmaker
55d57c552d Translations update from Weblate (#4909)
* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-24 11:48:08 +01:00
Niklas Meyer
a56e5eb2fe Merge pull request #4906 from mailcow/weblate-translated 2022-12-24 10:38:09 +01:00
milkmaker
e7817fab78 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
714b8417f4 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
ffb68c8848 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
7a5be0ccbf [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
c2927af554 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
24cea0cf22 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
f4351c119f [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
f40b6b5b65 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
bff96eb1ae [Web] Updated lang.sv-se.json
[Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: Filip <filipborglandgren@live.se>
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
de9564c4c9 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
614aa1e49e [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
b368c299d9 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
01a61d4e62 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
174fcd7167 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
dca85f2ffb [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
8ad5acb020 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
287118c3a7 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
78621a1f50 [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:23 +00:00
milkmaker
116859e0ba [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:22 +00:00
milkmaker
c4827e908c [Web] Language file updated by 'Cleanup translation files' addon
Co-authored-by: milkmaker <milkmaker@mailcow.de>
2022-12-23 20:45:22 +00:00
moo
41d56a867a Merge remote-tracking branch 'origin/feature/bootstrap5' into staging 2022-12-23 16:46:00 +01:00
Niklas Meyer
9f4dd1d172 Merge pull request #4905 from mailcow/feature/clamav-1.0
[Clamd] Update to 1.0
2022-12-23 16:30:40 +01:00
moo
948d23f56d [Clamd] Update to 1.0 2022-12-23 16:28:52 +01:00
Niklas Meyer
50e9a3ec8a Merge pull request #4835 from VermiumSifell/master
✏️ Fixed invalid regexs for banning.
2022-12-23 16:10:32 +01:00
Niklas Meyer
0dbd6be010 Merge pull request #4899 from mhupfauer/patch-1
Update bulk_header.map
2022-12-23 16:10:04 +01:00
Niklas Meyer
2b4189b1a4 Merge pull request #4900 from ethrgeist/chore/fix-github-template
fix incorrect render value
2022-12-23 16:08:42 +01:00
Niklas Meyer
4bf81975dc Merge pull request #4888 from mailcow/feature/helper-scripts_nextcloud25
[Nextcloud] Update to 25 + purge fix (DB)
2022-12-23 16:07:28 +01:00
Niklas Meyer
ea040f4412 Merge pull request #4903 from Der-Jan/msgidpushover
Add Message-ID to pushover
2022-12-23 16:07:03 +01:00
Niklas Meyer
c246648949 Merge pull request #4901 from ethrgeist/chore/docker-compose-cleanup
Chore/docker compose cleanup
2022-12-23 16:06:11 +01:00
Niklas Meyer
125aaa5b7d Merge pull request #4904 from mailcow/feature/alpine-3.17
Update Base Images to Alpine 3.17
2022-12-23 16:05:24 +01:00
DerLinkman
aa7888c37d Updated DB Schemata + reverted escape HTML of alert boxes 2022-12-23 14:47:27 +01:00
Der-Jan
f1e1232849 Add Message-ID to pushover 2022-12-21 10:39:14 +01:00
Peter
bb7c7bcff6 Install renovate 2022-12-18 22:40:21 +01:00
knuth
e5cf35aff8 fix unicode char 2022-12-16 14:17:17 +01:00
knuth
65585e286d use GitHub redirect for newest version 2022-12-16 14:16:46 +01:00
knuth
99bcfb8c4b fix incorrect render value 2022-12-16 14:09:39 +01:00
knuth
d98fd74968 use GitHub for newest docker-compose release 2022-12-16 13:58:15 +01:00
knuth
7875185e1f fix unicode char 2022-12-16 13:57:37 +01:00
knuth
a8d50955ee Use built in compose 2022-12-16 13:57:13 +01:00
knuth
bfd5329363 docker comes with compose 2022-12-16 13:57:01 +01:00
FreddleSpl0it
ea1eb48596 show version modal only on master 2022-12-16 09:48:33 +01:00
FreddleSpl0it
f1bb23ba2a fix darkmode toggle 2022-12-16 09:40:20 +01:00
FreddleSpl0it
5160eff294 add datatables date sort plugin & rename js files 2022-12-14 08:13:56 +01:00
mhupfauer
118984dfff Update bulk_header.map
AWeber is a massive Mail as a Service provider which is used by many legitimate corporations and should not be handled negatively by default.
2022-12-13 22:38:45 +01:00
Niklas Meyer
87214fef70 Update tweet-trigger-publish-release.yml 2022-12-13 15:16:47 +01:00
Niklas Meyer
f1f9626b5b Merge pull request #4898 from mailcow/staging
2022-11b
2022-12-13 15:15:46 +01:00
DerLinkman
3a13c93022 [SOGo] Updated to newer SOGo 5.8.0 (CalDav Issue fix) 2022-12-13 12:38:15 +01:00
DerLinkman
83bd66db98 [Update.sh] Increased Timeout for online status check 2022-12-13 11:52:04 +01:00
DerLinkman
13175b4e6c Updated README.md 2022-12-12 16:29:33 +01:00
Niklas Meyer
ecefbf2166 Merge pull request #4894 from mailcow/staging
2022-11a
2022-12-12 16:11:23 +01:00
Niklas Meyer
a763dda068 Update tweet-trigger-publish-release.yml 2022-12-12 16:09:13 +01:00
Niklas Meyer
698b2bf988 Merge pull request #4883 from schwindelbub/master
Update lang.de-de.json
2022-12-12 15:42:12 +01:00
DerLinkman
a71cc759f6 Renamed some Lang Classes + Added some new Strings 2022-12-12 11:58:40 +01:00
Kristian Feldsam
802d304579 Revert "[Dovecot] Disable imapsync job, when auth details are wrong. Fixes #4276 (#4540)" Closes #4711
This reverts commit d4e829465b.

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>

# Conflicts:
#	docker-compose.yml
2022-12-12 11:41:30 +01:00
DerLinkman
faf8da1365 [RSPAMD] Implemented new Password change Script 2022-12-12 10:51:31 +01:00
DerLinkman
ce546e8a90 Merge branch 'feature/bootstrap5' of https://github.com/mailcow/mailcow-dockerized into feature/bootstrap5 2022-12-12 10:49:02 +01:00
DerLinkman
f4731eecdb Cleanup + Language Fixes 2022-12-12 10:49:00 +01:00
FreddleSpl0it
6704377402 [Web] escape more html data 2022-12-09 16:10:10 +01:00
DerLinkman
827cb00837 [DockerAPI] Tagged as 2.0 (rewrite) 2022-12-08 16:09:20 +01:00
DerLinkman
299a342a62 [Nextcloud] Update to 25 + purge fix (DB) 2022-12-08 15:57:24 +01:00
Schwindelhub
8614d63ace Update lang.de-de.json
Corrected "Leerzeichen in Komposita".
2022-12-03 21:21:00 +01:00
DerLinkman
77f04d10c7 Update Base Images to Alpine 3.17 2022-12-01 23:02:03 +01:00
Niklas Meyer
6d8c978d17 Merge pull request #4882 from mailcow/staging
2022-11 Update
2022-12-01 21:22:41 +01:00
DerLinkman
d55994b66a Merge branch 'staging' into nightly 2022-12-01 21:06:19 +01:00
Niklas Meyer
ff4f2ae0b6 Merge pull request #4859 from mitch-geht-ab/updatesh-proxy-caplty
switch update.sh/check_online_status() from ping to curl to make it proxy compatible
2022-11-30 17:39:21 +01:00
DerLinkman
0b00f15811 Added additional Check for Docker Hub 2022-11-30 17:37:33 +01:00
Niklas Meyer
bed5218550 Merge pull request #4877 from mailcow/feature/sogo-5.8.0
Update SOGo to 5.8.0 nightly
2022-11-30 17:20:21 +01:00
DerLinkman
86b67a9a7b Updated mailcow/sogo to 1.112 2022-11-30 17:13:39 +01:00
FreddleSpl0it
73370de1f9 Update SOGo to 5.8.0 nightly 2022-11-30 11:08:38 +01:00
milkmaker
524aba0964 [Web] Updated lang.sk-sk.json (#4873)
Co-authored-by: Lukáš Matula <lukas@gbely.net>

Co-authored-by: Lukáš Matula <lukas@gbely.net>
2022-11-25 19:52:37 +01:00
Patrick Schult
64528d8e0e Merge pull request #4845 from mailcow/feature/rspamd-3.4
[Rspamd] Update to 3.4 (fix of 3.3 Bug)
2022-11-24 11:45:29 +01:00
Patrick Schult
31b5faa729 Merge pull request #4868 from mailcow/feat/build-backup-image
Add new action Build mailcow backup image
2022-11-24 11:30:24 +01:00
Patrick Schult
17977a2fff Merge pull request #4864 from bluewalk/pushover-improvements
Pushover improvements
2022-11-24 11:28:28 +01:00
Patrick Schult
3e007eeaae Merge pull request #4860 from yhdsl/master
Update Simplified Chinese Translation
2022-11-24 11:26:46 +01:00
Niklas Meyer
a96b209e1b Merge pull request #4870 from mailcow/staging
Automatic PR to nightly from 2022-11-23T12:47:06Z
2022-11-23 15:35:09 +01:00
Niklas Meyer
05b897f43e Merge pull request #4848 from nathanielmom/compose-fix
change 'return 1' to 'exit 1'
2022-11-23 15:29:38 +01:00
Niklas Meyer
738dcac60d Merge pull request #4855 from BigMichi1/polish_phpfpm_dockerfile
[PHP] Polish phpfpm dockerfile
2022-11-23 15:18:23 +01:00
Niklas Meyer
b3bbeee5e2 Merge pull request #4844 from mailcow/feature/php-8.1
[PHP] Update to 8.1
2022-11-23 15:17:55 +01:00
Niklas Meyer
782eae4d4c Merge pull request #4869 from benpro/patch-1
Fixy comment typo
2022-11-23 15:16:48 +01:00
Benoît S
f2f5e212f5 Fixy comment typo 2022-11-23 22:10:57 +09:00
Peter
ff7102468e [Helper] Backup and restore: Use latest tag for image 2022-11-22 18:38:38 +01:00
Peter
118cb1017a Add new action Build mailcow backup image 2022-11-22 18:37:15 +01:00
bluewalk
360bb6f306 Split name and address for TO-variables 2022-11-20 10:42:44 +01:00
bluewalk
d8e314db1a Fixed issue with subdomain senders + added TO variable and allow new lines in text using \n 2022-11-19 15:32:48 +01:00
bluewalk
fd14c51f85 Removed regex as we have the address from the header 2022-11-18 17:29:31 +01:00
bluewalk
57a5a9baeb Updated DB version and make sure default sound is "pushover" when null 2022-11-17 21:14:44 +01:00
bluewalk
65c74c75c7 Added SENDER_ADDRESS and SENDER_NAME as variables for messages 2022-11-17 21:01:18 +01:00
bluewalk
e82f3b3975 Added SENDER_ADDRESS and SENDER_NAME as variables for messages 2022-11-17 21:01:18 +01:00
Niklas Meyer
d7323213b8 Merge pull request #4865 from mailcow/staging
Automatic PR to nightly from 2022-11-17T17:56:06Z
2022-11-17 20:55:57 +01:00
DerLinkman
fbc33da734 Merge branch 'master' into staging 2022-11-17 20:54:46 +01:00
DerLinkman
210815d4cf Merge branch 'master' into staging 2022-11-17 20:54:13 +01:00
Niklas Meyer
1e672ae349 Update FUNDING.yml 2022-11-17 20:49:13 +01:00
DerLinkman
19fabd0e64 Merge branch 'feature/bootstrap5' into nightly 2022-11-17 11:12:55 +01:00
FreddleSpl0it
ef392ef6ba add demo_mode for mailcow ui 2022-11-17 08:36:03 +01:00
DerLinkman
046e658984 Use @MAGICCC Version of action 2022-11-16 18:42:20 +01:00
DerLinkman
a46db9e0df Fixed typo in tweet action 2022-11-16 18:39:37 +01:00
DerLinkman
17f3cc3ad8 Optimized/Fixed Tweet action 2022-11-16 18:34:22 +01:00
DerLinkman
3236a10cf5 Updated tweet action (again) 2022-11-16 18:19:12 +01:00
DerLinkman
a4eb6d5f1b Update Release Tweet action 2022-11-16 18:15:45 +01:00
DerLinkman
a09661fc83 Merge branch 'feature/bootstrap5' into nightly 2022-11-16 18:00:32 +01:00
FreddleSpl0it
f52ab69a5b change default template creation 2022-11-16 15:29:39 +01:00
Niklas Meyer
9d1b620dcf Merge pull request #4861 from mailcow/staging 2022-11-16 13:30:10 +01:00
FreddleSpl0it
3ebd801b3d remove whats new modal & add changelog modal 2022-11-16 12:12:23 +01:00
Peter
05181f1888 Update issue template 2022-11-15 19:44:07 +01:00
Peter
6875baf64c Update issue template 2022-11-15 19:43:03 +01:00
FreddleSpl0it
0cdb1e638d change git_project_url var for base.twig 2022-11-15 16:25:05 +01:00
FreddleSpl0it
da415e5c6b [Dockerapi] define matched var before use 2022-11-15 16:12:07 +01:00
Peter
c46a1c1e2f [GH-Actions][actionpr] Update to v0.5.3 2022-11-14 22:51:19 +01:00
Link Steve
b79a1530fb Update Simplified Chinese Translation 2022-11-14 21:18:37 +08:00
thomas
a6a7ab45f8 switch update.sh/check_online_status() from ping to curl to make it proxy ready 2022-11-13 07:34:18 +01:00
FreddleSpl0it
c8f69ffe77 show created_on, last_modified for domain, mailbox 2022-11-11 09:22:58 +01:00
FreddleSpl0it
79982e0e8d add template feature for domains and mailboxes 2022-11-10 16:22:18 +01:00
Michael Cramer
bc937ed2db [PHP] Polish dockerfile
includes also #4839 because of --with-avif for gd configure command (is not available in 8.0)

contains the following adjustments:
- upgrade APCu to 5.1.22
- use PECL package for mailparse instead of git clone (3.1.4 is the latest one available and sice then no changes on master branch)
- split PECL commands into separate ones (according to https://hub.docker.com/_/php this is the recommended way)
- add missing configure options for gd extension to include webp, xpm and avif
- specify composer version to be installed
- cleanup more dev dependencies
2022-11-08 09:45:25 +01:00
Niklas Meyer
8ca028eb2e Merge pull request #4847 from mailcow/staging
Automatic PR to nightly from 2022-11-06T20:27:08Z
2022-11-07 14:12:55 +01:00
Nathaniel Mom
df17e6b75e change 'return 1' to 'exit 1' 2022-11-07 09:27:22 +10:00
Niklas Meyer
f880e1834d Merge pull request #4846 from jorisdrenth/staging
Add undocumented /api/v1/get/mailbox/all/domain.tld endpoint to docs
2022-11-06 22:02:03 +01:00
DerLinkman
4dd1b97e38 [PHP] Update to 8.1 2022-11-06 15:52:30 +01:00
Niklas Meyer
074e3fcd6e Merge pull request #4843 from mailcow/staging
Automatic PR to nightly from 2022-11-06T14:21:03Z
2022-11-06 15:38:01 +01:00
Joris Drenth
aeb433cc39 Add undocumented /api/v1/get/mailbox/all/domain.tld endpoint to documentation 2022-11-06 00:25:38 +01:00
Niklas Meyer
eb9d360c0a Merge pull request #4837 from mailcow/feat/action-check_prs_if_on_staging
Add new action Check PRs if on staging
2022-11-04 16:02:30 +01:00
Peter
abfad4e025 Add new action Check PRs if on staging 2022-11-03 19:58:06 +01:00
FreddleSpl0it
3f40fada1b edit page for default domain and mailbox settings 2022-11-03 07:25:18 +01:00
Vermium Sifell
a9871d05b2 ✏️ Fixed invalid regexs for banning 2022-11-02 23:42:37 +01:00
FreddleSpl0it
39e46d2e0b querySelector fails when id starts with digits 2022-11-02 14:09:45 +01:00
DerLinkman
e9091cbb8c [Rspamd] Update to 3.4 (fix of 3.3 Bug) 2022-11-02 10:32:56 +01:00
Niklas Meyer
cb340d78e1 Merge pull request #4827 from mailcow/staging
2022-10a
2022-10-26 13:06:09 +02:00
Niklas Meyer
996b2db514 Merge pull request #4826 from mailcow/staging
Automatic PR to nightly from 2022-10-26T07:46:18Z
2022-10-26 12:57:17 +02:00
Niklas Meyer
548d7b9833 Merge pull request #4825 from mailcow/fix/qitems
Fix Error parsing Quarantine Items
2022-10-26 12:55:10 +02:00
Niklas Meyer
96dbbf4db6 Merge pull request #4823 from mailcow/feature/rspamd-downgrade
[RSPAMD] Downgrade to 3.2 (stable)
2022-10-26 12:44:36 +02:00
DerLinkman
4f14462af7 [RSPAMD] Downgrade to 3.2 (stable) 2022-10-26 12:33:52 +02:00
FreddleSpl0it
1e08b4ece6 fix encoding failures of parsed text_plain mail 2022-10-26 12:33:22 +02:00
Niklas Meyer
177ebe26de Merge pull request #4822 from mailcow/staging
Automatic PR to nightly from 2022-10-26T07:46:18Z
2022-10-26 11:15:51 +02:00
Niklas Meyer
6fd9efc30a Merge pull request #4769 from ro78/patch-1
Update base.twig to escape simple quote
2022-10-26 11:14:37 +02:00
Niklas Meyer
da72184fda Merge pull request #4821 from mailcow/staging
Automatic PR to nightly from 2022-10-26T07:46:18Z
2022-10-26 11:05:58 +02:00
Niklas Meyer
6f212a41d8 Merge pull request #4820 from mailcow/feature/netfilter-compose
[Compose] Use new (patched) Netfilter Image
2022-10-26 11:04:36 +02:00
DerLinkman
52314d1a35 [Compose] Use new (patched) Netfilter Image 2022-10-26 11:03:02 +02:00
Niklas Meyer
3028a18a37 Merge pull request #4819 from mailcow/staging
2022-10
2022-10-25 14:16:05 +02:00
DerLinkman
a2b31cb28d Merge branch 'staging' into nightly 2022-10-25 12:25:34 +02:00
Niklas Meyer
26a5fcf989 Merge pull request #4815 from ethrgeist:bump-redis-7
[redis] Bump Redis to version 7
2022-10-25 12:20:30 +02:00
Niklas Meyer
509086ef54 Merge pull request #4816 from mailcow/feature/rspamd-3.3
[RSPAMD] Update to 3.3
2022-10-25 11:42:34 +02:00
Niklas Meyer
963510ed22 Merge pull request #4806 from mailcow/feature/pigz-backup
[Backup] Swapped PIGZ instead of gzip (allow Threading)
2022-10-25 11:05:40 +02:00
DerLinkman
2c0f8cda50 [RSPAMD] Update to 3.3 2022-10-25 10:35:23 +02:00
DerLinkman
50d2671d75 Fixed leading / warning removal 2022-10-25 10:06:53 +02:00
DerLinkman
b73d879f3c Removed thread prompt again. Added notice message 2022-10-25 09:55:29 +02:00
Knuth
725a5fe5b9 Bump Redis to version 7 2022-10-25 09:47:03 +02:00
DerLinkman
65ca42ca42 Restored Thread Prompt due to implementation in restore 2022-10-24 15:10:15 +02:00
DerLinkman
b22ff59f7b Added PIGZ for Restoring as well. 2022-10-24 12:28:41 +02:00
DerLinkman
58527857d9 Removed debug message 2022-10-21 11:54:23 +02:00
DerLinkman
6306c4555c Removed Thread Prompt and set default value to 1 Thread 2022-10-21 11:48:29 +02:00
Peter
922603f906 Rename turkish language file for #4657 2022-10-20 17:57:13 +02:00
Niklas Meyer
f8d45de749 Merge pull request #4657 from tomy0000000:master
🌐 Add Traditional Chinese Translation
2022-10-20 11:27:58 +02:00
DerLinkman
b6760e19b7 Merge branch 'feature/bootstrap5' into nightly 2022-10-20 11:12:17 +02:00
Niklas Meyer
6ce25f38e1 Merge pull request #4808 from mailcow/feature/language-change
Backport Language Changer (+ Chinese Translation) to BS5
2022-10-20 11:10:12 +02:00
DerLinkman
5cb7f726bc Fixed changes due to BS5 Classes 2022-10-20 11:07:56 +02:00
DerLinkman
a334f33b35 Merge PR 4657 into language-change 2022-10-20 10:58:51 +02:00
DerLinkman
cb1602c2de Fix English Flag rendering 2022-10-19 16:09:22 +02:00
DerLinkman
b503271aba Use Translateable strings in Debug Page 2022-10-19 15:57:57 +02:00
DerLinkman
008e5651f8 Merge branch 'feature/bootstrap5' into nightly 2022-10-19 11:36:25 +02:00
DerLinkman
5e3aab12a7 Restored original Container length + Corrected Image size on Debug Page 2022-10-19 11:36:07 +02:00
DerLinkman
8026b6c874 Swapped PIGZ instead of gzip 2022-10-19 11:15:12 +02:00
DerLinkman
51b80f6fa1 Merge branch 'feature/bootstrap5' into nightly 2022-10-18 14:20:55 +02:00
DerLinkman
75fdeb2843 Fixed queue message error 2022-10-18 14:19:51 +02:00
DerLinkman
2b1d927de4 Merge branch 'feature/bootstrap5' into nightly 2022-10-18 11:36:28 +02:00
DerLinkman
e5d788497a Rearranged Queue Manager + Ukraine Flag fix 2022-10-18 11:34:48 +02:00
Niklas Meyer
b173e2ef86 Merge pull request #4795 from mailcow/staging 2022-10-12 18:34:11 +02:00
Peter
042676fff7 [GH-Actions][actionpr] Update to v0.5.1 2022-10-12 18:27:30 +02:00
Peter
44d53146af [GH-Actions][stale] Update to v6.0.1 2022-10-12 18:26:39 +02:00
moo
3d48c2427a Merge branch 'feature/bootstrap5' into nightly 2022-10-12 15:38:11 +02:00
FreddleSpl0it
a9046d8f35 remove max-height from debug logo 2022-10-12 15:37:03 +02:00
moo
b4a1b81aec Merge branch 'feature/bootstrap5' into nightly 2022-10-12 15:12:58 +02:00
FreddleSpl0it
90eb0ea27a make transportstable responsive 2022-10-12 09:28:03 +02:00
FreddleSpl0it
4f01b9fd25 use ui_texts.title_name for host_stats card-header 2022-10-12 09:20:57 +02:00
FreddleSpl0it
174b5c8f7f add goto previous page btn to top 2022-10-11 19:20:49 +02:00
FreddleSpl0it
3912fcb238 shift get_public_ips to json_api.php 2022-10-11 17:40:46 +02:00
FreddleSpl0it
ef70457a48 shift datatable css to new file 2022-10-11 11:48:46 +02:00
FreddleSpl0it
8c4dbaec4f rework datatables 2022-10-11 11:41:06 +02:00
FreddleSpl0it
645e8f426c shift datatable child toggle function to api.js 2022-10-11 11:35:07 +02:00
Niklas Meyer
bae1d1c047 Merge pull request #4790 from mailcow/staging
Automatic PR to nightly from 2022-10-09T11:34:14Z
2022-10-09 17:27:53 +02:00
Niklas Meyer
ce4fb069d5 Merge pull request #4789 from mailcow/feat/prtonightlyaction
Update PR to nightly template
2022-10-09 17:26:17 +02:00
Peter
9444000d46 Use milkmaker as PR author
Use template to be able to use get_diff var
2022-10-09 17:02:28 +02:00
Peter
eacd9ac240 Add pr_to_nighty_template.yml 2022-10-09 17:01:21 +02:00
Tomy Hsieh
cf38d6ca69 🛠 fix: Improve language preference algo 2022-10-06 23:22:54 +08:00
Tomy Hsieh
905993d66e 🛠 fix: Language detection 2022-10-06 22:21:12 +08:00
DerLinkman
b8656763ec Merge branch 'staging' into nightly 2022-10-06 14:25:39 +02:00
DerLinkman
0d7fe2e347 Some corrections to pr action 2022-10-06 14:14:07 +02:00
DerLinkman
33bd871a63 Corrected some PR Action Code 2022-10-06 14:06:18 +02:00
DerLinkman
772122b255 Added auto PR for nightly builds 2022-10-06 14:04:27 +02:00
Niklas Meyer
9fb346751c Merge pull request #4724 from mnin/master
[Netfilter] Fix creating endless SNAT rules for ipv4
2022-10-06 12:18:23 +02:00
FreddleSpl0it
10e560c5b2 fix set rspamd worker password 2022-10-01 15:56:45 +02:00
Niklas Meyer
cb058e91a3 Merge pull request #4772 from mailcow/staging
Update Twig to 3.4.3
2022-09-30 12:25:05 +02:00
DerLinkman
ba9f2bc376 Update Twig to 3.4.3 2022-09-30 12:21:31 +02:00
FreddleSpl0it
fb7e234120 move guid to debug.php 2022-09-30 11:38:43 +02:00
FreddleSpl0it
27e7407407 Update Twig to 3.4.3 2022-09-30 11:03:05 +02:00
Romain
623397d20a Update base.twig to escape simple quote
Update base.twig to escape simple quote
See issue https://github.com/mailcow/mailcow-dockerized/issues/4718
2022-09-30 10:32:15 +02:00
Tomy Hsieh
7d46de33d8 Merge from upstream branch 'staging'
# Conflicts:
#	data/web/inc/vars.inc.php
2022-09-30 16:03:49 +08:00
DerLinkman
8c80cecdfb Merge remote-tracking branch 'origin/staging' into nightly 2022-09-27 21:41:21 +02:00
Niklas Meyer
5470b51cc7 Merge pull request #4766 from mailcow/staging
2022-09
2022-09-27 15:53:31 +02:00
Niklas Meyer
8e0b1d8aee Merge pull request #4703 from devops-ansible/master
Improve send-as behaviour
2022-09-27 15:39:53 +02:00
FreddleSpl0it
e53f431273 Merge remote-tracking branch 'origin/feature/bootstrap5' into nightly 2022-09-27 14:43:20 +02:00
FreddleSpl0it
8e0ee67108 add sieve access toggle to mass-actions-mailbox 2022-09-27 12:32:14 +02:00
FreddleSpl0it
3d82d9af1b add loading animation for container charts 2022-09-27 12:31:02 +02:00
FreddleSpl0it
8a0bd23985 fix some layout issues 2022-09-27 12:30:10 +02:00
Niklas Meyer
2834459b22 Merge pull request #4763 from ntimo/task/update-swagger
[API] Update swagger version
2022-09-27 11:16:44 +02:00
ntimo
000894dabd [API] Update swagger version 2022-09-26 19:33:31 +00:00
milkmaker
494620cdea [Web] Updated lang.tr.json (#4765)
Co-authored-by: Burak Buylu <burak@burtinet.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Burak Buylu <burak@burtinet.com>
2022-09-26 19:05:54 +02:00
Niklas Meyer
a502eb239d Merge pull request #4758 from mailcow/feature/fix-4743 2022-09-26 18:41:40 +02:00
Niklas Meyer
caf775093e Merge pull request #4762 from mindsolve/patch-1 2022-09-26 18:40:19 +02:00
FreddleSpl0it
4387e4764f display public ips on debug page 2022-09-26 12:19:51 +02:00
FreddleSpl0it
3b8e17c21f fix layout issues 2022-09-26 11:23:04 +02:00
Alex
f28e18e676 GitHub Workflows security hardening (#4761)
* build: harden integration_tests.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden image_builds.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

Signed-off-by: Alex <aleksandrosansan@gmail.com>
Co-authored-by: Niklas Meyer <62480600+DerLinkman@users.noreply.github.com>
2022-09-25 14:42:01 +02:00
Felix E
b4bab1d5b9 Fixed typo in escape sequence in update script 2022-09-25 00:47:09 +02:00
Peter
c4d5072e5c [GH-Actions][stale] Update to v6.0.0 2022-09-22 19:48:19 +02:00
Peter
852bf750ca Use utf8mb4 charset and utf8mb4_general_ci collation 2022-09-19 19:29:55 +02:00
Peter
47359c4113 [GH-Actions][stale] Update to v5.2.0 2022-09-16 22:00:22 +02:00
Niklas Meyer
15f2c4c769 Merge pull request #4749 from mailcow/staging
2022-08b
2022-09-08 13:02:49 +02:00
DerLinkman
e74af0db89 Merge branch 'staging' into nightly 2022-09-08 12:35:51 +02:00
Niklas Meyer
a0174c61e8 Merge pull request #4747 from mailcow/fix/sogo
Fix for SOGo in 2022-08
2022-09-08 12:34:26 +02:00
Niklas Meyer
5b30dce609 Merge pull request #4741 from maljes/master
Modified branch switch in generate_config.sh
2022-09-08 12:31:44 +02:00
FreddleSpl0it
8f6099e3e4 add &amp; to smtp url 2022-09-08 11:02:52 +02:00
FreddleSpl0it
7c44375223 increase dovecot and sogo image version 2022-09-08 10:35:03 +02:00
FreddleSpl0it
72e204f8fd fix sogo bugs after 2022-08 update 2022-09-08 10:32:07 +02:00
Malte Jesgarzewsky
b5f5b53e37 Update generate_config.sh
Fixed bug in loop by replacing the variable.
2022-09-05 09:41:19 +02:00
Malte Jesgarzewsky
1c15133a52 Modified branch switch in generate_config.sh
Added possibility to define the mailcow branch by an environment variable to be able to bypass input.
2022-09-02 19:22:48 +02:00
Niklas Meyer
7c9c2c35f8 Merge pull request #4739 from mailcow/staging
2022-08a
2022-09-02 10:29:14 +02:00
DerLinkman
5ff62d8f22 Merge branch 'staging' into nightly 2022-09-02 10:25:28 +02:00
DerLinkman
9806e568c0 Readded Sieve Location for Dovecot 2022-09-02 10:24:49 +02:00
DerLinkman
b4bb4e2938 Improved compose version check (detect versions with v in front) 2022-09-02 10:05:11 +02:00
DerLinkman
4427173a6c Revert "Before update on 2022-09-01_20_20_45"
This reverts commit db66fe33fa.
2022-09-02 09:57:17 +02:00
DerLinkman
db66fe33fa Before update on 2022-09-01_20_20_45 2022-09-01 20:21:39 +02:00
Niklas Meyer
de7b809229 Merge pull request #4733 from mailcow/staging
Amoogus Update 2022 - Nightly Switch
2022-09-01 14:59:34 +02:00
DerLinkman
cf5fa96a93 Merge branch 'staging' into nightly 2022-09-01 13:57:39 +02:00
FreddleSpl0it
a40df1ff87 fix tfa modal trigger from dav/eas login 2022-09-01 09:53:08 +02:00
FreddleSpl0it
a161aa2c92 remove testing debug log 2022-08-31 11:37:45 +02:00
FreddleSpl0it
cad0f25345 Merge branch 'staging' of https://github.com/mailcow/mailcow-dockerized into staging 2022-08-31 11:31:59 +02:00
FreddleSpl0it
2ed453a400 fix mailbox tfa 2022-08-31 11:31:55 +02:00
DerLinkman
452d8a686f Merge branch 'master' into staging 2022-08-31 10:40:35 +02:00
DerLinkman
9e76b6ee70 Merge branch 'master' into nightly 2022-08-31 10:39:27 +02:00
FreddleSpl0it
45e97b3753 [BS5] fix merging bugs 2022-08-30 15:59:16 +02:00
DerLinkman
ecc16c69e6 Merge branch 'nightly' into feature/bootstrap5 2022-08-29 14:37:25 +02:00
Niklas Meyer
90f77f6d5c Merge pull request #4719 from mailcow/sogo-5.7.1
Update SOGo to 5.7.1
2022-08-29 11:57:18 +02:00
milkmaker
0c11cf747a Translations update from Weblate (#4722)
* [Web] Updated lang.cs.json [CI SKIP]

Co-authored-by: Vojtěch Kaizr <wojtishek@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr.json [CI SKIP]

Co-authored-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: ppelleti2 <pierre@ppelleti.fr>

* [Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Updated lang.tr.json [CI SKIP]

[Web] Added lang.tr.json [CI SKIP]

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>
Co-authored-by: therudeboy <abdullahozcelikisreklam@gmail.com>

* [Web] Updated lang.ro.json [CI SKIP]

Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.it.json [CI SKIP]

Co-authored-by: Peter <magic@kthx.at>

* [Web] Turkish translation

* [Web] Turkish translation

Co-authored-by: Vojtěch Kaizr <wojtishek@gmail.com>
Co-authored-by: ppelleti2 <pierre@ppelleti.fr>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: therudeboy <abdullahozcelikisreklam@gmail.com>
Co-authored-by: Vlad M <vlad+mailcow@manoila.co.uk>
2022-08-25 18:15:27 +02:00
Patrick Schult
6d36475ed3 Merge pull request #4725 from mailcow/feature/nightly-switch
[Update.sh] Nightly Version Switch implementation + Composev2 User Decision
2022-08-25 14:58:16 +02:00
DerLinkman
fee6ff43bf Corrected compose standalone update message in generate config 2022-08-25 14:51:49 +02:00
DerLinkman
57cd5ec818 Readded update.sh new Version check :P 2022-08-25 14:48:38 +02:00
Patrick Schult
02512e0f4f Merge pull request #4685 from FreddleSpl0it/tfa-patch
Update TFA flow
2022-08-25 14:38:37 +02:00
FreddleSpl0it
555f4a8a6d [Web] Mailbox TFA fix 2022-08-25 14:26:45 +02:00
DerLinkman
3633766544 Fixed missing branch variable in app info.php (gen-config) 2022-08-25 11:21:12 +02:00
DerLinkman
e98a984417 Implemented correct app_info.php set in generate_config 2022-08-25 11:16:55 +02:00
DerLinkman
bc9141753f Re-arranged position of source mailcow.conf 2022-08-25 10:32:33 +02:00
DerLinkman
1f9f4157a6 Corrected detect docker compose command position 2022-08-25 10:27:46 +02:00
DerLinkman
778a3ed551 Use universal Git Commit Date Command 2022-08-25 10:07:42 +02:00
DerLinkman
5ea4305185 Fix Upstream Commit ID grep 2022-08-24 16:26:07 +02:00
DerLinkman
ef311f22bf Corrected Twig Footer 2022-08-24 16:16:38 +02:00
DerLinkman
e202530afb Set correct Commit ID from origin instead of local 2022-08-24 16:12:36 +02:00
DerLinkman
85deeaf806 Corrected origin fetch 2022-08-24 16:00:57 +02:00
DerLinkman
825c8a6abe Changed Git Checkout form 2022-08-24 15:56:02 +02:00
DerLinkman
cdc8f63b4b Fixed Force flag 2022-08-24 15:05:14 +02:00
DerLinkman
9db9818ede Moved Force Mode check in prio 2022-08-24 15:00:39 +02:00
DerLinkman
4f7ee669d3 Added missing ;then in update.sh 2022-08-24 14:42:31 +02:00
DerLinkman
77f9947613 Readded footer + vars. 2022-08-24 14:37:00 +02:00
DerLinkman
a8eb3b6ac5 Added nightly footer 2022-08-24 14:31:32 +02:00
DerLinkman
575eab1cf0 Implemented Check if IPv6 is disabled 2022-08-24 12:26:14 +02:00
DerLinkman
7a23e4fd4e Fix for Sieve error (due to IPv6 Comp from SOGo) 2022-08-24 12:12:41 +02:00
FreddleSpl0it
77e6124b00 [BS5] move showWhatsNewModal 2022-08-23 14:24:10 +02:00
DerLinkman
b16b276f36 Implement nightly/stable switch in update.sh 2022-08-23 14:04:40 +02:00
FreddleSpl0it
a3ddb58566 [BS5]responsive fixes 2022-08-23 12:43:23 +02:00
FreddleSpl0it
be7252f620 [BS5] update async dockerapi 2022-08-23 11:57:05 +02:00
DerLinkman
4f380debb5 Added branch switch in generate_config.sh 2022-08-23 11:38:06 +02:00
Martin Wilhelmi
f34d3620b1 Remove trailing whitespaces 2022-08-22 22:16:01 +02:00
Martin Wilhelmi
70e99447f9 Fix adding same SNAT rule endless to the ipv4 POSTROUTING chain 2022-08-22 22:15:56 +02:00
FreddleSpl0it
db8af3d1e0 [BS5] use fastapi and aiodocker for dockerapi 2022-08-22 16:14:04 +02:00
FreddleSpl0it
7f70b0f703 [BS5] add container disk and network stats 2022-08-22 16:08:01 +02:00
FreddleSpl0it
2e10cc8e79 [BS5] fix RsettingsModal 2022-08-22 16:02:35 +02:00
FreddleSpl0it
047d9143c0 showWhatsNew modal remove default show class 2022-08-22 16:01:57 +02:00
DerLinkman
047c4aa3a0 Added seperate update_compose Script + some Improvements 2022-08-22 15:44:01 +02:00
DerLinkman
925b220905 Compose Version detection implemented in Backup script 2022-08-22 10:24:38 +02:00
DerLinkman
6708059227 Moved compose check to top.
Improved variable check.
2022-08-19 15:55:24 +02:00
DerLinkman
1f3d9d4e1c Implemented user choice compose in cold-standby 2022-08-19 15:17:19 +02:00
Peter
0dcfac8f15 Update SOGo to 5.7.1 2022-08-18 19:06:54 +02:00
andryyy
ad8b7f0894 [Dovecot] Fixes broken sieve compiler in some rare cases when using replication 2022-08-18 15:08:00 +02:00
DerLinkman
55f810b23f Implemented new compose check in update.sh 2022-08-17 16:00:58 +02:00
DerLinkman
65eddee63e New variable for mailcow.conf in generate_config.sh 2022-08-17 14:39:12 +02:00
FreddleSpl0it
a7a0eef125 [BS5] poll host stats if tab is active 2022-08-11 16:11:13 +02:00
FreddleSpl0it
5d35af9d69 [BS5] rework network and disk io 2022-08-10 16:16:36 +02:00
FreddleSpl0it
ea21bca7df [BS5] adjust host stats 2022-08-10 10:56:10 +02:00
FreddleSpl0it
a3c0737ba8 [BS5] add host statistics 2022-08-09 20:29:33 +02:00
Tomy Hsieh
7b57b3392c switch to IETF language tag 2022-08-09 15:44:09 +08:00
Tomy Hsieh
492451bfee Tailor translation
`quarantine`, `success`
2022-08-09 15:10:44 +08:00
FreddleSpl0it
9747995510 [BS5] redirect to /debug after login 2022-08-08 13:24:29 +02:00
FreddleSpl0it
ad9112010f [BS5] center container restart button text 2022-08-08 13:23:57 +02:00
FreddleSpl0it
a4ec2d1d86 [BS5] adjust whats new modal 2022-08-08 12:53:52 +02:00
FreddleSpl0it
b7f07951f6 [BS5] fix mobile navbar flex-direction 2022-08-08 12:53:25 +02:00
FreddleSpl0it
0e3363e61c [BS5] add additional info to app_info.inc.php 2022-08-08 12:52:42 +02:00
Niklas Meyer
4322c98f73 [UI] Moved PWChange Button for users back to original place 2022-08-05 14:12:25 +02:00
macwinnie
edcf789126 Update postfix version by +.1
Update Version of Docker-Image according to [related comment](https://github.com/mailcow/mailcow-dockerized/pull/4703#issuecomment-1205277142)
2022-08-05 00:37:58 +02:00
macwinnie
b985ba4f0e Improve send-as behaviour
Receiving mails for wildcard alias addresses is really easy – but
sending mails from those any-aliases was not possible at all unless
every sender address was added as an explicit alias to the database.

By this change in the database query for allowed sender addresses, the
first finding `not NULL` (see [`SELECT COALESCE`](https://www.w3schools.com/sql/func_sqlserver_coalesce.asp) for how it works)
– either an exact alias `mailbox@domain.tld` or the wildcard alias `@domain.tld`
will be allowed to send mails as the given address ... without the need
of explicit definition within the database.
2022-08-04 01:37:26 +02:00
Peter
67c0405274 [GH-Actions][stale] Update to v5.1.1 2022-08-02 19:06:04 +02:00
Peter
9b32151ab5 [GH-Actions][stale] Update to v5.1.1 2022-08-02 19:04:05 +02:00
Tomy Hsieh
a1e8077f45 Tailor translation
`user`
2022-08-02 18:53:58 +08:00
Tomy Hsieh
956e4e2aa7 Tailor translation
`mailbox`
2022-08-01 08:20:02 +08:00
Niklas Meyer
b51a659515 Merge pull request #4698 from mailcow/staging
2022-07a
2022-07-29 14:23:53 +02:00
Niklas Meyer
44a6f09a09 [CLAMAV] Update to 0.105.1 2022-07-29 14:08:26 +02:00
Erisa A
4c10525078 [Web] Update keyHandle max length to 1023 (#4696)
https://w3c.github.io/webauthn/#credential-id

Co-authored-by: Niklas Meyer <62480600+DerLinkman@users.noreply.github.com>
2022-07-26 09:16:23 +02:00
Peter
c9ab8b2eff [GH-Actions][stale] Upgrade to v5.1.0 and add close-issue-reason 2022-07-19 21:43:24 +02:00
Peter
4bf38bf00f Mailcow -> mailcow (#4687) 2022-07-19 20:31:25 +02:00
Peter
7c7c67948e Use yaml list style in docker build workflow (#4688)
* Use yaml list style

* Mailcow -> mailcow
2022-07-19 20:24:24 +02:00
l-with
263cb96786 Improve domain api schema (#4689)
* change response of add domain to array

* add tags to request body of add domain

* add gal to request body of add domain

* add relay_unknown_only to request body of add domain

* add relay_unknown_only to request body of edit domain

* add rl_frame, rl_value to request body of edit domain

* fix indentation

* add tags to request body of edit domain

* change response of edit domain to array

* Revert "change response of edit domain to array"

This reverts commit 692384e21b.

* change response type of edit domain to application/json

* change response type of edit domain

* change items in body of edit domain to array of strings

* change response of edit domain to array

* fix indentation

* revert changing response type of edit domain-admin

* change response type of edit domain to array

* fix response type of edit domains

* change msg in response of edit domains to array

* change items in body of delete domain to array of strings

* change request body of delete domain to array of strings

* fix

* remove properties

* change request body of delete domain to array of strings (fix)

* change reponse type of delete domain to array
2022-07-19 20:22:45 +02:00
Niklas Meyer
b6e3e7a658 Merge pull request #4691 from mailcow/staging
Merge staging into master
2022-07-18 10:49:47 +02:00
DerLinkman
ceaf1423f4 Moved general compose v2 check below the parameter section to respect --force 2022-07-18 10:39:17 +02:00
Tomy Hsieh
c2e0a275e1 Tailor translation
`edit`, `fido2`
2022-07-16 22:02:58 +08:00
FreddleSpl0it
c8620a066d yubi_otp undo authenticator selection 2022-07-15 16:45:28 +02:00
Niklas Meyer
9598b503ec Merge branch 'master' into staging 2022-07-15 14:03:38 +02:00
FreddleSpl0it
1ca566f670 autoselect authenticator if only one exists 2022-07-15 13:02:13 +02:00
Niklas Meyer
94f4ec8b96 Update tweet-trigger-publish-release.yml 2022-07-15 10:53:51 +02:00
DerLinkman
7aab2c55ff Changed which to command -v + seperated compose check from for loop 2022-07-15 10:30:01 +02:00
Niklas Meyer
6abb4d34c1 Merge pull request #4682 from mailcow/feature/badge-readme
Add Integration Tests badge
2022-07-14 22:45:34 +02:00
Peter
c8ccf080f3 Add Integration Tests badge 2022-07-14 20:01:38 +02:00
FreddleSpl0it
0342ae926c exclude oauth clients & app passwords from mailbox tfa 2022-07-14 18:55:35 +02:00
FreddleSpl0it
be08742653 exclude oauth clients & app passwords from mailbox tfa 2022-07-14 18:37:21 +02:00
Niklas Meyer
528f7da5ef Merge pull request #4680 from mailcow/staging
Mooly Update 2022 - TFA Flow Update
2022-07-14 16:28:59 +02:00
DerLinkman
7d72ae3449 Added update-compose to update.sh and create-coldstandby 2022-07-14 11:29:38 +02:00
FreddleSpl0it
753cde0b85 parse host from url for webauthn library 2022-07-14 09:40:02 +02:00
FreddleSpl0it
223ba44b61 rearrange custom params validation 2022-07-14 09:39:24 +02:00
FreddleSpl0it
cd02483b19 prevent auth wipe out at yubi otp registration 2022-07-14 09:38:44 +02:00
FreddleSpl0it
f724662874 readd imapsync fix 2022-07-13 17:13:25 +02:00
FreddleSpl0it
bee762737e readd imapsync fix 2022-07-13 17:02:14 +02:00
Niklas Meyer
83efd3e506 Merge pull request #4662 from mailcow/feature/updatesh-compose-update-prompt
[Update.sh] Added docker-compose Update prompt + Version check
2022-07-13 16:04:42 +02:00
Niklas Meyer
2278a6cc73 Merge pull request #4674 from mailcow/feature/SECURITY.md
Create SECURITY.md
2022-07-13 16:03:33 +02:00
DerLinkman
586b60b276 Unspecified direct compose version (lower then 2.X.X) 2022-07-13 15:13:14 +02:00
DerLinkman
f07b9ea304 Corrected pip check 2022-07-13 15:08:31 +02:00
Niklas Meyer
09dca5d76c Merge pull request #4677 from mhofer117/patch-1
fix blank page on /user when not logged
2022-07-13 15:07:43 +02:00
DerLinkman
65bb808441 Muted which Pip in update_compose 2022-07-13 11:02:41 +02:00
DerLinkman
83b79edb42 Fixed PIP Check 2022-07-13 08:57:50 +02:00
DerLinkman
b8ec244d92 Modified pip compose check 2022-07-13 08:50:28 +02:00
Marcel Hofer
5b924614aa fix blank page on /user when not logged
the current condition to redirect to / was never matching, so a blank page was displayed on /user when not logged in or when logged in as admin.
this will fix it and always redirect to / if nothing is rendered in the user.php
2022-07-12 15:26:03 +02:00
Niklas Meyer
43103add47 Merge pull request #4671 from ntimo/task/remove-drone-ci
Removed DroneCI & Travis CI
2022-07-12 12:16:29 +02:00
Niklas Meyer
124d5d6bb2 Merge pull request #4673 from ntimo/task/run-tests-using-actions
[CI] Added Mailcow tests & image builds
2022-07-12 12:15:18 +02:00
Timo
58fde558f7 Merge pull request #4670 from ntimo/task/fix-open-api-yml
Fixed OpenAPI docs to be spec compliant
2022-07-12 09:43:13 +02:00
Peter
8b314acfcf Create SECURITY.md 2022-07-11 21:06:23 +02:00
ntimo
1c0eab9893 [CI] Added Mailcow tests & image builds 2022-07-11 17:06:00 +00:00
Tomy Hsieh
514079fe96 Tailor translation
`danger`
2022-07-11 02:44:31 +08:00
DerLinkman
c62daa0c59 Corrected , to . for new workflow 2022-07-08 21:41:48 +02:00
Niklas Meyer
1a05101f50 Create tweet-trigger-publish-release,yml 2022-07-08 21:39:22 +02:00
ntimo
47fb46c837 Removed DroneCI & Travis CI 2022-07-08 18:50:51 +00:00
ntimo
d29580aa02 Fixed OpenAPI docs to be spec compliant 2022-07-08 18:47:28 +00:00
Niklas Meyer
d0fc62ef13 Merge pull request #4669 from mailcow/feature/issue-4668
Fix permissions of create_cold_standby.sh
2022-07-08 20:16:30 +02:00
Peter
b14c0e4c11 Fix permissions chmod +x 2022-07-08 18:29:34 +02:00
FreddleSpl0it
e26d5b8ba5 [BS5] add spacing 2022-07-08 15:47:35 +02:00
FreddleSpl0it
8987ebca36 [BS5] add whats new modal after update 2022-07-08 15:47:21 +02:00
FreddleSpl0it
d3cd21956a [BS5] rearrange nav items 2022-07-08 15:46:14 +02:00
DerLinkman
43ec12f4f0 Readded (again) the new update script check... 2022-07-08 13:49:33 +02:00
DerLinkman
40cf2c85e6 Re-aranged the functions position to top 2022-07-08 13:48:31 +02:00
DerLinkman
6195b7c334 [Backup Script]Check for docker and docker-compose in each step seperate 2022-07-08 13:29:05 +02:00
FreddleSpl0it
b149da28c8 [BS5] minor fixes 2022-07-08 11:32:46 +02:00
FreddleSpl0it
e5cb2dd00e [BS5] adjust restart container btn 2022-07-08 11:31:48 +02:00
FreddleSpl0it
c9b883dff5 [BS5] fix datatables 2022-07-08 11:31:08 +02:00
FreddleSpl0it
ad43253a90 [BS5] add rspamd logo change to darkmode toggle 2022-07-08 11:28:58 +02:00
FreddleSpl0it
979de67c2b [BS5] update bootstrap-select to v1.14.0-beta3 2022-07-08 11:28:27 +02:00
FreddleSpl0it
8416caf798 [BS5] add light and dark rspamd logo 2022-07-08 11:27:34 +02:00
FreddleSpl0it
80d9dfe420 [BS5] adjust css 2022-07-08 11:27:09 +02:00
DerLinkman
385570c1e8 Fixed wrongly override_backup overwriting 2022-07-08 10:54:50 +02:00
DerLinkman
d82cfc6c62 Changed no compose warning color 2022-07-08 10:43:44 +02:00
Tomy Hsieh
27e9210d52 Tailor translation
`admin`
2022-07-07 22:07:02 +08:00
André
fdf52dcb17 [Rspamd] Prevent LUA crash
Fixes LUA error when inserting unknown symbol from settings map
2022-07-07 09:20:59 +02:00
milkmaker
1ff220ccf8 Translations update from Weblate (#4664)
* [Web] Updated lang.ru.json [CI SKIP]

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

* [Web] Updated lang.uk.json [CI SKIP]

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>

Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
2022-07-06 22:02:15 +02:00
FreddleSpl0it
8a49b50f33 [BS5] fix minor issues 2022-07-06 16:55:31 +02:00
Tomy Hsieh
1b6e5b7116 Tailor translation
`add`
2022-07-06 13:33:18 +08:00
Niklas Meyer
536ab34955 Merge pull request #4634 from opsone-ch/staging 2022-07-05 12:55:10 +02:00
DerLinkman
f7369f0611 [Update.sh] Added docker-compose Update prompt + Version check 2022-07-05 12:07:10 +02:00
Rafael Kraut
14bc105d43 [Web] Remove default selection for sync job target mailbox (#4661)
+ Don't cache that form, closes #4642
2022-07-05 11:51:05 +02:00
Niklas Meyer
2efb4365bf Merge pull request #4659 from mailcow/feature/dovecot-2.3.19.1
[Dovecot] Update to 2.3.19.1
2022-07-05 09:08:11 +02:00
Niklas Meyer
c1b86fc782 Merge pull request #4632 from mailcow/sogo-5.7.0
Update SOGo to 5.7.0
2022-07-05 09:00:22 +02:00
FreddleSpl0it
52e92cc0db fix sql query for tfa registration 2022-07-04 17:17:31 +02:00
FreddleSpl0it
3af2f636a5 Merge branch 'feature/tfa-flow' of https://github.com/mailcow/mailcow-dockerized into feature/tfa-flow 2022-07-04 17:01:41 +02:00
FreddleSpl0it
6fb967cf79 extra tfa register debugging 2022-07-04 17:01:35 +02:00
Tomy Hsieh
0dab215e27 Tailor translation
`debug`, `diagnostics`, `tfa`
2022-07-04 23:00:22 +08:00
DerLinkman
03c49ea1f8 Merge branch 'staging' into feature/tfa-flow 2022-07-04 16:43:49 +02:00
Tomy Hsieh
6ec136e63f Tailor translation
`footer`, `header`, `info`, `login`, `oath2`, `ratelimit`, `start`, `warning`
2022-07-03 09:17:09 +08:00
Tomy Hsieh
bba5671eaf Tailor translation: acl 2022-07-03 01:18:34 +08:00
Tomy Hsieh
88d7593d89 Switch language key
zh_Hans -> zh-cn
zh_Hant -> zh-tw
2022-07-02 17:01:50 +08:00
Tomy Hsieh
bd23b80d45 Translation: Spacing
Add spaces between halfwidth and fullwidth characters
2022-07-02 13:06:13 +08:00
Tomy Hsieh
f96e0c4071 Adding Traditional Chinese Translation 2022-07-02 11:29:37 +08:00
FreddleSpl0it
cbd8e40f14 [BS5] fix 2fa 2022-07-01 16:44:24 +02:00
FreddleSpl0it
2d2c033ba7 [BS5] add spacing 2022-07-01 16:21:02 +02:00
FreddleSpl0it
496c68d2af [BS5] datatables handle null values 2022-07-01 16:20:39 +02:00
FreddleSpl0it
c505943e8b [BS5] fix user auth responsive tab 2022-07-01 10:51:58 +02:00
FreddleSpl0it
2841c09c1f [BS5] fix user auth responsive tab 2022-07-01 10:44:21 +02:00
Patrick Schult
11700d7ecb Merge pull request #4403 from El-Virus/master
Fix "The operation is insecure." when trying to register fido2 device.
2022-06-30 13:55:07 +02:00
FreddleSpl0it
18444bd284 [BS5] fix minor issues 2022-06-28 07:21:26 +02:00
FreddleSpl0it
9d3a89d362 [BS5] add darkmode 2022-06-28 07:20:46 +02:00
DerLinkman
33eb2c8801 Improved [::] Section check + included prior override backup 2022-06-24 23:10:00 +02:00
FreddleSpl0it
2d0ab4a1b8 [BS5] make container status more visible 2022-06-24 16:04:12 +02:00
FreddleSpl0it
2fec7ccd58 [BS5] make container status more visible 2022-06-24 15:55:52 +02:00
FreddleSpl0it
a835419168 fix imapsync 2022-06-23 18:36:54 +02:00
FreddleSpl0it
052959f435 [BS5] remove ui theme selector - add darkmode toggler 2022-06-23 16:34:58 +02:00
Niklas Meyer
4ce16d1ea4 Merge pull request #4644 from mailcow/feature/update-composev2
Added auto correction of composev1 Binds in compose.yml
2022-06-23 15:43:49 +02:00
DerLinkman
c1c7167ace Added auto correction of composev1 Binds in compose.yml 2022-06-23 15:41:48 +02:00
Niklas Meyer
3d538d4f14 Merge pull request #4643 from mailcow/staging
2022-06a | IMAPSync Hardening + Docker-Compose v2 now needed
2022-06-23 15:04:46 +02:00
Niklas Meyer
7969e7116d Merge branch 'feature/imapsync' into staging 2022-06-23 11:26:07 +02:00
Niklas Meyer
4f58f2caee Merge branch 'feature/update-composev2' into staging 2022-06-23 11:25:58 +02:00
DerLinkman
263baa81c0 Improved .yml and .yaml check for Port Removal 2022-06-23 10:55:12 +02:00
DerLinkman
092890b6ab Changed message in nginx-port removal function 2022-06-23 10:23:48 +02:00
DerLinkman
db7d7ea288 Added override NGINX Port Removal 2022-06-23 10:05:09 +02:00
DerLinkman
452daf5d5e Restored docker-compose Command 2022-06-23 08:55:06 +02:00
FreddleSpl0it
d373164e13 hotfix imapsync 2022-06-20 21:18:57 +02:00
FreddleSpl0it
cd7715fa0e Restore docker-compose check in scripts 2022-06-20 10:32:14 +02:00
milkmaker
af9c3a8565 [Web] Updated lang.es.json [CI SKIP] (#4638)
Co-authored-by: Daniel Castellanos <decacis@gmail.com>

Co-authored-by: Daniel Castellanos <decacis@gmail.com>
2022-06-19 22:23:35 +02:00
DerLinkman
dd6b8c44a4 Added automatic docker-compose standalone installation 2022-06-16 14:13:08 +02:00
DerLinkman
499273dbb7 Readded docker-compose check 2022-06-16 13:50:44 +02:00
DerLinkman
6612b892b7 Removed extra checkout line 2022-06-16 12:56:54 +02:00
DerLinkman
89cea31475 Revert "Before update on 2022-06-16_12_41_05"
This reverts commit 36e4ee7738.
2022-06-16 12:51:51 +02:00
DerLinkman
872fa07213 Restore docker-compose check in scripts 2022-06-16 12:49:17 +02:00
DerLinkman
36e4ee7738 Before update on 2022-06-16_12_41_05 2022-06-16 12:41:49 +02:00
DerLinkman
a139eb9bce Readded Dual Stack availability of WebUI (default) 2022-06-16 12:38:06 +02:00
DerLinkman
7166696aa2 Readded Compose Standalone Download 2022-06-16 12:28:04 +02:00
Markus Ritzmann
537a7908f1 Clamd: Fix Docker Healthcheck 2022-06-16 09:50:33 +02:00
FreddleSpl0it
560df58bb4 [BS5] fix minor issues 2022-06-15 16:34:49 +02:00
DerLinkman
5629d47cb6 Merge branch 'pr/FreddleSpl0it/4527' into feature/bootstrap5 2022-06-15 11:22:59 +02:00
Peter
3fe776ee69 Update SOGo to 5.7.0 2022-06-14 18:55:26 +02:00
FreddleSpl0it
37b4ff811d [BS5] add theme selector 2022-06-14 16:31:21 +02:00
FreddleSpl0it
7384aab2f4 [BS5] fix minor issues 2022-06-14 15:52:59 +02:00
DerLinkman
581be02e53 [Dovecot] Update to 2.3.19.1 2022-06-14 15:02:40 +02:00
FreddleSpl0it
71db83efce hotfix imapsync 2022-06-13 12:46:39 +02:00
andryyy
7ae7f25580 [Web] Re-use DKIM key if available 2022-06-11 11:42:36 +02:00
FreddleSpl0it
4ce05d4d4d [BS5] datatables add responsivePrio and adjust className 2022-06-08 16:21:15 +02:00
FreddleSpl0it
fdb56de0a8 [BS5] jquery datatable - add classes to action column 2022-06-08 15:31:10 +02:00
FreddleSpl0it
df56d73cec [BS5] jquery datatable - add classes to action column 2022-06-08 15:28:45 +02:00
FreddleSpl0it
4ba0e155f3 [BS5] fix guid collapse stutter 2022-06-08 12:16:45 +02:00
FreddleSpl0it
304655f7ff [BS5] remember last nav pill - revert id var 2022-06-08 12:12:12 +02:00
FreddleSpl0it
6210f06bc0 [BS5] adjust admin refresh_table function 2022-06-08 12:06:14 +02:00
FreddleSpl0it
09ae37410e [BS5] jquery datatables disable orderable checkboxes 2022-06-08 12:03:54 +02:00
FreddleSpl0it
351c803623 [BS5] change onVisible querySelectors to table id 2022-06-08 11:49:05 +02:00
FreddleSpl0it
6a027b70e7 [BS5] replace footable with jquery datatables (edit.twig) 2022-06-08 11:19:20 +02:00
DerLinkman
5d14baa43a Fixed typo for previous commit 2022-06-07 18:38:43 +02:00
DerLinkman
141b397c82 Fix Docker Compose recognition for docker-compose syntax 2022-06-07 18:34:41 +02:00
Niklas Meyer
fd853cfc6f [Compose] Rollback watchdog to 1.96
Due to https://github.com/nagios-plugins/nagios-plugins/pull/649 which cause the Certificate Check to fail.
2022-06-07 17:50:42 +02:00
Niklas Meyer
63f718178e 🌕🐄 Moone Update 2022 - The Docker Compose v2 Update (Part I)
The next major mailcow release.
2022-06-07 15:37:41 +02:00
FreddleSpl0it
cdd2adbc73 [BS5] remember last nav pill fix 2022-06-07 15:28:28 +02:00
DerLinkman
74baf20feb Optimized if-else arguments and outputs 2022-06-07 14:45:19 +02:00
FreddleSpl0it
958112af6b [Compose] Remove >&2 in if block 2022-06-07 14:07:35 +02:00
FreddleSpl0it
08d0f9448e [Compose] move then in if statement 2022-06-07 13:59:59 +02:00
Niklas Meyer
7bcc8bd3a2 [Compose] Removed volume Bind from rspamd-vol 2022-06-07 10:34:59 +02:00
FreddleSpl0it
0eb2545773 [WebAuthn] send empty transports array to fix android bug 2022-06-07 09:01:04 +02:00
Niklas Meyer
714511b0a8 [Compose] Update to Docker Compose v2 (#4605)
* Change default HTTP_BIND, HTTPS_BIND

https://github.com/mailcow/mailcow-dockerized/issues/4315#issuecomment-1083034329

* [Compose] Removed Colon after fallback IP in docker-compose.yml

* [Compose] Remove bind options from volumes (#4577)

(cherry picked from commit 4d53216c05)

* Migration (partially) of update.sh + cold-standby.sh to composev2

* Migration of update.sh + cold-standby.sh to composev2

* Migration of update.sh + cold-standby.sh to composev2

* Migration of update.sh + cold-standby.sh to composev2

* [ClamAV] Fixed ClamAV start before unbound

* Migration of update.sh + cold-standby.sh to composev2

* Formulation and values adjusted (IPv4 bind in generate-config.sh)

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: qupfer <github@qupfer.de>
Co-authored-by: FreddleSpl0it <patschul@posteo.de>
2022-06-07 08:53:08 +02:00
FreddleSpl0it
cb6a5d4069 [BS5] add responsive tabs and more 2022-06-06 20:38:24 +02:00
Niklas Meyer
c9700773f4 Merge pull request #4613 from mailcow/phpfpm-alpine3.16
PHP-FPM base image update
2022-06-05 20:26:24 +02:00
Peter
2229f87d9b Update base image to alpine 3.16 and updated some dependencies 2022-06-05 19:36:09 +02:00
Niklas Meyer
d360503443 Merge pull request #4609 from mailcow/unbound-alpine3.16
Unbound base image update
2022-06-05 19:20:15 +02:00
Niklas Meyer
838182a8b4 Merge pull request #4608 from mailcow/watchdog-alpine3.16
Watchdog base image update
2022-06-05 19:18:36 +02:00
Niklas Meyer
967cfedbb3 Merge pull request #4610 from mailcow/olefy-alpine3.16
Olefy base image update
2022-06-05 19:15:06 +02:00
Niklas Meyer
a36645a282 Merge pull request #4611 from mailcow/dockerapi-alpine3.16
Dockerapi base image update
2022-06-05 19:14:33 +02:00
Niklas Meyer
3368a70f88 Merge pull request #4612 from mailcow/acme-alpine3.16
acme base image update
2022-06-05 19:14:07 +02:00
Peter
cd1715ba52 Update base image to alpine 3.16 2022-06-05 19:06:03 +02:00
Peter
0bc2a16093 Update base image to alpine 3.16 2022-06-05 19:04:51 +02:00
Peter
a21b3cd606 Update base image to alpine 3.16 2022-06-05 19:03:37 +02:00
Peter
1c479684fc Revert "Update base image to alpine 3.16"
This reverts commit c9dbc7c7b7.
2022-06-05 19:02:21 +02:00
Peter
c9dbc7c7b7 Update base image to alpine 3.16 2022-06-05 19:01:55 +02:00
Peter
c41dc9d8c0 Update base image to alpine 3.16 2022-06-05 19:01:06 +02:00
Peter
1db5841424 Update base image to alpine 3.16 2022-06-05 18:59:56 +02:00
Niklas Meyer
e53b068902 Merge pull request #4607 from mailcow/netfilter-alpine3.16
Netfilter base image update
2022-06-05 18:44:38 +02:00
Peter
2bd436dfd8 Update base image to alpine 3.16 2022-06-05 18:41:54 +02:00
Peter
d13be25f45 Update base image to alpine 3.16 2022-06-05 18:38:16 +02:00
Niklas Meyer
6efd9dc5f9 [Postfix] Update to 3.5.6 (Rebase to Debian 11)
New Postfix Image is: mailcow/postfix:1.67
2022-06-05 14:48:03 +02:00
FreddleSpl0it
f13530d8a1 [BS5] Replace FooTable with jquery Datatables 2022-06-03 15:45:36 +02:00
Niklas Meyer
1edd4012e4 [Web] escapehtml in mailbox.js (#4604)
Co-authored-by: FreddleSpl0it <patschul@posteo.de>
2022-06-03 14:37:56 +02:00
milkmaker
4390c9855a [Web] Updated lang.de.json [CI SKIP] (#4600)
[Web] Updated lang.de.json [CI SKIP]

Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Peter <magic@kthx.at>
2022-05-31 19:59:00 +02:00
qupfer
4d53216c05 [Compose] Remove bind options from volumes (#4577) 2022-05-31 09:34:06 +02:00
FreddleSpl0it
8a86fa491e [BS5] Replace FooTable with jquery Datatables 2022-05-20 12:03:12 +02:00
DerLinkman
040206859f [DB] Remove pipemes from custom_params
(cherry picked from commit c27ad97287)
2022-05-20 09:45:54 +02:00
DerLinkman
d06119a21d [IMAPSYNC] Hardened pipemess exploit prevention (pipemes)
(cherry picked from commit b1658c0f83)
2022-05-20 09:45:45 +02:00
DerLinkman
c27ad97287 [DB] Remove pipemes from custom_params 2022-05-20 09:44:11 +02:00
DerLinkman
b1658c0f83 [IMAPSYNC] Hardened pipemess exploit prevention (pipemes) 2022-05-20 09:30:42 +02:00
FreddleSpl0it
3e6a241c69 [BS5] Replace FooTable with jquery Datatables 2022-05-19 21:29:01 +02:00
Niklas Meyer
05b8609073 [Postfix] Update to 3.5.6 (Rebase to Debian 11) 2022-05-19 18:49:01 +02:00
DerLinkman
97df5c3b9c [DB] Update DB Version to remove pipemess parameters 2022-05-19 15:42:13 +02:00
FreddleSpl0it
160dceff3e [BS5] Replace FooTable with jquery Datatables 2022-05-19 15:06:18 +02:00
DerLinkman
33e5ad2b5c [Imapsync] Case sensitive PIPEMESS removal 2022-05-19 14:41:21 +02:00
DerLinkman
998cb642a9 [UI] Moved Password Change warning to top for user site 2022-05-19 10:43:06 +02:00
milkmaker
07ac195fea Translations update from Weblate (#4591)
* [Web] Updated lang.ru.json [CI SKIP]

Co-authored-by: DRago_Angel <alekseev.dmitriy.92@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.uk.json [CI SKIP]

[Web] Updated lang.uk.json [CI SKIP]

[Web] Added lang.uk.json [CI SKIP]

Co-authored-by: OGudzik <olegrpg@gmail.com>
Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.it.json [CI SKIP]

Co-authored-by: Stefano <stefano.vassena@gmail.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* Add Ukrainian language code in vars.inc.php

Co-authored-by: DRago_Angel <alekseev.dmitriy.92@gmail.com>
Co-authored-by: OGudzik <olegrpg@gmail.com>
Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Stefano <stefano.vassena@gmail.com>
2022-05-18 18:20:03 +02:00
FreddleSpl0it
7d5990bf0f restrict webauthn-tfa-get-args sql query 2022-05-18 10:03:10 +02:00
FreddleSpl0it
4ec982163e restrict webauthn-tfa-get-args sql query 2022-05-18 09:39:50 +02:00
FreddleSpl0it
3c9502f241 add webauthn console log 2022-05-17 19:02:52 +02:00
Niklas Meyer
63cecb2fd8 Merge pull request #4484 from FreddleSpl0it/selection-tfa
[Web] change tfa flow
2022-05-17 15:26:43 +02:00
Niklas Meyer
3029a2d33d Change DB Date to newer Date than staging 2022-05-17 15:26:01 +02:00
Niklas Meyer
fa0d2a959d Merge branch 'feature/tfa-flow' into selection-tfa 2022-05-17 15:23:10 +02:00
FreddleSpl0it
0ece065cb0 [BS5] Replace FooTable with jquery Datatables 2022-05-17 14:08:22 +02:00
Niklas Meyer
f79cac3292 Merge pull request #4590 from FreddleSpl0it/swagger-appPasswd 2022-05-17 08:53:57 +02:00
FreddleSpl0it
7a20a9941e Update swagger docs - add/app-passwd 2022-05-17 07:03:33 +02:00
Niklas Meyer
24cc960379 [Clamd] Update to ClamAV 0.105
Merge pull request #4589 from mailcow/feature/clamd-0.105
2022-05-16 19:51:18 +02:00
Niklas Meyer
353df6413f [UI] Increase Mailadmin loading performance
Merge pull request #4562 from marcojarjour/unblock_mailadmin_upstream
2022-05-16 19:30:50 +02:00
FreddleSpl0it
fb7e00c158 [BS5] Replace FooTable with jquery Datatables 2022-05-16 11:26:49 +02:00
FreddleSpl0it
a0567beee5 [BS5] Replace FooTable with jquery Datatables 2022-05-13 14:16:32 +02:00
DerLinkman
ee844c81d2 Changed Base Docker Image to 0.105.0_base 2022-05-08 18:33:29 +02:00
Niklas Meyer
b6cb3b026c [ClamAV] Update to 0.105 2022-05-06 15:44:58 +02:00
Marco Jarjour
003a6342a5 Match also mobile id's 2022-04-27 17:43:40 +02:00
Marco Jarjour
fb10764167 Execute API calls only when needed 2022-04-27 15:57:53 +02:00
FreddleSpl0it
96c8e01a3b [BS5] change spinner icons 2022-04-14 10:22:06 +02:00
FreddleSpl0it
88bd7bff1e [BS5] fix card header btns 2022-04-13 21:45:00 +02:00
FreddleSpl0it
7075b9f0c0 [BS5] mobile navbar fix 2022-04-13 21:34:00 +02:00
FreddleSpl0it
b19666f7e0 [BS5] add layout spacing 2022-04-13 16:37:52 +02:00
FreddleSpl0it
e663f3db72 [BS5] change form-group 2022-04-13 14:07:07 +02:00
FreddleSpl0it
fd1ffdba80 [BS5] layout fixes 2022-04-13 12:36:59 +02:00
FreddleSpl0it
a12538b3a8 [BS5] layout fixes 2022-04-13 12:35:04 +02:00
FreddleSpl0it
cdff1ba37b [BS5] update bootstrap-select to v1.14beta 2022-04-13 12:34:14 +02:00
FreddleSpl0it
f6a51f6b6f [BS5] add gridjs lib 2022-04-13 12:32:48 +02:00
FreddleSpl0it
45dd0611d9 [BS5] fix card classes 2022-04-01 08:26:37 +02:00
FreddleSpl0it
e62069d3db [BS5] change bootstrap in js 2022-04-01 08:25:47 +02:00
FreddleSpl0it
5088636d5f [BS5] change bootstrap responsive 2022-04-01 08:02:11 +02:00
FreddleSpl0it
003d70990e [BS5] change bootstrap general 2022-04-01 07:33:01 +02:00
FreddleSpl0it
051d08b499 [BS5] bug fixes 2022-03-31 20:16:44 +02:00
FreddleSpl0it
b980e7af29 [BS5] change bootstrap responsive 2022-03-31 15:24:10 +02:00
FreddleSpl0it
4d0799dead [BS5] change bootstrap general 2022-03-31 13:24:18 +02:00
FreddleSpl0it
d3dca1ddc2 [BS5] change bootstrap general 2022-03-31 12:57:33 +02:00
FreddleSpl0it
9b8039440c [BS5] change bootstrap general 2022-03-31 12:41:50 +02:00
FreddleSpl0it
eea5c9df2f [BS5] change bootstrap panels/cards 2022-03-31 11:37:14 +02:00
FreddleSpl0it
aa9aff800c [BS5] change bootstrap dropdowns 2022-03-31 10:09:25 +02:00
FreddleSpl0it
0b3b5e230b [BS5] change bootstrap data-attributes 2022-03-30 13:04:54 +02:00
FreddleSpl0it
db0d91beb1 [BS5] change bootstrap tabs 2022-03-30 12:54:38 +02:00
FreddleSpl0it
4758033445 [BS5] change bootstrap tabs 2022-03-30 12:39:18 +02:00
FreddleSpl0it
1e48fb8cda [BS5] change jquery $(window).load 2022-03-30 08:45:24 +02:00
FreddleSpl0it
1d8da117d6 [BS5] change bootstrap navbar 2022-03-30 08:39:38 +02:00
FreddleSpl0it
635fa795d2 [BS5] move init frontend block 2022-03-30 07:55:52 +02:00
FreddleSpl0it
c1792df819 [BS5] include dependencies 2022-03-30 07:54:07 +02:00
FreddleSpl0it
36944f8073 [BS5] remove dependencies 2022-03-30 07:08:24 +02:00
FreddleSpl0it
4d59cb0351 [BS5] remove u2f-api.js 2022-03-29 09:41:11 +02:00
FreddleSpl0it
6d3798ad08 [Web] fix yubi otp 2022-03-19 20:18:31 +01:00
FreddleSpl0it
70921b8d15 [Web] tfa extra debugging 2022-03-18 08:45:02 +01:00
FreddleSpl0it
b185f83fc3 [Web] tfa extra debugging 2022-03-18 08:37:22 +01:00
FreddleSpl0it
60af295c0a Merge branch 'selection-tfa' of https://github.com/FreddleSpl0it/mailcow-dockerized into selection-tfa 2022-03-14 10:32:55 +01:00
FreddleSpl0it
e7fe52a625 [Web] increase mysql publicKey field length 2022-03-14 10:31:59 +01:00
FreddleSpl0it
49c506eed9 [Web] multiple tfa - user support 2022-03-14 10:31:59 +01:00
FreddleSpl0it
21fadf6df2 [Web] multiple tfa - domainadmin support 2022-03-14 10:31:58 +01:00
FreddleSpl0it
5fcccbc97d [Web] add verify selected tfa 2022-03-14 10:31:56 +01:00
FreddleSpl0it
3ef2b6cfa2 [Web] add verify selected tfa 2022-03-14 10:31:51 +01:00
FreddleSpl0it
84b4269c75 [Web] increase mysql publicKey field length 2022-03-14 09:29:07 +01:00
FreddleSpl0it
a2d57d43d1 [Web] multiple tfa - user support 2022-03-07 11:41:13 +01:00
FreddleSpl0it
df33f1a130 [Web] multiple tfa - domainadmin support 2022-02-22 09:38:06 +01:00
FreddleSpl0it
4c6a2055c2 [Web] add verify selected tfa 2022-02-21 14:10:12 +01:00
FreddleSpl0it
f09a3df870 [Web] add verify selected tfa 2022-02-21 10:46:24 +01:00
El-Virus
ea1a412749 Fix missing "lbuchs", after resolving last conflict
It seems that when solving the conflict in my pr when the latest staging branch was merged to master, I accidentally deleted "lbuchs", I added it back
2022-01-21 15:46:44 +01:00
El-Virus
db82327d9a Merge branch 'staging' into master 2022-01-21 15:40:37 +01:00
El-Virus
ea1a02bd7d Fix "The operation is insecure." when trying to register fido2 device.
navigator.credentials.create(); Doesn't accept a port in the "id" parameter. So, when trying to register a fido2 device via WebAuthn throws: "The operation is insecure." on firefox and "The relying party ID is not a registrable domain suffix of, nor equal to the current domain." on Chrome or Edge.
This commit replaces `$_SERVER['HTTP_HOST']` with `$_SERVER['SERVER_NAME']` when initializing `$WebAuthn` which excludes the port to formulate correct requests.
Now Mailcow allows the registration of fido2 devices when running in a non-standard port(eg. 443).
2021-12-26 17:11:06 +01:00
Daniel Lo Nigro
1606658cb1 Add missing spaces 2021-08-28 20:02:39 -07:00
Daniel Lo Nigro
54ba66733e Enable maildir_very_dirty_syncs rather than just adding comment 2021-05-02 16:39:26 -07:00
Daniel Lo Nigro
f6847e6f8c Add comment about maildir_very_dirty_syncs to dovecot.conf 2021-03-13 10:46:32 -08:00
1403 changed files with 148900 additions and 32579 deletions

View File

@@ -1,120 +0,0 @@
---
kind: pipeline
name: integration-testing
platform:
os: linux
arch: amd64
clone:
disable: true
steps:
- name: prepare-tests
pull: default
image: timovibritannia/ansible
commands:
- git clone https://github.com/mailcow/mailcow-integration-tests.git --branch $(curl -sL https://api.github.com/repos/mailcow/mailcow-integration-tests/releases/latest | jq -r '.tag_name') --single-branch .
- chmod +x ci.sh
- chmod +x ci-ssh.sh
- chmod +x ci-piprequierments.sh
- ./ci.sh
- wget -O group_vars/all/secrets.yml $SECRETS_DOWNLOAD_URL --quiet
environment:
SECRETS_DOWNLOAD_URL:
from_secret: SECRETS_DOWNLOAD_URL
VAULT_PW:
from_secret: VAULT_PW
when:
branch:
- master
- staging
event:
- push
- name: lint
pull: default
image: timovibritannia/ansible
commands:
- ansible-lint ./
when:
branch:
- master
- staging
event:
- push
- name: create-server
pull: default
image: timovibritannia/ansible
commands:
- ./ci-piprequierments.sh
- ansible-playbook mailcow-start-server.yml --diff
- ./ci-ssh.sh
environment:
ANSIBLE_HOST_KEY_CHECKING: false
ANSIBLE_FORCE_COLOR: true
when:
branch:
- master
- staging
event:
- push
- name: setup-server
pull: default
image: timovibritannia/ansible
commands:
- sleep 120
- ./ci-piprequierments.sh
- ansible-playbook mailcow-setup-server.yml --private-key /drone/src/id_ssh_rsa --diff
environment:
ANSIBLE_HOST_KEY_CHECKING: false
ANSIBLE_FORCE_COLOR: true
when:
branch:
- master
- staging
event:
- push
- name: run-tests
pull: default
image: timovibritannia/ansible
commands:
- ./ci-piprequierments.sh
- ansible-playbook mailcow-integration-tests.yml --private-key /drone/src/id_ssh_rsa --diff
environment:
ANSIBLE_HOST_KEY_CHECKING: false
ANSIBLE_FORCE_COLOR: true
when:
branch:
- master
- staging
event:
- push
- name: delete-server
pull: default
image: timovibritannia/ansible
commands:
- ./ci-piprequierments.sh
- ansible-playbook mailcow-delete-server.yml --diff
environment:
ANSIBLE_HOST_KEY_CHECKING: false
ANSIBLE_FORCE_COLOR: true
when:
branch:
- master
- staging
event:
- push
status:
- failure
- success
---
kind: signature
hmac: f6619243fe2a27563291c9f2a46d93ffbc3b6dced9a05f23e64b555ce03a31e5
...

3
.github/FUNDING.yml vendored
View File

@@ -1 +1,2 @@
custom: https://mailcow.github.io/mailcow-dockerized-docs/#help-mailcow
github: mailcow
custom: ["https://www.servercow.de/mailcow?lang=en#sal"]

View File

@@ -7,8 +7,8 @@ body:
label: Contribution guidelines
description: Please read the contribution guidelines before proceeding.
options:
- label: I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree
required: true
- label: I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree
required: true
- type: checkboxes
attributes:
label: I've found a bug and checked that ...
@@ -26,70 +26,142 @@ body:
attributes:
label: Description
description: Please provide a brief description of the bug in 1-2 sentences. If applicable, add screenshots to help explain your problem. Very useful for bugs in mailcow UI.
render: plain text
validations:
required: true
- type: textarea
attributes:
label: Logs
description: Please take a look at the [official documentation](https://mailcow.github.io/mailcow-dockerized-docs/debug-logs/) and post the last few lines of logs, when the error occurs. For example, docker container logs of affected containers. This will be automatically formatted into code, so no need for backticks.
render: bash
label: "Logs:"
description: "Please take a look at the [official documentation](https://docs.mailcow.email/troubleshooting/debug-logs/) and post the last few lines of logs, when the error occurs. For example, docker container logs of affected containers. This will be automatically formatted into code, so no need for backticks."
render: plain text
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Please describe the steps to reproduce the bug. Screenshots can be added, if helpful.
label: "Steps to reproduce:"
description: "Please describe the steps to reproduce the bug. Screenshots can be added, if helpful."
render: plain text
placeholder: |-
1. ...
2. ...
3. ...
validations:
required: true
- type: textarea
- type: markdown
attributes:
label: System information
description: In this stage we would kindly ask you to attach general system information about your setup.
value: |-
| Question | Answer |
| --- | --- |
| My operating system | I_DO_REPLY_HERE |
| Is Apparmor, SELinux or similar active? | I_DO_REPLY_HERE |
| Virtualization technology (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE |
| Server/VM specifications (Memory, CPU Cores) | I_DO_REPLY_HERE |
| Docker version (`docker version`) | I_DO_REPLY_HERE |
| docker-compose version (`docker-compose version`) | I_DO_REPLY_HERE |
| mailcow version (```git describe --tags `git rev-list --tags --max-count=1` ```) | I_DO_REPLY_HERE |
| Reverse proxy (custom solution) | I_DO_REPLY_HERE |
Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:
```
YOUR OUTPUT GOES HERE
```
All third-party firewalls and custom iptables rules are unsupported. **Please check the Docker docs about how to use Docker with your own ruleset**. Nevertheless, iptabels output can help us to help you:
iptables -L -vn:
```
YOUR OUTPUT GOES HERE
```
ip6tables -L -vn:
```
YOUR OUTPUT GOES HERE
```
iptables -L -vn -t nat:
```
YOUR OUTPUT GOES HERE
```
ip6tables -L -vn -t nat:
```
YOUR OUTPUT GOES HERE
```
DNS problems? Please run `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network) and post the output:
```
YOUR OUTPUT GOES HERE
```
value: |
## System information
### In this stage we would kindly ask you to attach general system information about your setup.
- type: dropdown
attributes:
label: "Which branch are you using?"
description: "#### `git rev-parse --abbrev-ref HEAD`"
multiple: false
options:
- master
- nightly
validations:
required: true
- type: dropdown
attributes:
label: "Which architecture are you using?"
description: "#### `uname -m`"
multiple: false
options:
- x86
- ARM64 (aarch64)
validations:
required: true
- type: input
attributes:
label: "Operating System:"
placeholder: "e.g. Ubuntu 22.04 LTS"
validations:
required: true
- type: input
attributes:
label: "Server/VM specifications:"
placeholder: "Memory, CPU Cores"
validations:
required: true
- type: input
attributes:
label: "Is Apparmor, SELinux or similar active?"
placeholder: "yes/no"
validations:
required: true
- type: input
attributes:
label: "Virtualization technology:"
placeholder: "KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported**"
validations:
required: true
- type: input
attributes:
label: "Docker version:"
description: "#### `docker version`"
placeholder: "20.10.21"
validations:
required: true
- type: input
attributes:
label: "docker-compose version or docker compose version:"
description: "#### `docker-compose version` or `docker compose version`"
placeholder: "v2.12.2"
validations:
required: true
- type: input
attributes:
label: "mailcow version:"
description: "#### ```git describe --tags `git rev-list --tags --max-count=1` ```"
placeholder: "2022-08"
validations:
required: true
- type: input
attributes:
label: "Reverse proxy:"
placeholder: "e.g. Nginx/Traefik"
validations:
required: true
- type: textarea
attributes:
label: "Logs of git diff:"
description: "#### Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of iptables -L -vn:"
description: "#### Output of `iptables -L -vn`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of ip6tables -L -vn:"
description: "#### Output of `ip6tables -L -vn`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of iptables -L -vn -t nat:"
description: "#### Output of `iptables -L -vn -t nat`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of ip6tables -L -vn -t nat:"
description: "#### Output of `ip6tables -L -vn -t nat`"
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "DNS check:"
description: "#### Output of `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network)"
render: plain text
validations:
required: true

View File

@@ -1,8 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: ❓ Community-driven support
url: https://mailcow.github.io/mailcow-dockerized-docs/#get-support
- name: ❓ Community-driven support (Free)
url: https://docs.mailcow.email/#community-support-and-chat
about: Please use the community forum for questions or assistance
- name: 🔥 Premium Support (Paid)
url: https://www.servercow.de/mailcow?lang=en#support
about: Buy a support subscription for any critical issues and get assisted by the mailcow Team. See conditions!
- name: 🚨 Report a security vulnerability
url: https://www.servercow.de/anfrage?lang=en
url: "mailto:info@servercow.de?subject=mailcow: dockerized Security Vulnerability"
about: Please give us appropriate time to verify, respond and fix before disclosure.

View File

@@ -0,0 +1,3 @@
## :file_folder: Modified files
<!-- Diff files - START -->
<!-- Diff files - END -->

38
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,38 @@
<!-- _Please make sure to review and check all of these items, otherwise we might refuse your PR:_ -->
## Contribution Guidelines
* [ ] I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree them
<!-- _NOTE: this tickbox is needed to fullfil on order to get your PR reviewed._ -->
## What does this PR include?
### Short Description
<!-- Please write a short description, what your PR does here. -->
### Affected Containers
<!-- Please list all affected Docker containers here, which you commited changes to -->
<!--
Please list them like this:
- container1
- container2
- container3
etc.
-->
## Did you run tests?
### What did you tested?
<!-- Please write shortly, what you've tested (which components etc.). -->
### What were the final results? (Awaited, got)
<!-- Please write shortly, what your final tests results were. What did you awaited? Was the outcome the awaited one? -->

25
.github/renovate.json vendored Normal file
View File

@@ -0,0 +1,25 @@
{
"enabled": true,
"timezone": "Europe/Berlin",
"dependencyDashboard": true,
"dependencyDashboardTitle": "Renovate Dashboard",
"commitBody": "Signed-off-by: milkmaker <milkmaker@mailcow.de>",
"rebaseWhen": "auto",
"labels": ["renovate"],
"assignees": [
"@magiccc"
],
"baseBranches": ["staging"],
"enabledManagers": ["github-actions", "regex", "docker-compose"],
"ignorePaths": [
"data\/web\/inc\/lib\/vendor\/**"
],
"regexManagers": [
{
"fileMatch": ["(^|/)Dockerfile[^/]*$"],
"matchStrings": [
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?( extractVersion=(?<extractVersion>.*?))?\\s(ENV|ARG) .*?_VERSION=(?<currentValue>.*)\\s"
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -0,0 +1,37 @@
name: Check if labeled support, if so send message and close issue
on:
issues:
types:
- labeled
jobs:
add-comment:
if: github.event.label.name == 'support'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Add comment
run: gh issue comment "$NUMBER" --body "$BODY"
env:
GH_TOKEN: ${{ secrets.SUPPORTISSUES_ACTION_PAT }}
GH_REPO: ${{ github.repository }}
NUMBER: ${{ github.event.issue.number }}
BODY: |
**THIS IS A AUTOMATED MESSAGE!**
It seems your issue is not a bug.
Therefore we highly advise you to get support!
You can get support either by:
- ordering a paid [support contract at Servercow](https://www.servercow.de/mailcow?lang=en#support/) (Directly from the developers) or
- using the [community forum](https://community.mailcow.email) (**Based on volunteers! NO guaranteed answer**) or
- using the [Telegram support channel](https://t.me/mailcow) (**Based on volunteers! NO guaranteed answer**)
This issue will be closed. If you think your reported issue is not a support case feel free to comment above and if so the issue will reopened.
- name: Close issue
env:
GH_TOKEN: ${{ secrets.SUPPORTISSUES_ACTION_PAT }}
GH_REPO: ${{ github.repository }}
NUMBER: ${{ github.event.issue.number }}
run: gh issue close "$NUMBER" -r "not planned"

View File

@@ -0,0 +1,33 @@
name: Check PRs if on staging
on:
pull_request_target:
types: [opened, edited]
permissions: {}
jobs:
is_not_staging:
runs-on: ubuntu-latest
if: github.event.pull_request.base.ref != 'staging' #check if the target branch is not staging
steps:
- name: Send message
uses: thollander/actions-comment-pull-request@v3.0.1
with:
github-token: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
message: |
Thanks for contributing!
I noticed that you didn't select `staging` as your base branch. Please change the base branch to `staging`.
See the attached picture on how to change the base branch to `staging`:
![check_prs_if_on_staging.png](https://raw.githubusercontent.com/mailcow/mailcow-dockerized/master/.github/workflows/assets/check_prs_if_on_staging.png)
- name: Fail #we want to see failed checks in the PR
if: ${{ success() }} #set exit code to 1 even if commenting somehow failed
run: exit 1
is_staging:
runs-on: ubuntu-latest
if: github.event.pull_request.base.ref == 'staging' #check if the target branch is staging
steps:
- name: Success
run: exit 0

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v5.0.0
uses: actions/stale@v9.1.0
with:
repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60
@@ -30,6 +30,7 @@ jobs:
stale-issue-label: "stale"
stale-pr-label: "stale"
exempt-draft-pr: "true"
close-issue-reason: "not_planned"
operations-per-run: "250"
ascending: "true"
#DRY-RUN

42
.github/workflows/image_builds.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Build mailcow Docker Images
on:
push:
branches: [ "master", "staging" ]
workflow_dispatch:
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
docker_image_builds:
strategy:
matrix:
images:
- "acme-mailcow"
- "clamd-mailcow"
- "dockerapi-mailcow"
- "dovecot-mailcow"
- "netfilter-mailcow"
- "olefy-mailcow"
- "php-fpm-mailcow"
- "postfix-mailcow"
- "rspamd-mailcow"
- "sogo-mailcow"
- "unbound-mailcow"
- "watchdog-mailcow"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Docker
run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
sudo service docker start
- name: Prepair Image Builds
run: |
cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml
- name: Build Docker Images
run: |
docker compose build ${image}
env:
image: ${{ matrix.images }}

25
.github/workflows/pr_to_nightly.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Create PR to merge to nightly from staging
on:
push:
branches:
- staging
jobs:
action-pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run the Action
uses: devops-infra/action-pull-request@v0.6.0
with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
assignee: DerLinkman
source_branch: staging
target_branch: nightly
reviewer: DerLinkman
label: upstream
template: .github/ISSUE_TEMPLATE/pr_to_nighty_template.yml
get_diff: true

View File

@@ -0,0 +1,39 @@
name: Build mailcow backup image
on:
schedule:
# At 00:00 on Sunday
- cron: "0 0 * * 0"
workflow_dispatch: # Allow to run workflow manually
jobs:
docker_image_build:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
file: data/Dockerfiles/backup/Dockerfile
push: true
tags: ghcr.io/mailcow/backup:latest

View File

@@ -0,0 +1,39 @@
name: Update postscreen_access.cidr
on:
schedule:
# Monthly
- cron: "0 0 1 * *"
workflow_dispatch: # Allow to run workflow manually
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
Update-postscreen_access_cidr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate postscreen_access.cidr
run: |
bash helper-scripts/update_postscreen_whitelist.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.mailcow_action_Update_postscreen_access_cidr_pat }}
commit-message: update postscreen_access.cidr
committer: milkmaker <milkmaker@mailcow.de>
author: milkmaker <milkmaker@mailcow.de>
signoff: false
branch: update/postscreen_access.cidr
base: staging
delete-branch: true
add-paths: |
data/conf/postfix/postscreen_access.cidr
title: '[Postfix] update postscreen_access.cidr'
body: |
This PR updates the postscreen_access.cidr using GitHub Actions and [helper-scripts/update_postscreen_whitelist.sh](https://github.com/mailcow/mailcow-dockerized/blob/master/helper-scripts/update_postscreen_whitelist.sh)

45
.gitignore vendored
View File

@@ -1,6 +1,3 @@
!data/conf/nginx/dynmaps.conf
!data/conf/nginx/meta_exporter.conf
!data/conf/nginx/site.conf
!/**/.gitkeep
*.iml
.idea
@@ -8,44 +5,33 @@
data/assets/ssl-example/*
data/assets/ssl/*
data/conf/borgmatic/
data/conf/clamav/whitelist.ign2
data/conf/dovecot/acl_anyone
data/conf/dovecot/dovecot-master.passwd
data/conf/dovecot/dovecot-master.userdb
data/conf/clamav/rendered_configs
data/conf/dovecot/extra.conf
data/conf/dovecot/global_sieve_*
data/conf/dovecot/last_login
data/conf/dovecot/lua
data/conf/dovecot/mail_plugins*
data/conf/dovecot/shared_namespace.conf
data/conf/dovecot/sni.conf
data/conf/dovecot/sogo-sso.conf
data/conf/dovecot/sogo_trusted_ip.conf
data/conf/dovecot/sql
data/conf/nextcloud-*.bak
data/conf/nginx/*.active
data/conf/nginx/*.bak
data/conf/nginx/*.conf
data/conf/nginx/*.custom
data/conf/dovecot/rendered_configs
data/conf/nginx/rendered_configs
data/conf/phpfpm/sogo-sso/sogo-sso.pass
data/conf/phpfpm/rendered_configs
data/conf/portainer/
data/conf/postfix/allow_mailcow_local.regexp
data/conf/postfix/custom_postscreen_whitelist.cidr
data/conf/postfix/custom_transport.pcre
data/conf/postfix/extra.cf
data/conf/postfix/sni.map
data/conf/postfix/sni.map.db
data/conf/postfix/sql
data/conf/postfix/rendered_configs
data/conf/rspamd/custom/*
data/conf/rspamd/local.d/*
data/conf/rspamd/override.d/*
data/conf/rspamd/rendered_configs
data/conf/sogo/custom-theme.js
data/conf/sogo/plist_ldap
data/conf/sogo/sieve.creds
data/conf/sogo/sogo-full.svg
data/conf/sogo/cron.creds
data/conf/sogo/custom-fulllogo.svg
data/conf/sogo/custom-shortlogo.svg
data/conf/sogo/custom-fulllogo.png
data/conf/sogo/rendered_configs
data/conf/mysql/rendered_configs
data/gitea/
data/gogs/
data/hooks/clamd/*
data/hooks/dovecot/*
data/hooks/mariadb/*
data/hooks/nginx/*
data/hooks/phpfpm/*
data/hooks/postfix/*
data/hooks/rspamd/*
@@ -66,3 +52,4 @@ rebuild-images.sh
refresh_images.sh
update_diffs/
create_cold_standby.sh
!data/conf/nginx/mailcow_auth.conf

View File

@@ -1,16 +0,0 @@
sudo: required
services:
- docker
script:
- echo 'Europe/Berlin' | MAILCOW_HOSTNAME=build.mailcow ./generate_config.sh
- docker-compose pull --ignore-pull-failures --parallel
- docker-compose build
- docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD
- docker-compose push
branches:
only:
- master_disabled
env:
global:
- secure: MpxpTwD7f0CNEVLitSpVmocK7O9r+BwFE1deEHK4AlQo/oc9cOlhGe1EL3mx9zbglPmjlDg/8kMUGv6vSirIabfBo9Szjps76bHckFr9lr2Ykkg0e29oC8pgPpSXD1eY/1ZIN/FvIkxpUFLETo1okS/j9q/A0DCGFmti0n3EoMORsgRz9CpNAiEh0zpSd6+euPAGHuczuCrDuO84my9bIOCjA/+aPunHNeXiuM8yIM2SxCSyGtIKT0+jvquIvLF58VxivysXBlRfhDn8fhB09nXA2Ru/derYQACfcmNSn9Pd4bDpebPJW5B9H/XA8xjb58uKinUlncbAMB/QnxoT75j9YRWJZRSQ+34XNYP6ZgK9soZ2TC6djQyEKTUu45Kp/1s+poSn42m9jytJJTmmK0KxsZTRcC8JD5nrjIMZWPUNNTwC5L4+I7ZRWg2WooK3LNyq1Ng8Hn6W77wSgsvAJw2HD3Lx58AprGUhHuBeaIZRuSN9aKwZrl9vKQJLqPnOp/nF2EC6kot5HYYtcotGtETXPUDih21gWD5ZM2BqVqYfQQnJnNMgeYmMdj6QQuTFqhuNJf7hXRIRkTnD3j1gDOLKQZazW0+N2JE8XWDFwi6fKScDsxT85lJti9HmzHa7+k4RVHmUYuDgRoPuzUgjWHvPsiz3/Z8WQ9JYpH84S8w=
- secure: fWzZisT6nGDNL4lf6tXB07eFG2drgBakHxzdF/NFVvzuP861RFR6omuL+ED0PgXrEHDJBxaBLv52je8irmUXrAH1CNr7T8DWiZo/h5h609Uzr+38T1NnIu4krL0Wo6/CDwlLKnzqTq9yBIZLQSHVJmo8AOpo1JPIi2ajodqj9ZfmAxDQTQl+G6zvQjtqIkYHsHY7A44Rto0f14ykn7w2S82Jn6Ry89VNI5V1WEO3sMpM/XekNP/HokNcRIuntL/0+kuLvTJ5akGoTjBQxSnSW95opzPeGky74HRU2obExJYqKvF0VfVJRNAqejwjIiFIbbjqV0Sk5391kFuhuBErQQDM1bOHGdxZ41HsJH29qNWIl7C33Yl10qERoqecgsJ1N/bS2ZEmWqm/zQh5GClCXPvYmzEqMYsMGM3vjbKdjDlc1Wh2w/eFclsXN9LSXh1mc35rtj46frcT6e5Kof87AIfC9hTgDvk9kAsyjaHMkSHSZthbZXCIcsD8qriNm5UqfFBYD79mPIP1S2YMQ2jscCsjHOZgYVrcm0kzDF21J1w6H0Lo7d1jw37LYlegBdtLQ9gYgqY2D5m+nxWuVoD5FZmpR+5JGtK+ootyLFF8aiFoHXd4op1JCxRLjgkmnZKXzw3kTQSpE7oa7CgzchtQmK2nqcqla1b5Qk7ilVcjooo=

View File

@@ -1,9 +1,58 @@
When a problem occurs, then always for a reason! What you want to do in such a case is:
# Contribution Guidelines
**_Last modified on 15th August 2024_**
First of all, thank you for wanting to provide a bugfix or a new feature for the mailcow community, it's because of your help that the project can continue to grow!
As we want to keep mailcow's development structured we setup these Guidelines which helps you to create your issue/pull request accordingly.
**PLEASE NOTE, THAT WE MIGHT CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
## Topics
- [Pull Requests](#pull-requests)
- [Issue Reporting](#issue-reporting)
- [Guidelines](#issue-reporting-guidelines)
- [Issue Report Guide](#issue-report-guide)
## Pull Requests
**_Last modified on 15th August 2024_**
However, please note the following regarding pull requests:
1. **ALWAYS** create your PR using the staging branch of your locally cloned mailcow instance, as the pull request will end up in said staging branch of mailcow once approved. Ideally, you should simply create a new branch for your pull request that is named after the type of your PR (e.g. `feat/` for function updates or `fix/` for bug fixes) and the actual content (e.g. `sogo-6.0.0` for an update from SOGo to version 6 or `html-escape` for a fix that includes escaping HTML in mailcow).
2. **ALWAYS** report/request issues/features in the english language, even though mailcow is a german based company. This is done to allow other GitHub users to reply to your issues/requests too which did not speak german or other languages besides english.
3. Please **keep** this pull request branch **clean** and free of commits that have nothing to do with the changes you have made (e.g. commits from other users from other branches). *If you make changes to the `update.sh` script or other scripts that trigger a commit, there is usually a developer mode for clean working in this case.*
4. **Test your changes before you commit them as a pull request.** <ins>If possible</ins>, write a small **test log** or demonstrate the functionality with a **screenshot or GIF**. *We will of course also test your pull request ourselves, but proof from you will save us the question of whether you have tested your own changes yourself.*
5. **Please use** the pull request template we provide once creating a pull request. *HINT: During editing you encounter comments which looks like: `<!-- CONTENT -->`. These can be removed or kept, as they will not rendered later on GitHub! Please only create actual content without the said comments.*
6. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.*
7. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project.
8. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort!
---
## Issue Reporting
**_Last modified on 15th August 2024_**
If you plan to report a issue within mailcow please read and understand the following rules:
### Issue Reporting Guidelines
1. **ONLY** use the issue tracker for bug reports or improvement requests and NOT for support questions. For support questions you can either contact the [mailcow community on Telegram](https://docs.mailcow.email/#community-support-and-chat) or the mailcow team directly in exchange for a [support fee](https://docs.mailcow.email/#commercial-support).
2. **ONLY** report an error if you have the **necessary know-how (at least the basics)** for the administration of an e-mail server and the usage of Docker. mailcow is a complex and fully-fledged e-mail server including groupware components on a Docker basement and it requires a bit of technical know-how for debugging and operating.
3. **ALWAYS** report/request issues/features in the english language, even though mailcow is a german based company. This is done to allow other GitHub users to reply to your issues/requests too which did not speak german or other languages besides english.
4. **ONLY** report bugs that are contained in the latest mailcow release series. *The definition of the latest release series includes the last major patch (e.g. 2023-12) and all minor patches (revisions) below it (e.g. 2023-12a, b, c etc.).* New issue reports published starting from January 1, 2024 must meet this criterion, as versions below the latest releases are no longer supported by us.
5. When reporting a problem, please be as detailed as possible and include even the smallest changes to your mailcow installation. Simply fill out the corresponding bug report form in detail and accurately to minimize possible questions.
6. **Before you open an issue/feature request**, please first check whether a similar request already exists in the mailcow tracker on GitHub. If so, please include yourself in this request.
7. When you create a issue/feature request: Please note that the creation does <ins>**not guarantee an instant implementation or fix by the mailcow team or the community**</ins>.
8. Please **ALWAYS** anonymize any sensitive information in your bug report or feature request before submitting it.
### Issue Report Guide
1. Read your logs; follow them to see what the reason for your problem is.
2. Follow the leads given to you in your logfiles and start investigating.
3. Restarting the troubled service or the whole stack to see if the problem persists.
4. Read the [documentation](https://mailcow.github.io/mailcow-dockerized-docs/) of the troubled service and search its bugtracker for your problem.
4. Read the [documentation](https://docs.mailcow.email/) of the troubled service and search its bugtracker for your problem.
5. Search our [issues](https://github.com/mailcow/mailcow-dockerized/issues) for your problem.
6. [Create an issue](https://github.com/mailcow/mailcow-dockerized/issues/new/choose) over at our GitHub repository if you think your problem might be a bug or a missing feature you badly need. But please make sure, that you include **all the logs** and a full description to your problem.
7. Ask your questions in our community-driven [support channels](https://mailcow.github.io/mailcow-dockerized-docs/#community-support-and-chat).
7. Ask your questions in our community-driven [support channels](https://docs.mailcow.email/#community-support-and-chat).
## When creating an issue/feature request or a pull request, you will be asked to confirm these guidelines.

View File

@@ -1,9 +1,9 @@
# mailcow: dockerized - 🐮 + 🐋 = 💕
## We stand with 🇺🇦
[![master build status](https://img.shields.io/drone/build/mailcow/mailcow-dockerized/master?label=master%20build&server=https%3A%2F%2Fdrone.mailcow.email)](https://drone.mailcow.email/mailcow/mailcow-dockerized) [![staging build status](https://img.shields.io/drone/build/mailcow/mailcow-dockerized/staging?label=staging%20build&server=https%3A%2F%2Fdrone.mailcow.email)](https://drone.mailcow.email/mailcow/mailcow-dockerized) [![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/)
[![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/)
[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/mailcow_email.svg?style=social&label=Follow%20%40mailcow_email)](https://twitter.com/mailcow_email)
![Mastodon Follow](https://img.shields.io/mastodon/follow/109388212176073348?domain=https%3A%2F%2Fmailcow.social&label=Follow%20%40doncow%40mailcow.social&link=https%3A%2F%2Fmailcow.social%2F%40doncow)
## Want to support mailcow?
@@ -13,9 +13,25 @@ You can also [get a SAL](https://www.servercow.de/mailcow?lang=en#sal) which is
Or just spread the word: moo.
## Many thanks to our GitHub Sponsors ❤️
A big thank you to everyone supporting us on GitHub Sponsors—your contributions mean the world to us! Special thanks to the following amazing supporters:
### 100$/Month Sponsors
<a href="https://www.colba.net/" target=_blank><img
src="https://avatars.githubusercontent.com/u/204464723" height="58"
/></a>
<a href="https://www.maehdros.com/" target=_blank><img
src="https://avatars.githubusercontent.com/u/173894712" height="58"
/></a>
### 50$/Month Sponsors
<a href="https://github.com/vnukhr" target=_blank><img
src="https://avatars.githubusercontent.com/u/7805987?s=52&v=4" height="58"
/></a>
## Info, documentation and support
Please see [the official documentation](https://mailcow.github.io/mailcow-dockerized-docs/) for installation and support instructions. 🐄
Please see [the official documentation](https://docs.mailcow.email/) for installation and support instructions. 🐄
🐛 **If you found a critical security issue, please mail us to [info at servercow.de](mailto:info@servercow.de).**
@@ -27,7 +43,9 @@ Please see [the official documentation](https://mailcow.github.io/mailcow-docker
[Telegram mailcow Off-Topic channel](https://t.me/mailcowOfftopic)
[Official Twitter Account](https://twitter.com/mailcow_email)
[Official 𝕏 (Twitter) Account](https://twitter.com/mailcow_email)
[Official Mastodon Account](https://mailcow.social/@doncow)
Telegram desktop clients are available for [multiple platforms](https://desktop.telegram.org). You can search the groups history for keywords.
@@ -35,3 +53,9 @@ Telegram desktop clients are available for [multiple platforms](https://desktop.
**Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow.
Any part of mailcow itself is released under **GNU General Public License, Version 3**.
mailcow is a registered word mark of The Infrastructure Company GmbH, Parkstr. 42, 47877 Willich, Germany.
The project is managed and maintained by The Infrastructure Company GmbH.
Originated from @andryyy (André)

42
SECURITY.md Normal file
View File

@@ -0,0 +1,42 @@
# Security Policies and Procedures
This document outlines security procedures and general policies for the _mailcow: dockerized_ project as found on [mailcow-dockerized](https://github.com/mailcow/mailcow-dockerized).
* [Reporting a Vulnerability](#reporting-a-vulnerability)
* [Disclosure Policy](#disclosure-policy)
* [Comments on this Policy](#comments-on-this-policy)
## Reporting a Vulnerability
The mailcow team and community take all security vulnerabilities
seriously. Thank you for improving the security of our open source
software. We appreciate your efforts and responsible disclosure and will
make every effort to acknowledge your contributions.
Report security vulnerabilities by emailing the mailcow team at:
info at servercow.de
mailcow team will acknowledge your email as soon as possible, and will
send a more detailed response afterwards indicating the next steps in
handling your report. After the initial reply to your report, the mailcow
team will endeavor to keep you informed of the progress towards a fix and
full announcement, and may ask for additional information or guidance.
Report security vulnerabilities in third-party modules to the person or
team maintaining the module.
## Disclosure Policy
When the mailcow team receives a security bug report, they will assign it
to a primary handler. This person will coordinate the fix and release
process, involving the following steps:
* Confirm the problem and determine the affected versions.
* Audit code to find any potential similar problems.
* Prepare fixes for all releases still under maintenance.
## Comments on this Policy
If you have suggestions on how this process could be improved please submit a
pull request.

0
create_cold_standby.sh Normal file → Executable file
View File

View File

@@ -1,6 +1,6 @@
FROM alpine:3.15
FROM alpine:3.21
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
RUN apk upgrade --no-cache \
&& apk add --update --no-cache \
@@ -14,9 +14,7 @@ RUN apk upgrade --no-cache \
tini \
tzdata \
python3 \
py3-pip \
&& pip3 install --upgrade pip \
&& pip3 install acme-tiny
acme-tiny
COPY acme.sh /srv/acme.sh
COPY functions.sh /srv/functions.sh

View File

@@ -4,9 +4,9 @@ exec 5>&1
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
export REDIS_CMDLINE="redis-cli -h redis -p 6379"
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
@@ -33,6 +33,10 @@ if [[ "${ONLY_MAILCOW_HOSTNAME}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
ONLY_MAILCOW_HOSTNAME=y
fi
if [[ "${AUTODISCOVER_SAN}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
AUTODISCOVER_SAN=y
fi
# Request individual certificate for every domain
if [[ "${ENABLE_SSL_SNI}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
ENABLE_SSL_SNI=y
@@ -113,13 +117,13 @@ fi
chmod 600 ${ACME_BASE}/key.pem
log_f "Waiting for database..."
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent > /dev/null; do
while ! /usr/bin/mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent > /dev/null; do
sleep 2
done
log_f "Database OK"
log_f "Waiting for Nginx..."
until $(curl --output /dev/null --silent --head --fail http://nginx:8081); do
until $(curl --output /dev/null --silent --head --fail http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network:8081); do
sleep 2
done
log_f "Nginx OK"
@@ -133,8 +137,8 @@ log_f "Resolver OK"
# Waiting for domain table
log_f "Waiting for domain table..."
while [[ -z ${DOMAIN_TABLE} ]]; do
curl --silent http://nginx/ >/dev/null 2>&1
DOMAIN_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
curl --silent http://nginx.${COMPOSE_PROJECT_NAME}_mailcow-network/ >/dev/null 2>&1
DOMAIN_TABLE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
[[ -z ${DOMAIN_TABLE} ]] && sleep 10
done
log_f "OK" no_date
@@ -211,17 +215,23 @@ while true; do
ADDITIONAL_SAN_ARR+=($i)
fi
done
ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig')
if [[ ${AUTODISCOVER_SAN} == "y" ]]; then
# Fetch certs for autoconfig and autodiscover subdomains
ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig')
fi
if [[ ${SKIP_IP_CHECK} != "y" ]]; then
# Start IP detection
log_f "Detecting IP addresses..."
IPV4=$(get_ipv4)
IPV6=$(get_ipv6)
log_f "OK: ${IPV4}, ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}"
fi
#########################################
# IP and webroot challenge verification #
SQL_DOMAINS=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs)
SQL_DOMAINS=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 and active=1" -Bs)
if [[ ! $? -eq 0 ]]; then
log_f "Failed to read SQL domains, retrying in 1 minute..."
sleep 1m

View File

@@ -124,7 +124,7 @@ case "$SUCCESS" in
;;
*) # non-zero is non-fun
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
redis-cli -h redis SET ACME_FAIL_TIME "$(date +%s)"
redis-cli -h redis -a ${REDISPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
exit 100${SUCCESS}
;;
esac

View File

@@ -2,32 +2,32 @@
# Reading container IDs
# Wrapping as array to ensure trimmed content when calling $NGINX etc.
NGINX=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"nginx-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
DOVECOT=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"dovecot-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
POSTFIX=($(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
NGINX=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"nginx-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
DOVECOT=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"dovecot-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
POSTFIX=($(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" | tr "\n" " "))
reload_nginx(){
echo "Reloading Nginx..."
NGINX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${NGINX}/exec -d '{"cmd":"reload", "task":"nginx"}' --silent -H 'Content-type: application/json' | jq -r .type)
NGINX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${NGINX}/exec -d '{"cmd":"reload", "task":"nginx"}' --silent -H 'Content-type: application/json' | jq -r .type)
[[ ${NGINX_RELOAD_RET} != 'success' ]] && { echo "Could not reload Nginx, restarting container..."; restart_container ${NGINX} ; }
}
reload_dovecot(){
echo "Reloading Dovecot..."
DOVECOT_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${DOVECOT}/exec -d '{"cmd":"reload", "task":"dovecot"}' --silent -H 'Content-type: application/json' | jq -r .type)
DOVECOT_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${DOVECOT}/exec -d '{"cmd":"reload", "task":"dovecot"}' --silent -H 'Content-type: application/json' | jq -r .type)
[[ ${DOVECOT_RELOAD_RET} != 'success' ]] && { echo "Could not reload Dovecot, restarting container..."; restart_container ${DOVECOT} ; }
}
reload_postfix(){
echo "Reloading Postfix..."
POSTFIX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi/containers/${POSTFIX}/exec -d '{"cmd":"reload", "task":"postfix"}' --silent -H 'Content-type: application/json' | jq -r .type)
POSTFIX_RELOAD_RET=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${POSTFIX}/exec -d '{"cmd":"reload", "task":"postfix"}' --silent -H 'Content-type: application/json' | jq -r .type)
[[ ${POSTFIX_RELOAD_RET} != 'success' ]] && { echo "Could not reload Postfix, restarting container..."; restart_container ${POSTFIX} ; }
}
restart_container(){
for container in $*; do
echo "Restarting ${container}..."
C_REST_OUT=$(curl -X POST --insecure https://dockerapi/containers/${container}/restart --silent | jq -r '.msg')
C_REST_OUT=$(curl -X POST --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${container}/restart --silent | jq -r '.msg')
echo "${C_REST_OUT}"
done
}

View File

@@ -0,0 +1,3 @@
FROM debian:bookworm-slim
RUN apt update && apt install pigz -y --no-install-recommends

View File

@@ -0,0 +1,66 @@
import os
import sys
import signal
import ipaddress
def handle_sigterm(signum, frame):
print("Received SIGTERM, exiting gracefully...")
sys.exit(0)
def get_mysql_config(service_name):
db_config = {
"user": os.getenv("DBUSER") or os.getenv("MYSQL_USER"),
"password": os.getenv("DBPASS") or os.getenv("MYSQL_PASSWORD"),
"database": os.getenv("DBNAME") or os.getenv("MYSQL_DATABASE"),
"connection_timeout": 2,
"service_table": "service_settings",
"service_types": [service_name]
}
db_host = os.getenv("DB_HOST")
if db_host.startswith("/"):
db_config["host"] = "localhost"
db_config["unix_socket"] = db_host
else:
db_config["host"] = db_host
return db_config
def get_redis_config():
redis_config = {
"read_host": os.getenv("REDIS_HOST"),
"read_port": 6379,
"write_host": os.getenv("REDIS_SLAVEOF_IP") or os.getenv("REDIS_HOST"),
"write_port": int(os.getenv("REDIS_SLAVEOF_PORT") or 6379),
"password": os.getenv("REDISPASS"),
"db": 0
}
return redis_config
def main():
signal.signal(signal.SIGTERM, handle_sigterm)
container_name = os.getenv("CONTAINER_NAME")
service_name = container_name.replace("-mailcow", "").replace("-", "")
module_name = f"Bootstrap{service_name.capitalize()}"
try:
mod = __import__(f"modules.{module_name}", fromlist=[module_name])
Bootstrap = getattr(mod, module_name)
except (ImportError, AttributeError) as e:
print(f"Failed to load bootstrap module for: {container_name}{module_name}")
print(str(e))
sys.exit(1)
b = Bootstrap(
container=container_name,
service=service_name,
db_config=get_mysql_config(service_name),
redis_config=get_redis_config()
)
b.bootstrap()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,827 @@
import os
import pwd
import grp
import shutil
import secrets
import string
import subprocess
import time
import socket
import re
import redis
import hashlib
import json
import psutil
import signal
from urllib.parse import quote
from pathlib import Path
import dns.resolver
import mysql.connector
class BootstrapBase:
def __init__(self, container, service, db_config, redis_config):
self.container = container
self.service = service
self.db_config = db_config
self.redis_config = redis_config
self.env = None
self.env_vars = None
self.mysql_conn = None
self.redis_connr = None
self.redis_connw = None
def render_config(self, config_dir):
"""
Renders multiple Jinja2 templates from a config.json file in a given directory.
Args:
config_dir (str or Path): Path to the directory containing config.json
Behavior:
- Renders each template defined in config.json
- Writes the result to the specified output path
- Also copies the rendered file to: <config_dir>/rendered_configs/<relative_output_path>
"""
config_dir = Path(config_dir)
config_path = config_dir / "config.json"
if not config_path.exists():
print(f"config.json not found in: {config_dir}")
return
with config_path.open("r") as f:
entries = json.load(f)
for entry in entries:
template_name = entry["template"]
output_path = Path(entry["output"])
clean_blank_lines = entry.get("clean_blank_lines", False)
if_not_exists = entry.get("if_not_exists", False)
if if_not_exists and output_path.exists():
print(f"Skipping {output_path} (already exists)")
continue
output_path.parent.mkdir(parents=True, exist_ok=True)
try:
template = self.env.get_template(template_name)
except Exception as e:
print(f"Template not found: {template_name} ({e})")
continue
rendered = template.render(self.env_vars)
if clean_blank_lines:
rendered = "\n".join(line for line in rendered.splitlines() if line.strip())
rendered = rendered.replace('\r\n', '\n').replace('\r', '\n')
with output_path.open("w") as f:
f.write(rendered)
rendered_copy_path = config_dir / "rendered_configs" / output_path.name
rendered_copy_path.parent.mkdir(parents=True, exist_ok=True)
self.copy_file(output_path, rendered_copy_path)
print(f"Rendered {template_name}{output_path}")
def prepare_template_vars(self, overwrite_path, extra_vars = None):
"""
Loads and merges environment variables for Jinja2 templates from multiple sources, and registers custom template filters.
This method combines variables from:
1. System environment variables
2. The MySQL `service_settings` table (filtered by service type if defined)
3. An optional `extra_vars` dictionary
4. A JSON overwrite file (if it exists at the given path)
Also registers custom Jinja2 filters.
Args:
overwrite_path (str or Path): Path to a JSON file containing key-value overrides.
extra_vars (dict, optional): Additional variables to merge into the environment.
Returns:
dict: A dictionary containing all resolved template variables.
Raises:
Prints errors if database fetch or JSON parsing fails, but does not raise exceptions.
"""
# 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)
# 3. Load from MySQL
try:
cursor = self.mysql_conn.cursor()
if self.db_config['service_types']:
placeholders = ','.join(['%s'] * len(self.db_config['service_types']))
sql = f"SELECT `key`, `value` FROM {self.db_config['service_table']} WHERE `type` IN ({placeholders})"
cursor.execute(sql, self.db_config['service_types'])
else:
cursor.execute(f"SELECT `key`, `value` FROM {self.db_config['service_table']}")
for key, value in cursor.fetchall():
env_vars[key] = value
cursor.close()
except Exception as e:
print(f"Failed to fetch DB service settings: {e}")
# 4. Load extra vars
if extra_vars:
env_vars.update(extra_vars)
# 5. Load overwrites
overwrite_path = Path(overwrite_path)
if overwrite_path.exists():
try:
with overwrite_path.open("r") as f:
overwrite_data = json.load(f)
env_vars.update(overwrite_data)
except Exception as e:
print(f"Failed to parse overwrites: {e}")
return env_vars
def set_timezone(self):
"""
Sets the system timezone based on the TZ environment variable.
If the TZ variable is set, writes its value to /etc/timezone.
"""
timezone = os.getenv("TZ")
if timezone:
with open("/etc/timezone", "w") as f:
f.write(timezone + "\n")
def set_syslog_redis(self):
"""
Reconfigures syslog-ng to use a Redis slave configuration.
If the REDIS_SLAVEOF_IP environment variable is set, replaces the syslog-ng config
with the Redis slave-specific config.
"""
redis_slave_ip = os.getenv("REDIS_SLAVEOF_IP")
if redis_slave_ip:
shutil.copy("/etc/syslog-ng/syslog-ng-redis_slave.conf", "/etc/syslog-ng/syslog-ng.conf")
def rsync_file(self, src, dst, recursive=False, owner=None, mode=None):
"""
Copies files or directories using rsync, with optional ownership and permissions.
Args:
src (str or Path): Source file or directory.
dst (str or Path): Destination directory.
recursive (bool): If True, copies contents recursively.
owner (tuple): Tuple of (user, group) to set ownership.
mode (int): File mode (e.g., 0o644) to set permissions after sync.
"""
src_path = Path(src)
dst_path = Path(dst)
dst_path.mkdir(parents=True, exist_ok=True)
rsync_cmd = ["rsync", "-a"]
if recursive:
rsync_cmd.append(str(src_path) + "/")
else:
rsync_cmd.append(str(src_path))
rsync_cmd.append(str(dst_path))
try:
subprocess.run(rsync_cmd, check=True)
except Exception as e:
print(f"Rsync failed: {e}")
if owner:
self.set_owner(dst_path, *owner, recursive=True)
if mode:
self.set_permissions(dst_path, mode)
def set_permissions(self, path, mode):
"""
Sets file or directory permissions.
Args:
path (str or Path): Path to the file or directory.
mode (int): File mode to apply, e.g., 0o644.
Raises:
FileNotFoundError: If the path does not exist.
"""
file_path = Path(path)
if not file_path.exists():
raise FileNotFoundError(f"Cannot chmod: {file_path} does not exist")
os.chmod(file_path, mode)
def set_owner(self, path, user, group=None, recursive=False):
"""
Changes ownership of a file or directory.
Args:
path (str or Path): Path to the file or directory.
user (str or int): Username or UID for new owner.
group (str or int, optional): Group name or GID; defaults to user's group if not provided.
recursive (bool): If True and path is a directory, ownership is applied recursively.
Raises:
FileNotFoundError: If the path does not exist.
"""
# Resolve UID
uid = int(user) if str(user).isdigit() else pwd.getpwnam(user).pw_uid
# Resolve GID
if group is not None:
gid = int(group) if str(group).isdigit() else grp.getgrnam(group).gr_gid
else:
gid = uid if isinstance(user, int) or str(user).isdigit() else grp.getgrnam(user).gr_gid
p = Path(path)
if not p.exists():
raise FileNotFoundError(f"{path} does not exist")
if recursive and p.is_dir():
for sub_path in p.rglob("*"):
os.chown(sub_path, uid, gid)
os.chown(p, uid, gid)
def fix_permissions(self, path, user=None, group=None, mode=None, recursive=False):
"""
Sets owner and/or permissions on a file or directory.
Args:
path (str or Path): Target path.
user (str|int, optional): Username or UID.
group (str|int, optional): Group name or GID.
mode (int, optional): File mode (e.g. 0o644).
recursive (bool): Apply recursively if path is a directory.
"""
if user or group:
self.set_owner(path, user, group, recursive)
if mode:
self.set_permissions(path, mode)
def move_file(self, src, dst, overwrite=True):
"""
Moves a file from src to dst, optionally overwriting existing files.
Args:
src (str or Path): Source file path.
dst (str or Path): Destination path.
overwrite (bool): If False, raises error if dst exists.
Raises:
FileNotFoundError: If the source file does not exist.
FileExistsError: If the destination file exists and overwrite is False.
"""
src_path = Path(src)
dst_path = Path(dst)
if not src_path.exists():
raise FileNotFoundError(f"Source file does not exist: {src}")
dst_path.parent.mkdir(parents=True, exist_ok=True)
if dst_path.exists() and not overwrite:
raise FileExistsError(f"Destination already exists: {dst} (set overwrite=True to overwrite)")
shutil.move(str(src_path), str(dst_path))
def copy_file(self, src, dst, overwrite=True):
"""
Copies a file from src to dst using shutil.
Args:
src (str or Path): Source file path.
dst (str or Path): Destination file path.
overwrite (bool): Whether to overwrite the destination if it exists.
Raises:
FileNotFoundError: If the source file doesn't exist.
FileExistsError: If the destination exists and overwrite is False.
IOError: If the copy operation fails.
"""
src_path = Path(src)
dst_path = Path(dst)
if not src_path.is_file():
raise FileNotFoundError(f"Source file not found: {src_path}")
if dst_path.exists() and not overwrite:
raise FileExistsError(f"Destination exists: {dst_path}")
dst_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src_path, dst_path)
def remove(self, path, recursive=False, wipe_contents=False, exclude=None):
"""
Removes a file or directory with optional exclusion logic.
Args:
path (str or Path): The file or directory path to remove.
recursive (bool): If True, directories will be removed recursively.
wipe_contents (bool): If True and path is a directory, only its contents are removed, not the dir itself.
exclude (list[str], optional): List of filenames to exclude from deletion.
Raises:
FileNotFoundError: If the path does not exist.
ValueError: If a directory is passed without recursive or wipe_contents.
"""
path = Path(path)
exclude = set(exclude or [])
if not path.exists():
raise FileNotFoundError(f"Cannot remove: {path} does not exist")
if wipe_contents and path.is_dir():
for child in path.iterdir():
if child.name in exclude:
continue
if child.is_dir():
shutil.rmtree(child)
else:
child.unlink()
elif path.is_file():
if path.name not in exclude:
path.unlink()
elif path.is_dir():
if recursive:
shutil.rmtree(path)
else:
raise ValueError(f"{path} is a directory. Use recursive=True or wipe_contents=True to remove it.")
def create_dir(self, path):
"""
Creates a directory if it does not exist.
If the directory is missing, it will be created along with any necessary parent directories.
Args:
path (str or Path): The directory path to create.
"""
dir_path = Path(path)
if not dir_path.exists():
print(f"Creating directory: {dir_path}")
dir_path.mkdir(parents=True, exist_ok=True)
def patch_exists(self, target_file, patch_file, reverse=False):
"""
Checks whether a patch can be applied (or reversed) to a target file.
Args:
target_file (str): File to test the patch against.
patch_file (str): Patch file to apply.
reverse (bool): If True, checks whether the patch can be reversed.
Returns:
bool: True if patch is applicable, False otherwise.
"""
cmd = ["patch", "-sfN", "--dry-run", target_file, "<", patch_file]
if reverse:
cmd.insert(1, "-R")
try:
result = subprocess.run(
" ".join(cmd),
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
return result.returncode == 0
except Exception as e:
print(f"Patch dry-run failed: {e}")
return False
def apply_patch(self, target_file, patch_file, reverse=False):
"""
Applies a patch file to a target file.
Args:
target_file (str): File to be patched.
patch_file (str): Patch file containing the diff.
reverse (bool): If True, applies the patch in reverse (rollback).
Logs:
Success or failure of the patching operation.
"""
cmd = ["patch", target_file, "<", patch_file]
if reverse:
cmd.insert(0, "-R")
try:
subprocess.run(" ".join(cmd), shell=True, check=True)
print(f"Applied patch {'(reverse)' if reverse else ''} to {target_file}")
except subprocess.CalledProcessError as e:
print(f"Patch failed: {e}")
def isYes(self, value):
"""
Determines whether a given string represents a "yes"-like value.
Args:
value (str): Input string to evaluate.
Returns:
bool: True if value is "yes" or "y" (case-insensitive), otherwise False.
"""
return value.lower() in ["yes", "y"]
def is_port_open(self, host, port):
"""
Checks whether a TCP port is open on a given host.
Args:
host (str): The hostname or IP address to check.
port (int): The TCP port number to test.
Returns:
bool: True if the port is open and accepting connections, False otherwise.
"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(1)
result = sock.connect_ex((host, port))
return result == 0
def resolve_docker_dns_record(self, hostname, record_type="A"):
"""
Resolves DNS A or AAAA records for a given hostname.
Args:
hostname (str): The domain to query.
record_type (str): "A" for IPv4, "AAAA" for IPv6. Default is "A".
Returns:
list[str]: A list of resolved IP addresses.
Raises:
Exception: If resolution fails or no results are found.
"""
try:
resolver = dns.resolver.Resolver()
resolver.nameservers = ["127.0.0.11"]
answers = resolver.resolve(hostname, record_type)
return [answer.to_text() for answer in answers]
except Exception as e:
raise Exception(f"Failed to resolve {record_type} record for {hostname}: {e}")
def kill_proc(self, process_name):
"""
Sends SIGTERM to all running processes matching the given name.
Args:
process_name (str): Name of the process to terminate.
Returns:
int: Number of processes successfully signaled.
"""
killed = 0
for proc in psutil.process_iter(['name']):
try:
if proc.info['name'] == process_name:
proc.send_signal(signal.SIGTERM)
killed += 1
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
return killed
def connect_mysql(self, socket=None):
"""
Establishes a connection to the MySQL database using the provided configuration.
Continuously retries the connection until the database is reachable. Stores
the connection in `self.mysql_conn` once successful.
Logs:
Connection status and retry errors to stdout.
Args:
socket (str, optional): Custom UNIX socket path to override the default.
"""
print("Connecting to MySQL...")
config = {
"host": self.db_config['host'],
"user": self.db_config['user'],
"password": self.db_config['password'],
"database": self.db_config['database'],
'connection_timeout': self.db_config['connection_timeout']
}
if self.db_config['unix_socket']:
config["unix_socket"] = socket or self.db_config['unix_socket']
while True:
try:
self.mysql_conn = mysql.connector.connect(**config)
if self.mysql_conn.is_connected():
print("MySQL is up and ready!")
break
except mysql.connector.Error as e:
print(f"Waiting for MySQL... ({e})")
time.sleep(2)
def close_mysql(self):
"""
Closes the MySQL connection if it's currently open and connected.
Safe to call even if the connection has already been closed.
"""
if self.mysql_conn and self.mysql_conn.is_connected():
self.mysql_conn.close()
def connect_redis(self, max_retries=10, delay=2):
"""
Connects to both read and write Redis servers and stores the connections.
Read server: tries indefinitely until successful.
Write server: tries up to `max_retries` before giving up.
Sets:
self.redis_connr: Redis client for read
self.redis_connw: Redis client for write
"""
use_rw = self.redis_config['read_host'] == self.redis_config['write_host'] and self.redis_config['read_port'] == self.redis_config['write_port']
if use_rw:
print("Connecting to Redis read server...")
else:
print("Connecting to Redis server...")
while True:
try:
clientr = redis.Redis(
host=self.redis_config['read_host'],
port=self.redis_config['read_port'],
password=self.redis_config['password'],
db=self.redis_config['db'],
decode_responses=True
)
if clientr.ping():
self.redis_connr = clientr
print("Redis read server is up and ready!")
if use_rw:
break
else:
self.redis_connw = clientr
return
except redis.RedisError as e:
print(f"Waiting for Redis read... ({e})")
time.sleep(delay)
print("Connecting to Redis write server...")
for attempt in range(max_retries):
try:
clientw = redis.Redis(
host=self.redis_config['write_host'],
port=self.redis_config['write_port'],
password=self.redis_config['password'],
db=self.redis_config['db'],
decode_responses=True
)
if clientw.ping():
self.redis_connw = clientw
print("Redis write server is up and ready!")
return
except redis.RedisError as e:
print(f"Waiting for Redis write... (attempt {attempt + 1}/{max_retries}) ({e})")
time.sleep(delay)
print("Redis write server is unreachable.")
def close_redis(self):
"""
Closes the Redis read/write connections if open.
"""
if self.redis_connr:
try:
self.redis_connr.close()
except Exception as e:
print(f"Error while closing Redis read connection: {e}")
finally:
self.redis_connr = None
if self.redis_connw:
try:
self.redis_connw.close()
except Exception as e:
print(f"Error while closing Redis write connection: {e}")
finally:
self.redis_connw = None
def wait_for_schema_update(self, init_file_path="init_db.inc.php", check_interval=5):
"""
Waits until the current database schema version matches the expected version
defined in a PHP initialization file.
Compares the `version` value in the `versions` table for `application = 'db_schema'`
with the `$db_version` value extracted from the specified PHP file.
Args:
init_file_path (str): Path to the PHP file containing the expected version string.
check_interval (int): Time in seconds to wait between version checks.
Logs:
Current vs. expected schema versions until they match.
"""
print("Checking database schema version...")
while True:
current_version = self._get_current_db_version()
expected_version = self._get_expected_schema_version(init_file_path)
if current_version == expected_version:
print(f"DB schema is up to date: {current_version}")
break
print(f"Waiting for schema update... (DB: {current_version}, Expected: {expected_version})")
time.sleep(check_interval)
def wait_for_host(self, host, retry_interval=1.0, count=1):
"""
Waits for a host to respond to ICMP ping.
Args:
host (str): Hostname or IP to ping.
retry_interval (float): Seconds to wait between pings.
count (int): Number of ping packets to send per check (default 1).
"""
while True:
try:
result = subprocess.run(
["ping", "-c", str(count), host],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
if result.returncode == 0:
print(f"{host} is reachable via ping.")
break
except Exception:
pass
print(f"Waiting for {host}...")
time.sleep(retry_interval)
def wait_for_dns(self, domain, retry_interval=1, timeout=30):
"""
Waits until the domain resolves via DNS using pure Python (socket).
Args:
domain (str): The domain to resolve.
retry_interval (int): Time (seconds) to wait between attempts.
timeout (int): Maximum total wait time (seconds).
Returns:
bool: True if resolved, False if timed out.
"""
start = time.time()
while True:
try:
socket.gethostbyname(domain)
print(f"{domain} is resolving via DNS.")
return True
except socket.gaierror:
pass
if time.time() - start > timeout:
print(f"DNS resolution for {domain} timed out.")
return False
print(f"Waiting for DNS for {domain}...")
time.sleep(retry_interval)
def _get_current_db_version(self):
"""
Fetches the current schema version from the database.
Executes a SELECT query on the `versions` table where `application = 'db_schema'`.
Returns:
str or None: The current schema version as a string, or None if not found or on error.
Logs:
Error message if the query fails.
"""
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SELECT version FROM versions WHERE application = 'db_schema'")
result = cursor.fetchone()
cursor.close()
return result[0] if result else None
except Exception as e:
print(f"Error fetching current DB schema version: {e}")
return None
def _get_expected_schema_version(self, filepath):
"""
Extracts the expected database schema version from a PHP initialization file.
Looks for a line in the form of: `$db_version = "..."` and extracts the version string.
Args:
filepath (str): Path to the PHP file containing the `$db_version` definition.
Returns:
str or None: The extracted version string, or None if not found or on error.
Logs:
Error message if the file cannot be read or parsed.
"""
try:
with open(filepath, "r") as f:
content = f.read()
match = re.search(r'\$db_version\s*=\s*"([^"]+)"', content)
if match:
return match.group(1)
except Exception as e:
print(f"Error reading expected schema version from {filepath}: {e}")
return None
def rand_pass(self, length=22):
"""
Generates a secure random password using allowed characters.
Allowed characters include upper/lowercase letters, digits, underscores, and hyphens.
Args:
length (int): Length of the password to generate. Default is 22.
Returns:
str: A securely generated random password string.
"""
allowed_chars = string.ascii_letters + string.digits + "_-"
return ''.join(secrets.choice(allowed_chars) for _ in range(length))
def run_command(self, command, check=True, shell=False, input_stream=None, log_output=True):
"""
Executes a shell command and optionally logs output.
Args:
command (str or list): Command to run.
check (bool): Raise if non-zero exit.
shell (bool): Run in shell.
input_stream: stdin stream.
log_output (bool): If True, print output.
Returns:
subprocess.CompletedProcess
"""
try:
result = subprocess.run(
command,
shell=shell,
check=check,
stdin=input_stream,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if log_output:
if result.stdout:
print(result.stdout.strip())
if result.stderr:
print(result.stderr.strip())
return result
except subprocess.CalledProcessError as e:
print(f"Command failed with exit code {e.returncode}: {e.cmd}")
print(e.stderr.strip())
if check:
raise
return e
def sha1_filter(self, value):
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

@@ -0,0 +1,60 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
from pathlib import Path
import os
import sys
import time
class BootstrapClamd(BootstrapBase):
def bootstrap(self):
# Skip Clamd if set
if self.isYes(os.getenv("SKIP_CLAMD", "")):
print("SKIP_CLAMD is set, skipping ClamAV startup...")
time.sleep(365 * 24 * 60 * 60)
sys.exit(1)
# Connect to MySQL
self.connect_mysql()
print("Cleaning up tmp files...")
tmp_files = Path("/var/lib/clamav").glob("clamav-*.tmp")
for tmp_file in tmp_files:
try:
self.remove(tmp_file)
print(f"Removed: {tmp_file}")
except Exception as e:
print(f"Failed to remove {tmp_file}: {e}")
self.create_dir("/run/clamav")
self.create_dir("/var/lib/clamav")
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Render config")
self.render_config("/service_config")
# Fix permissions
self.set_owner("/var/lib/clamav", "clamav", "clamav", recursive=True)
self.set_owner("/run/clamav", "clamav", "clamav", recursive=True)
self.set_permissions("/var/lib/clamav", 0o755)
for item in Path("/var/lib/clamav").glob("*"):
self.set_permissions(item, 0o644)
self.set_permissions("/run/clamav", 0o750)
# Copying to /etc/clamav to expose file as-is to administrator
self.copy_file("/var/lib/clamav/whitelist.ign2", "/etc/clamav/whitelist.ign2")

View File

@@ -0,0 +1,289 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
from pathlib import Path
import os
import pwd
import hashlib
class BootstrapDovecot(BootstrapBase):
def bootstrap(self):
# Connect to MySQL
self.connect_mysql()
self.wait_for_schema_update()
# Connect to Redis
self.connect_redis()
if self.redis_connw:
self.redis_connw.set("DOVECOT_REPL_HEALTH", 1)
# Wait for DNS
self.wait_for_dns("mailcow.email")
# Create missing directories
self.create_dir("/etc/dovecot/sql/")
self.create_dir("/etc/dovecot/auth/")
self.create_dir("/var/vmail/_garbage")
self.create_dir("/var/vmail/sieve")
self.create_dir("/etc/sogo")
self.create_dir("/var/volatile")
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
"VALID_CERT_DIRS": self.get_valid_cert_dirs(),
"RAND_USER": self.rand_pass(),
"RAND_PASS": self.rand_pass(),
"RAND_PASS2": self.rand_pass(),
"ENV_VARS": dict(os.environ)
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Render config")
self.render_config("/service_config")
files = [
"/etc/dovecot/mail_plugins",
"/etc/dovecot/mail_plugins_imap",
"/etc/dovecot/mail_plugins_lmtp",
"/templates/quarantine.tpl"
]
for file in files:
self.set_permissions(file, 0o644)
try:
# Migrate old sieve_after file
self.move_file("/etc/dovecot/sieve_after", "/var/vmail/sieve/global_sieve_after.sieve")
except Exception as e:
pass
try:
# Cleanup random user maildirs
self.remove("/var/vmail/mailcow.local", wipe_contents=True)
except Exception as e:
pass
try:
# Cleanup PIDs
self.remove("/tmp/quarantine_notify.pid")
except Exception as e:
pass
try:
self.remove("/var/run/dovecot/master.pid")
except Exception as e:
pass
# Check permissions of vmail/index/garbage directories.
# Do not do this every start-up, it may take a very long time. So we use a stat check here.
files = [
"/var/vmail",
"/var/vmail/_garbage",
"/var/vmail_index"
]
for file in files:
path = Path(file)
try:
stat_info = path.stat()
current_user = pwd.getpwuid(stat_info.st_uid).pw_name
if current_user != "vmail":
print(f"Ownership of {path} is {current_user}, fixing to vmail:vmail...")
self.set_owner(path, user="vmail", group="vmail", recursive=True)
else:
print(f"Ownership of {path} is already correct (vmail)")
except Exception as e:
print(f"Error checking ownership of {path}: {e}")
# Compile sieve scripts
files = [
"/var/vmail/sieve/global_sieve_before.sieve",
"/var/vmail/sieve/global_sieve_after.sieve",
"/usr/lib/dovecot/sieve/report-spam.sieve",
"/usr/lib/dovecot/sieve/report-ham.sieve",
]
for file in files:
self.run_command(["sievec", file], check=False)
# Fix permissions
for path in Path("/etc/dovecot/sql").glob("*.conf"):
self.set_owner(path, "root", "root")
self.set_permissions(path, 0o640)
files = [
"/etc/dovecot/auth/passwd-verify.lua",
*Path("/etc/dovecot/sql").glob("dovecot-dict-sql-sieve*"),
*Path("/etc/dovecot/sql").glob("dovecot-dict-sql-quota*")
]
for file in files:
self.set_owner(file, "root", "dovecot")
self.set_permissions("/etc/dovecot/auth/passwd-verify.lua", 0o640)
for file in ["/var/vmail/sieve", "/var/volatile", "/var/vmail_index"]:
self.set_owner(file, "vmail", "vmail", recursive=True)
self.run_command(["adduser", "vmail", "tty"])
self.run_command(["chmod", "g+rw", "/dev/console"])
self.set_owner("/dev/console", "root", "tty")
files = [
"/usr/lib/dovecot/sieve/rspamd-pipe-ham",
"/usr/lib/dovecot/sieve/rspamd-pipe-spam",
"/usr/local/bin/imapsync_runner.pl",
"/usr/local/bin/imapsync",
"/usr/local/bin/trim_logs.sh",
"/usr/local/bin/sa-rules.sh",
"/usr/local/bin/clean_q_aged.sh",
"/usr/local/bin/maildir_gc.sh",
"/usr/local/sbin/stop-supervisor.sh",
"/usr/local/bin/quota_notify.py",
"/usr/local/bin/repl_health.sh",
"/usr/local/bin/optimize-fts.sh"
]
for file in files:
self.set_permissions(file, 0o755)
# Collect SA rules once now
self.run_command(["/usr/local/bin/sa-rules.sh"], check=False)
self.generate_mail_crypt_keys()
self.cleanup_imapsync_jobs()
self.generate_guid_version()
def get_valid_cert_dirs(self):
"""
Returns a mapping of domains to their certificate directory path.
Example:
{
"example.com": "/etc/ssl/mail/example.com/",
"www.example.com": "/etc/ssl/mail/example.com/"
}
"""
sni_map = {}
base_path = Path("/etc/ssl/mail")
if not base_path.exists():
return sni_map
for cert_dir in base_path.iterdir():
if not cert_dir.is_dir():
continue
domains_file = cert_dir / "domains"
cert_file = cert_dir / "cert.pem"
key_file = cert_dir / "key.pem"
if not (domains_file.exists() and cert_file.exists() and key_file.exists()):
continue
with open(domains_file, "r") as f:
domains = [line.strip() for line in f if line.strip()]
for domain in domains:
sni_map[domain] = str(cert_dir)
return sni_map
def generate_mail_crypt_keys(self):
"""
Ensures mail_crypt EC keypair exists. Generates if missing. Adjusts permissions.
"""
key_dir = Path("/mail_crypt")
priv_key = key_dir / "ecprivkey.pem"
pub_key = key_dir / "ecpubkey.pem"
# Generate keys if they don't exist or are empty
if not priv_key.exists() or priv_key.stat().st_size == 0 or \
not pub_key.exists() or pub_key.stat().st_size == 0:
self.run_command(
"openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem",
shell=True
)
self.run_command(
"openssl pkey -in /mail_crypt/ecprivkey.pem -pubout -out /mail_crypt/ecpubkey.pem",
shell=True
)
# Set ownership to UID 401 (dovecot)
self.set_owner(priv_key, user='401')
self.set_owner(pub_key, user='401')
def cleanup_imapsync_jobs(self):
"""
Cleans up stale imapsync locks and resets running status in the database.
Deletes the imapsync_busy.lock file if present and sets `is_running` to 0
in the `imapsync` table, if it exists.
Logs:
Any issues with file operations or SQL execution.
"""
lock_file = Path("/tmp/imapsync_busy.lock")
if lock_file.exists():
try:
lock_file.unlink()
except Exception as e:
print(f"Failed to remove lock file: {e}")
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SHOW TABLES LIKE 'imapsync'")
result = cursor.fetchone()
if result:
cursor.execute("UPDATE imapsync SET is_running='0'")
self.mysql_conn.commit()
cursor.close()
except Exception as e:
print(f"Error updating imapsync table: {e}")
def generate_guid_version(self):
"""
Waits for the `versions` table to be created, then generates a GUID
based on the mail hostname and Dovecot's public key and inserts it
into the `versions` table.
If the key or hash is missing or malformed, marks it as INVALID.
"""
try:
result = self.run_command(["doveconf", "-P"], check=True, log_output=False)
pubkey_path = None
for line in result.stdout.splitlines():
if "mail_crypt_global_public_key" in line:
parts = line.split('<')
if len(parts) > 1:
pubkey_path = parts[1].strip()
break
if pubkey_path and Path(pubkey_path).exists():
with open(pubkey_path, "rb") as key_file:
pubkey_data = key_file.read()
hostname = self.env_vars.get("MAILCOW_HOSTNAME", "mailcow.local").encode("utf-8")
concat = hostname + pubkey_data
guid = hashlib.sha256(concat).hexdigest()
if len(guid) == 64:
version_value = guid
else:
version_value = "INVALID"
cursor = self.mysql_conn.cursor()
cursor.execute(
"REPLACE INTO versions (application, version) VALUES (%s, %s)",
("GUID", version_value)
)
self.mysql_conn.commit()
cursor.close()
else:
print("Public key not found or unreadable. GUID not generated.")
except Exception as e:
print(f"Failed to generate or store GUID: {e}")

View File

@@ -0,0 +1,163 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
import os
import time
import subprocess
class BootstrapMysql(BootstrapBase):
def bootstrap(self):
dbuser = "root"
dbpass = os.getenv("MYSQL_ROOT_PASSWORD", "")
socket = "/tmp/mysql-temp.sock"
# Check if mysql has been initialized
if os.path.exists("/var/lib/mysql/mysql/db.frm"):
print("Starting temporary mysqld for upgrade...")
self.start_temporary(socket)
self.connect_mysql(socket)
print("Running mysql_upgrade...")
self.upgrade_mysql(dbuser, dbpass, socket)
print("Checking timezone support with CONVERT_TZ...")
self.check_and_import_timezone_support(dbuser, dbpass, socket)
print("Shutting down temporary mysqld...")
self.close_mysql()
self.stop_temporary(dbuser, dbpass, socket)
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Render config")
self.render_config("/service_config")
def start_temporary(self, socket):
"""
Starts a temporary mysqld process in the background using the given UNIX socket.
The server is started with networking disabled (--skip-networking).
Args:
socket (str): Path to the UNIX socket file for MySQL to listen on.
Returns:
subprocess.Popen: The running mysqld process object.
"""
return subprocess.Popen([
"mysqld",
"--user=mysql",
"--skip-networking",
f"--socket={socket}"
])
def stop_temporary(self, dbuser, dbpass, socket):
"""
Shuts down the temporary mysqld instance gracefully.
Uses mariadb-admin to issue a shutdown command to the running server.
Args:
dbuser (str): The MySQL username with shutdown privileges (typically 'root').
dbpass (str): The password for the MySQL user.
socket (str): Path to the UNIX socket the server is listening on.
"""
self.run_command([
"mariadb-admin",
"shutdown",
f"--socket={socket}",
"-u", dbuser,
f"-p{dbpass}"
])
def upgrade_mysql(self, dbuser, dbpass, socket, max_retries=5, wait_interval=3):
"""
Executes mysql_upgrade to check and fix any schema or table incompatibilities.
Retries the upgrade command if it fails, up to a maximum number of attempts.
Args:
dbuser (str): MySQL username with privilege to perform the upgrade.
dbpass (str): Password for the MySQL user.
socket (str): Path to the MySQL UNIX socket for local communication.
max_retries (int): Maximum number of attempts before giving up. Default is 5.
wait_interval (int): Number of seconds to wait between retries. Default is 3.
Returns:
bool: True if upgrade succeeded, False if all attempts failed.
"""
retries = 0
while retries < max_retries:
result = self.run_command([
"mysql_upgrade",
"-u", dbuser,
f"-p{dbpass}",
f"--socket={socket}"
], check=False)
if result.returncode == 0:
print("mysql_upgrade completed successfully.")
break
else:
print(f"mysql_upgrade failed (try {retries+1}/{max_retries})")
retries += 1
time.sleep(wait_interval)
else:
print("mysql_upgrade failed after all retries.")
return False
def check_and_import_timezone_support(self, dbuser, dbpass, socket):
"""
Checks if MySQL supports timezone conversion (CONVERT_TZ).
If not, it imports timezone info using mysql_tzinfo_to_sql piped into mariadb.
"""
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC')")
result = cursor.fetchone()
cursor.close()
if not result or result[0] is None:
print("Timezone conversion failed or returned NULL. Importing timezone info...")
# Use mysql_tzinfo_to_sql piped into mariadb
tz_dump = subprocess.Popen(
["mysql_tzinfo_to_sql", "/usr/share/zoneinfo"],
stdout=subprocess.PIPE
)
self.run_command([
"mariadb",
"--socket", socket,
"-u", dbuser,
f"-p{dbpass}",
"mysql"
], input_stream=tz_dump.stdout)
tz_dump.stdout.close()
tz_dump.wait()
print("Timezone info successfully imported.")
else:
print(f"Timezone support is working. Sample result: {result[0]}")
except Exception as e:
print(f"Failed to verify or import timezone info: {e}")

View File

@@ -0,0 +1,65 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
import os
class BootstrapNginx(BootstrapBase):
def bootstrap(self):
# Connect to MySQL
self.connect_mysql()
# wait for Hosts
php_service = os.getenv("PHPFPM_HOST") or "php-fpm-mailcow"
rspamd_service = os.getenv("RSPAMD_HOST") or "rspamd-mailcow"
sogo_service = os.getenv("SOGO_HOST")
self.wait_for_host(php_service)
if not self.isYes(os.getenv("SKIP_RSPAMD", False)):
self.wait_for_host(rspamd_service)
if not self.isYes(os.getenv("SKIP_SOGO", False)):
self.wait_for_host(sogo_service)
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
"VALID_CERT_DIRS": self.get_valid_cert_dirs(),
'TRUSTED_PROXIES': [item.strip() for item in os.getenv("TRUSTED_PROXIES", "").split(",") if item.strip()],
'ADDITIONAL_SERVER_NAMES': [item.strip() for item in os.getenv("ADDITIONAL_SERVER_NAMES", "").split(",") if item.strip()],
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Render config")
self.render_config("/service_config")
def get_valid_cert_dirs(self):
ssl_dir = '/etc/ssl/mail/'
valid_cert_dirs = []
for d in os.listdir(ssl_dir):
full_path = os.path.join(ssl_dir, d)
if not os.path.isdir(full_path):
continue
cert_path = os.path.join(full_path, 'cert.pem')
key_path = os.path.join(full_path, 'key.pem')
domains_path = os.path.join(full_path, 'domains')
if os.path.isfile(cert_path) and os.path.isfile(key_path) and os.path.isfile(domains_path):
with open(domains_path, 'r') as file:
domains = file.read().strip()
domains_list = domains.split()
if domains_list and os.getenv("MAILCOW_HOSTNAME", "") not in domains_list:
valid_cert_dirs.append({
'cert_path': full_path + '/',
'domains': domains
})
return valid_cert_dirs

View File

@@ -0,0 +1,202 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
import os
import ipaddress
class BootstrapPhpfpm(BootstrapBase):
def bootstrap(self):
self.connect_mysql()
self.connect_redis()
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
# Prepare Redis and MySQL Database
# TODO: move to dockerapi
if self.isYes(os.getenv("MASTER", "")):
print("We are master, preparing...")
self.prepare_redis()
self.setup_apikeys(
os.getenv("API_ALLOW_FROM", "").strip(),
os.getenv("API_KEY", "").strip(),
os.getenv("API_KEY_READ_ONLY", "").strip()
)
self.setup_mysql_events()
print("Render config")
self.render_config("/service_config")
self.copy_file("/usr/local/etc/php/conf.d/opcache-recommended.ini", "/php-conf/opcache-recommended.ini")
self.copy_file("/usr/local/etc/php-fpm.d/z-pools.conf", "/php-conf/pools.conf")
self.copy_file("/usr/local/etc/php/conf.d/zzz-other.ini", "/php-conf/other.ini")
self.copy_file("/usr/local/etc/php/conf.d/upload.ini", "/php-conf/upload.ini")
self.copy_file("/usr/local/etc/php/conf.d/session_store.ini", "/php-conf/session_store.ini")
self.set_owner("/global_sieve", 82, 82, recursive=True)
self.set_owner("/web/templates/cache", 82, 82, recursive=True)
self.remove("/web/templates/cache", wipe_contents=True, exclude=[".gitkeep"])
print("Running DB init...")
self.run_command(["php", "-c", "/usr/local/etc/php", "-f", "/web/inc/init_db.inc.php"], check=False)
def prepare_redis(self):
print("Setting default Redis keys if missing...")
# Q_RELEASE_FORMAT
if self.redis_connw and self.redis_connr.get("Q_RELEASE_FORMAT") is None:
self.redis_connw.set("Q_RELEASE_FORMAT", "raw")
# Q_MAX_AGE
if self.redis_connw and self.redis_connr.get("Q_MAX_AGE") is None:
self.redis_connw.set("Q_MAX_AGE", 365)
# PASSWD_POLICY hash defaults
if self.redis_connw and self.redis_connr.hget("PASSWD_POLICY", "length") is None:
self.redis_connw.hset("PASSWD_POLICY", mapping={
"length": 6,
"chars": 0,
"special_chars": 0,
"lowerupper": 0,
"numbers": 0
})
# DOMAIN_MAP
print("Rebuilding DOMAIN_MAP from MySQL...")
if self.redis_connw:
self.redis_connw.delete("DOMAIN_MAP")
domains = set()
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SELECT domain FROM domain")
domains.update(row[0] for row in cursor.fetchall())
cursor.execute("SELECT alias_domain FROM alias_domain")
domains.update(row[0] for row in cursor.fetchall())
cursor.close()
if domains:
for domain in domains:
if self.redis_connw:
self.redis_conn.hset("DOMAIN_MAP", domain, 1)
print(f"{len(domains)} domains added to DOMAIN_MAP.")
else:
print("No domains found to insert into DOMAIN_MAP.")
except Exception as e:
print(f"Failed to rebuild DOMAIN_MAP: {e}")
def setup_apikeys(self, api_allow_from, api_key_rw, api_key_ro):
if not api_allow_from or api_allow_from == "invalid":
return
print("Validating API_ALLOW_FROM IPs...")
ip_list = [ip.strip() for ip in api_allow_from.split(",")]
validated_ips = []
for ip in ip_list:
try:
ipaddress.ip_network(ip, strict=False)
validated_ips.append(ip)
except ValueError:
continue
if not validated_ips:
print("No valid IPs found in API_ALLOW_FROM")
return
allow_from_str = ",".join(validated_ips)
cursor = self.mysql_conn.cursor()
try:
if api_key_rw and api_key_rw != "invalid":
print("Setting RW API key...")
cursor.execute("DELETE FROM api WHERE access = 'rw'")
cursor.execute(
"INSERT INTO api (api_key, active, allow_from, access) VALUES (%s, %s, %s, %s)",
(api_key_rw, 1, allow_from_str, "rw")
)
if api_key_ro and api_key_ro != "invalid":
print("Setting RO API key...")
cursor.execute("DELETE FROM api WHERE access = 'ro'")
cursor.execute(
"INSERT INTO api (api_key, active, allow_from, access) VALUES (%s, %s, %s, %s)",
(api_key_ro, 1, allow_from_str, "ro")
)
self.mysql_conn.commit()
print("API key(s) set successfully.")
except Exception as e:
print(f"Failed to configure API keys: {e}")
self.mysql_conn.rollback()
finally:
cursor.close()
def setup_mysql_events(self):
print("Creating scheduled MySQL EVENTS...")
queries = [
"DROP EVENT IF EXISTS clean_spamalias;",
"""
CREATE EVENT clean_spamalias
ON SCHEDULE EVERY 1 DAY
DO
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
""",
"DROP EVENT IF EXISTS clean_oauth2;",
"""
CREATE EVENT clean_oauth2
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
DELETE FROM oauth_refresh_tokens WHERE expires < NOW();
DELETE FROM oauth_access_tokens WHERE expires < NOW();
DELETE FROM oauth_authorization_codes WHERE expires < NOW();
END;
""",
"DROP EVENT IF EXISTS clean_sasl_log;",
"""
CREATE EVENT clean_sasl_log
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
DELETE sasl_log.* FROM sasl_log
LEFT JOIN (
SELECT username, service, MAX(datetime) AS lastdate
FROM sasl_log
GROUP BY username, service
) AS last
ON sasl_log.username = last.username AND sasl_log.service = last.service
WHERE datetime < DATE_SUB(NOW(), INTERVAL 31 DAY)
AND datetime < lastdate;
DELETE FROM sasl_log
WHERE username NOT IN (SELECT username FROM mailbox)
AND datetime < DATE_SUB(NOW(), INTERVAL 31 DAY);
END;
"""
]
try:
cursor = self.mysql_conn.cursor()
for query in queries:
cursor.execute(query)
self.mysql_conn.commit()
cursor.close()
print("MySQL EVENTS created successfully.")
except Exception as e:
print(f"Failed to create MySQL EVENTS: {e}")
self.mysql_conn.rollback()

View File

@@ -0,0 +1,83 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
from pathlib import Path
class BootstrapPostfix(BootstrapBase):
def bootstrap(self):
# Connect to MySQL
self.connect_mysql()
# Wait for DNS
self.wait_for_dns("mailcow.email")
self.create_dir("/opt/postfix/conf/sql/")
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
"VALID_CERT_DIRS": self.get_valid_cert_dirs()
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Set Syslog redis")
self.set_syslog_redis()
print("Render config")
self.render_config("/service_config")
# Create aliases DB
self.run_command(["newaliases"])
# Create SNI Config
self.run_command(["postmap", "-F", "hash:/opt/postfix/conf/sni.map"])
# Fix Postfix permissions
self.set_owner("/opt/postfix/conf/sql", user="root", group="postfix", recursive=True)
self.set_owner("/opt/postfix/conf/custom_transport.pcre", user="root", group="postfix")
for cf_file in Path("/opt/postfix/conf/sql").glob("*.cf"):
self.set_permissions(cf_file, 0o640)
self.set_permissions("/opt/postfix/conf/custom_transport.pcre", 0o640)
self.set_owner("/var/spool/postfix/public", user="root", group="postdrop", recursive=True)
self.set_owner("/var/spool/postfix/maildrop", user="root", group="postdrop", recursive=True)
self.run_command(["postfix", "set-permissions"], check=False)
# Checking if there is a leftover of a crashed postfix container before starting a new one
pid_file = Path("/var/spool/postfix/pid/master.pid")
if pid_file.exists():
print(f"Removing stale Postfix PID file: {pid_file}")
pid_file.unlink()
def get_valid_cert_dirs(self):
certs = {}
base_path = Path("/etc/ssl/mail")
if not base_path.exists():
return certs
for cert_dir in base_path.iterdir():
if not cert_dir.is_dir():
continue
domains_file = cert_dir / "domains"
cert_file = cert_dir / "cert.pem"
key_file = cert_dir / "key.pem"
if not (domains_file.exists() and cert_file.exists() and key_file.exists()):
continue
with open(domains_file, "r") as f:
domains = [line.strip() for line in f if line.strip()]
if domains:
certs[str(cert_dir)] = domains
return certs

View File

@@ -0,0 +1,132 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
from pathlib import Path
import time
import platform
class BootstrapRspamd(BootstrapBase):
def bootstrap(self):
# Connect to MySQL
self.connect_mysql()
# Connect to MySQL
self.connect_redis()
# get dovecot ips
dovecot_v4 = []
dovecot_v6 = []
while not dovecot_v4 and not dovecot_v6:
try:
dovecot_v4 = self.resolve_docker_dns_record("dovecot-mailcow", "A")
dovecot_v6 = self.resolve_docker_dns_record("dovecot-mailcow", "AAAA")
except Exception as e:
print(e)
if not dovecot_v4 and not dovecot_v6:
print("Waiting for Dovecot IPs...")
time.sleep(3)
# get rspamd ips
rspamd_v4 = []
rspamd_v6 = []
while not rspamd_v4 and not rspamd_v6:
try:
rspamd_v4 = self.resolve_docker_dns_record("rspamd-mailcow", "A")
rspamd_v6 = self.resolve_docker_dns_record("rspamd-mailcow", "AAAA")
except Exception:
print(e)
if not rspamd_v4 and not rspamd_v6:
print("Waiting for Rspamd IPs...")
time.sleep(3)
# wait for Services
services = [
["php-fpm-mailcow", 9001],
["php-fpm-mailcow", 9002]
]
for service in services:
while not self.is_port_open(service[0], service[1]):
print(f"Waiting for {service[0]} on port {service[1]}...")
time.sleep(1)
print(f"Service {service[0]} on port {service[1]} is ready!")
for dir_path in ["/etc/rspamd/plugins.d", "/etc/rspamd/custom"]:
Path(dir_path).mkdir(parents=True, exist_ok=True)
for file_path in ["/etc/rspamd/rspamd.conf.local", "/etc/rspamd/rspamd.conf.override"]:
Path(file_path).touch(exist_ok=True)
self.set_permissions("/var/lib/rspamd", 0o755)
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
"DOVECOT_V4": dovecot_v4[0],
"DOVECOT_V6": dovecot_v6[0],
"RSPAMD_V4": rspamd_v4[0],
"RSPAMD_V6": rspamd_v6[0],
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Render config")
self.render_config("/service_config")
# Fix missing default global maps, if any
# These exists in mailcow UI and should not be removed
files = [
"/etc/rspamd/custom/global_mime_from_blacklist.map",
"/etc/rspamd/custom/global_rcpt_blacklist.map",
"/etc/rspamd/custom/global_smtp_from_blacklist.map",
"/etc/rspamd/custom/global_mime_from_whitelist.map",
"/etc/rspamd/custom/global_rcpt_whitelist.map",
"/etc/rspamd/custom/global_smtp_from_whitelist.map",
"/etc/rspamd/custom/bad_languages.map",
"/etc/rspamd/custom/sa-rules",
"/etc/rspamd/custom/dovecot_trusted.map",
"/etc/rspamd/custom/rspamd_trusted.map",
"/etc/rspamd/custom/mailcow_networks.map",
"/etc/rspamd/custom/ip_wl.map",
"/etc/rspamd/custom/fishy_tlds.map",
"/etc/rspamd/custom/bad_words.map",
"/etc/rspamd/custom/bad_asn.map",
"/etc/rspamd/custom/bad_words_de.map",
"/etc/rspamd/custom/bulk_header.map",
"/etc/rspamd/custom/bad_header.map"
]
for file in files:
path = Path(file)
path.parent.mkdir(parents=True, exist_ok=True)
path.touch(exist_ok=True)
# Fix permissions
paths_rspamd = [
"/var/lib/rspamd",
"/etc/rspamd/local.d",
"/etc/rspamd/override.d",
"/etc/rspamd/rspamd.conf.local",
"/etc/rspamd/rspamd.conf.override",
"/etc/rspamd/plugins.d"
]
for path in paths_rspamd:
self.set_owner(path, "_rspamd", "_rspamd", recursive=True)
self.set_owner("/etc/rspamd/custom", "_rspamd", "_rspamd")
self.set_permissions("/etc/rspamd/custom", 0o755)
custom_path = Path("/etc/rspamd/custom")
for child in custom_path.iterdir():
if child.is_file():
self.set_owner(child, 82, 82)
self.set_permissions(child, 0o644)
# Provide additional lua modules
arch = platform.machine()
self.run_command(["ln", "-s", f"/usr/lib/{arch}-linux-gnu/liblua5.1-cjson.so.0.0.0", "/usr/lib/rspamd/cjson.so"], check=False)

View File

@@ -0,0 +1,138 @@
from jinja2 import Environment, FileSystemLoader
from modules.BootstrapBase import BootstrapBase
from pathlib import Path
import os
import sys
import time
class BootstrapSogo(BootstrapBase):
def bootstrap(self):
# Skip SOGo if set
if self.isYes(os.getenv("SKIP_SOGO", "")):
print("SKIP_SOGO is set, skipping SOGo startup...")
time.sleep(365 * 24 * 60 * 60)
sys.exit(1)
# Connect to MySQL
self.connect_mysql()
# Wait until port is free
while self.is_port_open(os.getenv("SOGO_HOST"), 20000):
print("Port 20000 still in use — terminating sogod...")
self.kill_proc("sogod")
time.sleep(3)
# Wait for schema to update to expected version
self.wait_for_schema_update(init_file_path="init_db.inc.php")
# Setup Jinja2 Environment and load vars
self.env = Environment(
loader=FileSystemLoader([
'/service_config/custom_templates',
'/service_config/config_templates'
]),
keep_trailing_newline=True,
lstrip_blocks=True,
trim_blocks=True
)
extra_vars = {
"SQL_DOMAINS": self.get_domains(),
"IAM_SETTINGS": self.get_identity_provider_settings()
}
self.env_vars = self.prepare_template_vars('/service_config/overwrites.json', extra_vars)
print("Set Timezone")
self.set_timezone()
print("Set Syslog redis")
self.set_syslog_redis()
print("Render config")
self.render_config("/service_config")
print("Fix permissions")
self.set_owner("/var/lib/sogo", "sogo", "sogo", recursive=True)
self.set_permissions("/var/lib/sogo/GNUstep/Defaults/sogod.plist", 0o600)
# Rename custom logo
logo_src = Path("/etc/sogo/sogo-full.svg")
if logo_src.exists():
print("Set Logo")
self.move_file(logo_src, "/etc/sogo/custom-fulllogo.svg")
# Rsync web content
print("Syncing web content")
self.rsync_file("/usr/lib/GNUstep/SOGo/", "/sogo_web/", recursive=True)
# Chown backup path
self.set_owner("/sogo_backup", "sogo", "sogo", recursive=True)
def get_domains(self):
"""
Retrieves a list of domains and their GAL (Global Address List) status.
Executes a SQL query to select:
- `domain`
- a human-readable GAL status ("YES" or "NO")
- `ldap_gal` as a boolean (True/False)
Returns:
list[dict]: A list of dicts with keys: domain, gal_status, ldap_gal.
Example: [{"domain": "example.com", "gal_status": "YES", "ldap_gal": True}]
Logs:
Error messages if the query fails.
"""
query = """
SELECT domain,
CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal_status,
ldap_gal = 1 AS ldap_gal
FROM domain;
"""
try:
cursor = self.mysql_conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
cursor.close()
return [
{
"domain": row[0],
"gal_status": row[1],
"ldap_gal": bool(row[2])
}
for row in result
]
except Exception as e:
print(f"Error fetching domains: {e}")
return []
def get_identity_provider_settings(self):
"""
Retrieves all key-value identity provider settings.
Returns:
dict: Settings in the format { key: value }
Logs:
Error messages if the query fails.
"""
query = "SELECT `key`, `value` FROM identity_provider;"
try:
cursor = self.mysql_conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
cursor.close()
iam_settings = {row[0]: row[1] for row in result}
if iam_settings['authsource'] == "ldap":
protocol = "ldaps" if iam_settings.get("use_ssl") else "ldap"
starttls = "/????!StartTLS" if iam_settings.get("use_tls") else ""
iam_settings['ldap_url'] = f"{protocol}://{iam_settings['host']}:{iam_settings['port']}{starttls}"
return iam_settings
except Exception as e:
print(f"Error fetching identity provider settings: {e}")
return {}

View File

@@ -1,15 +1,129 @@
FROM clamav/clamav:0.104.2-2_base
FROM alpine:3.21 AS builder
LABEL maintainer "André Peters <andre.peters@servercow.de>"
WORKDIR /src
ENV CLAMD_VERSION=1.4.2
RUN apk upgrade --no-cache \
&& apk add --update --no-cache \
rsync \
bind-tools \
bash
g++ \
gcc \
gdb \
make \
cmake \
py3-pytest \
python3 \
valgrind \
bzip2-dev \
check-dev \
curl-dev \
json-c-dev \
libmilter-dev \
libxml2-dev \
linux-headers \
ncurses-dev \
openssl-dev \
pcre2-dev \
zlib-dev \
cargo \
rust
COPY clamd.sh ./
RUN chmod +x /sbin/tini
RUN wget -P /src https://www.clamav.net/downloads/production/clamav-${CLAMD_VERSION}.tar.gz \
&& tar xzfv /src/clamav-${CLAMD_VERSION}.tar.gz \
&& cd /src/clamav-${CLAMD_VERSION} \
&& cmake . \
-D CMAKE_BUILD_TYPE="Release" \
-D CMAKE_INSTALL_PREFIX="/usr" \
-D CMAKE_INSTALL_LIBDIR="/usr/lib" \
-D APP_CONFIG_DIRECTORY="/etc/clamav" \
-D DATABASE_DIRECTORY="/var/lib/clamav" \
-D ENABLE_CLAMONACC=OFF \
-D ENABLE_EXAMPLES=OFF \
-D ENABLE_MILTER=ON \
-D ENABLE_MAN_PAGES=OFF \
-D ENABLE_STATIC_LIB=OFF \
-D ENABLE_JSON_SHARED=ON \
&& cmake --build . \
&& make DESTDIR="/clamav" -j$(($(nproc) - 1)) install \
&& rm -r "/clamav/usr/lib/pkgconfig/" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(LocalSocket\) .*|\1 /tmp/clamd.sock|" \
-e "s|.*\(TCPSocket\) .*|\1 3310|" \
-e "s|.*\(TCPAddr\) .*|#\1 0.0.0.0|" \
-e "s|.*\(User\) .*|\1 clamav|" \
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/clamd.log|" \
-e "s|^\#\(LogTime\).*|\1 yes|" \
"/clamav/etc/clamav/clamd.conf.sample" > "/clamav/etc/clamav/clamd.conf" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(DatabaseOwner\) .*|\1 clamav|" \
-e "s|^\#\(UpdateLogFile\) .*|\1 /var/log/clamav/freshclam.log|" \
-e "s|^\#\(NotifyClamd\).*|\1 /etc/clamav/clamd.conf|" \
-e "s|^\#\(ScriptedUpdates\).*|\1 yes|" \
"/clamav/etc/clamav/freshclam.conf.sample" > "/clamav/etc/clamav/freshclam.conf" \
&& sed -e "s|^\(Example\)|\# \1|" \
-e "s|.*\(MilterSocket\) .*|\1 inet:7357|" \
-e "s|.*\(User\) .*|\1 clamav|" \
-e "s|^\#\(LogFile\) .*|\1 /var/log/clamav/milter.log|" \
-e "s|^\#\(LogTime\).*|\1 yes|" \
-e "s|.*\(\ClamdSocket\) .*|\1 unix:/tmp/clamd.sock|" \
"/clamav/etc/clamav/clamav-milter.conf.sample" > "/clamav/etc/clamav/clamav-milter.conf" || exit 1
ENTRYPOINT []
FROM alpine:3.21
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
RUN apk upgrade --no-cache \
&& apk add --update --no-cache \
tzdata \
rsync \
bind-tools \
bash \
tini \
json-c \
libbz2 \
libcurl \
libmilter \
libxml2 \
ncurses-libs \
pcre2 \
zlib \
libgcc \
py3-pip \
&& addgroup -S "clamav" && \
adduser -D -G "clamav" -h "/var/lib/clamav" -s "/bin/false" -S "clamav" && \
install -d -m 755 -g "clamav" -o "clamav" "/var/log/clamav" && \
chown -R clamav:clamav /var/lib/clamav
RUN apk add --no-cache --virtual .build-deps \
gcc \
musl-dev \
python3-dev \
linux-headers \
&& pip install --break-system-packages psutil \
&& apk del .build-deps
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython
COPY --from=builder "/clamav" "/"
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/clamd/docker-entrypoint.sh /docker-entrypoint.sh
COPY data/Dockerfiles/clamd/clamd.sh /clamd.sh
COPY data/Dockerfiles/clamd/healthcheck.sh /healthcheck.sh
COPY data/Dockerfiles/clamd/clamdcheck.sh /usr/local/bin
HEALTHCHECK --start-period=6m CMD "/healthcheck.sh"
RUN chmod +x /docker-entrypoint.sh \
/clamd.sh \
/healthcheck.sh \
/usr/local/bin/clamdcheck.sh \
/sbin/tini
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/sbin/tini", "-g", "--", "/clamd.sh"]

View File

@@ -1,48 +1,5 @@
#!/bin/bash
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_CLAMD=y, skipping ClamAV..."
sleep 365d
exit 0
fi
# Cleaning up garbage
echo "Cleaning up tmp files..."
rm -rf /var/lib/clamav/clamav-*.tmp
# Prepare whitelist
mkdir -p /run/clamav /var/lib/clamav
if [[ -s /etc/clamav/whitelist.ign2 ]]; then
echo "Copying non-empty whitelist.ign2 to /var/lib/clamav/whitelist.ign2"
cp /etc/clamav/whitelist.ign2 /var/lib/clamav/whitelist.ign2
fi
if [[ ! -f /var/lib/clamav/whitelist.ign2 ]]; then
echo "Creating /var/lib/clamav/whitelist.ign2"
cat <<EOF > /var/lib/clamav/whitelist.ign2
# Please restart ClamAV after changing signatures
Example-Signature.Ignore-1
PUA.Win.Trojan.EmbeddedPDF-1
PUA.Pdf.Trojan.EmbeddedJavaScript-1
PUA.Pdf.Trojan.OpenActionObjectwithJavascript-1
EOF
fi
chown clamav:clamav -R /var/lib/clamav /run/clamav
chmod 755 /var/lib/clamav
chmod 644 -R /var/lib/clamav/*
chmod 750 /run/clamav
stat /var/lib/clamav/whitelist.ign2
dos2unix /var/lib/clamav/whitelist.ign2
sed -i '/^\s*$/d' /var/lib/clamav/whitelist.ign2
# Copying to /etc/clamav to expose file as-is to administrator
cp -p /var/lib/clamav/whitelist.ign2 /etc/clamav/whitelist.ign2
BACKGROUND_TASKS=()
echo "Running freshclam..."
@@ -91,6 +48,7 @@ done
) &
BACKGROUND_TASKS+=($!)
echo "$(clamd -V) is starting... please wait a moment."
nice -n10 clamd &
BACKGROUND_TASKS+=($!)

View File

@@ -0,0 +1,14 @@
#!/bin/sh
set -eu
if [ "${CLAMAV_NO_CLAMD:-}" != "false" ]; then
if [ "$(echo "PING" | nc localhost 3310)" != "PONG" ]; then
echo "ERROR: Unable to contact server"
exit 1
fi
echo "Clamd is up"
fi
exit 0

View File

@@ -0,0 +1,20 @@
#!/bin/bash
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
echo "Running hook ${file}"
"${file}"
fi
done
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Clamd."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting Clamd..."
exec "$@"

View File

@@ -0,0 +1,9 @@
#!/bin/bash
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_CLAMD=y, skipping ClamAV..."
exit 0
fi
# run clamd healthcheck
/usr/local/bin/clamdcheck.sh

View File

@@ -1,18 +1,27 @@
FROM alpine:3.15
FROM alpine:3.21
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
ARG PIP_BREAK_SYSTEM_PACKAGES=1
WORKDIR /app
RUN apk add --update --no-cache python3 \
py3-pip \
openssl \
tzdata \
py3-psutil \
py3-redis \
py3-async-timeout \
&& pip3 install --upgrade pip \
docker \
flask \
flask-restful
fastapi \
uvicorn \
aiodocker \
docker
RUN mkdir /app/modules
COPY dockerapi.py /app/
COPY data/Dockerfiles/dockerapi/docker-entrypoint.sh /app/
COPY data/Dockerfiles/dockerapi/main.py /app/main.py
COPY data/Dockerfiles/dockerapi/modules/ /app/modules/
CMD ["python3", "-u", "/app/dockerapi.py"]
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
CMD ["python", "main.py"]

View File

@@ -0,0 +1,9 @@
#!/bin/bash
`openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-keyout /app/dockerapi_key.pem \
-out /app/dockerapi_cert.pem \
-subj /CN=dockerapi/O=mailcow \
-addext subjectAltName=DNS:dockerapi`
exec "$@"

View File

@@ -1,419 +0,0 @@
#!/usr/bin/env python3
from flask import Flask
from flask_restful import Resource, Api
from flask import jsonify
from flask import Response
from flask import request
from threading import Thread
import docker
import uuid
import signal
import time
import os
import re
import sys
import ssl
import socket
import subprocess
import traceback
docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
app = Flask(__name__)
api = Api(app)
class containers_get(Resource):
def get(self):
containers = {}
try:
for container in docker_client.containers.list(all=True):
containers.update({container.attrs['Id']: container.attrs})
return containers
except Exception as e:
return jsonify(type='danger', msg=str(e))
class container_get(Resource):
def get(self, container_id):
if container_id and container_id.isalnum():
try:
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
return container.attrs
except Exception as e:
return jsonify(type='danger', msg=str(e))
else:
return jsonify(type='danger', msg='no or invalid id defined')
class container_post(Resource):
def post(self, container_id, post_action):
if container_id and container_id.isalnum() and post_action:
try:
"""Dispatch container_post api call"""
if post_action == 'exec':
if not request.json or not 'cmd' in request.json:
return jsonify(type='danger', msg='cmd is missing')
if not request.json or not 'task' in request.json:
return jsonify(type='danger', msg='task is missing')
api_call_method_name = '__'.join(['container_post', str(post_action), str(request.json['cmd']), str(request.json['task']) ])
else:
api_call_method_name = '__'.join(['container_post', str(post_action) ])
api_call_method = getattr(self, api_call_method_name, lambda container_id: jsonify(type='danger', msg='container_post - unknown api call'))
print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
return api_call_method(container_id)
except Exception as e:
print("error - container_post: %s" % str(e))
return jsonify(type='danger', msg=str(e))
else:
return jsonify(type='danger', msg='invalid container id or missing action')
# api call: container_post - post_action: stop
def container_post__stop(self, container_id):
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
container.stop()
return jsonify(type='success', msg='command completed successfully')
# api call: container_post - post_action: start
def container_post__start(self, container_id):
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
container.start()
return jsonify(type='success', msg='command completed successfully')
# api call: container_post - post_action: restart
def container_post__restart(self, container_id):
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
container.restart()
return jsonify(type='success', msg='command completed successfully')
# api call: container_post - post_action: top
def container_post__top(self, container_id):
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
return jsonify(type='success', msg=container.top())
# api call: container_post - post_action: stats
def container_post__stats(self, container_id):
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
for stat in container.stats(decode=True, stream=True):
return jsonify(type='success', msg=stat )
# api call: container_post - post_action: exec - cmd: mailq - task: delete
def container_post__exec__mailq__delete(self, container_id):
if 'items' in request.json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
flagged_qids = ['-d %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: hold
def container_post__exec__mailq__hold(self, container_id):
if 'items' in request.json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
flagged_qids = ['-h %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: cat
def container_post__exec__mailq__cat(self, container_id):
if 'items' in request.json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
sanitized_string = str(' '.join(filtered_qids));
for container in docker_client.containers.list(filters={"id": container_id}):
postcat_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
if not postcat_return:
postcat_return = 'err: invalid'
return exec_run_handler('utf8_text_only', postcat_return)
# api call: container_post - post_action: exec - cmd: mailq - task: unhold
def container_post__exec__mailq__unhold(self, container_id):
if 'items' in request.json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
flagged_qids = ['-H %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: deliver
def container_post__exec__mailq__deliver(self, container_id):
if 'items' in request.json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
flagged_qids = ['-i %s' % i for i in filtered_qids]
for container in docker_client.containers.list(filters={"id": container_id}):
for i in flagged_qids:
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
# todo: check each exit code
return jsonify(type='success', msg=str("Scheduled immediate delivery"))
# api call: container_post - post_action: exec - cmd: mailq - task: list
def container_post__exec__mailq__list(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix')
return exec_run_handler('utf8_text_only', mailq_return)
# api call: container_post - post_action: exec - cmd: mailq - task: flush
def container_post__exec__mailq__flush(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix')
return exec_run_handler('generic', postqueue_r)
# api call: container_post - post_action: exec - cmd: mailq - task: super_delete
def container_post__exec__mailq__super_delete(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"])
return exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: system - task: fts_rescan
def container_post__exec__system__fts_rescan(self, container_id):
if 'username' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request.json['username'].replace("'", "'\\''") + "'"], user='vmail')
if rescan_return.exit_code == 0:
return jsonify(type='success', msg='fts_rescan: rescan triggered')
else:
return jsonify(type='warning', msg='fts_rescan error')
if 'all' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
if rescan_return.exit_code == 0:
return jsonify(type='success', msg='fts_rescan: rescan triggered')
else:
return jsonify(type='warning', msg='fts_rescan error')
# api call: container_post - post_action: exec - cmd: system - task: df
def container_post__exec__system__df(self, container_id):
if 'dir' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
df_return = container.exec_run(["/bin/bash", "-c", "/bin/df -H '" + request.json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
if df_return.exit_code == 0:
return df_return.output.decode('utf-8').rstrip()
else:
return "0,0,0,0,0,0"
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
def container_post__exec__system__mysql_upgrade(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
if sql_return.exit_code == 0:
matched = False
for line in sql_return.output.decode('utf-8').split("\n"):
if 'is already upgraded to' in line:
matched = True
if matched:
return jsonify(type='success', msg='mysql_upgrade: already upgraded', text=sql_return.output.decode('utf-8'))
else:
container.restart()
return jsonify(type='warning', msg='mysql_upgrade: upgrade was applied', text=sql_return.output.decode('utf-8'))
else:
return jsonify(type='error', msg='mysql_upgrade: error running command', text=sql_return.output.decode('utf-8'))
# api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
if sql_return.exit_code == 0:
return jsonify(type='info', msg='mysql_tzinfo_to_sql: command completed successfully', text=sql_return.output.decode('utf-8'))
else:
return jsonify(type='error', msg='mysql_tzinfo_to_sql: error running command', text=sql_return.output.decode('utf-8'))
# api call: container_post - post_action: exec - cmd: reload - task: dovecot
def container_post__exec__reload__dovecot(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
return exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: reload - task: postfix
def container_post__exec__reload__postfix(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
return exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: reload - task: nginx
def container_post__exec__reload__nginx(self, container_id):
for container in docker_client.containers.list(filters={"id": container_id}):
reload_return = container.exec_run(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
return exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: sieve - task: list
def container_post__exec__sieve__list(self, container_id):
if 'username' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"])
return exec_run_handler('utf8_text_only', sieve_return)
# api call: container_post - post_action: exec - cmd: sieve - task: print
def container_post__exec__sieve__print(self, container_id):
if 'username' in request.json and 'script_name' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]
sieve_return = container.exec_run(cmd)
return exec_run_handler('utf8_text_only', sieve_return)
# api call: container_post - post_action: exec - cmd: maildir - task: cleanup
def container_post__exec__maildir__cleanup(self, container_id):
if 'maildir' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
sane_name = re.sub(r'\W+', '', request.json['maildir'])
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
maildir_cleanup = container.exec_run(cmd, user='vmail')
return exec_run_handler('generic', maildir_cleanup)
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
def container_post__exec__rspamd__worker_password(self, container_id):
if 'raw' in request.json:
for container in docker_client.containers.list(filters={"id": container_id}):
cmd = "/usr/bin/rspamadm pw -e -p '" + request.json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
matched = False
for line in cmd_response.split("\n"):
if '$2$' in line:
hash = line.strip()
hash_out = re.search('\$2\$.+$', hash).group(0)
rspamd_passphrase_hash = re.sub('[^0-9a-zA-Z\$]+', '', hash_out.rstrip())
rspamd_password_filename = "/etc/rspamd/override.d/worker-controller-password.inc"
cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename)
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
container.restart()
matched = True
if matched:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg='command did not complete')
def exec_cmd_container(container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
def recv_socket_data(c_socket, timeout):
c_socket.setblocking(0)
total_data=[];
data='';
begin=time.time()
while True:
if total_data and time.time()-begin > timeout:
break
elif time.time()-begin > timeout*2:
break
try:
data = c_socket.recv(8192)
if data:
total_data.append(data.decode('utf-8'))
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
break
except:
pass
return ''.join(total_data)
try :
socket = container.exec_run([shell_cmd], stdin=True, socket=True, user=user).output._sock
if not cmd.endswith("\n"):
cmd = cmd + "\n"
socket.send(cmd.encode('utf-8'))
data = recv_socket_data(socket, timeout)
socket.close()
return data
except Exception as e:
print("error - exec_cmd_container: %s" % str(e))
traceback.print_exc(file=sys.stdout)
def exec_run_handler(type, output):
if type == 'generic':
if output.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg='command failed: ' + output.output.decode('utf-8'))
if type == 'utf8_text_only':
r = Response(response=output.output.decode('utf-8'), status=200, mimetype="text/plain")
r.headers["Content-Type"] = "text/plain; charset=utf-8"
return r
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, signum, frame):
self.kill_now = True
def create_self_signed_cert():
process = subprocess.Popen(
"openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout /app/dockerapi_key.pem -out /app/dockerapi_cert.pem -subj /CN=dockerapi/O=mailcow -addext subjectAltName=DNS:dockerapi".split(),
stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=False
)
process.wait()
def startFlaskAPI():
create_self_signed_cert()
try:
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ctx.check_hostname = False
ctx.load_cert_chain(certfile='/app/dockerapi_cert.pem', keyfile='/app/dockerapi_key.pem')
except:
print ("Cannot initialize TLS, retrying in 5s...")
time.sleep(5)
app.run(debug=False, host='0.0.0.0', port=443, threaded=True, ssl_context=ctx)
api.add_resource(containers_get, '/containers/json')
api.add_resource(container_get, '/containers/<string:container_id>/json')
api.add_resource(container_post, '/containers/<string:container_id>/<string:post_action>')
if __name__ == '__main__':
api_thread = Thread(target=startFlaskAPI)
api_thread.daemon = True
api_thread.start()
killer = GracefulKiller()
while True:
time.sleep(1)
if killer.kill_now:
break
print ("Stopping dockerapi-mailcow")

View File

@@ -0,0 +1,261 @@
import os
import sys
import uvicorn
import json
import uuid
import async_timeout
import asyncio
import aiodocker
import docker
import logging
from logging.config import dictConfig
from fastapi import FastAPI, Response, Request
from modules.DockerApi import DockerApi
from redis import asyncio as aioredis
from contextlib import asynccontextmanager
dockerapi = None
@asynccontextmanager
async def lifespan(app: FastAPI):
global dockerapi
# Initialize a custom logger
logger = logging.getLogger("dockerapi")
logger.setLevel(logging.INFO)
# Configure the logger to output logs to the terminal
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
formatter = logging.Formatter("%(levelname)s: %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("Init APP")
# Init redis client
if os.environ['REDIS_SLAVEOF_IP'] != "":
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0", password=os.environ['REDISPASS'])
else:
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_HOST']}:6379/0", password=os.environ['REDISPASS'])
# Init docker clients
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
dockerapi = DockerApi(redis_client, sync_docker_client, async_docker_client, logger)
logger.info("Subscribe to redis channel")
# Subscribe to redis channel
dockerapi.pubsub = redis.pubsub()
await dockerapi.pubsub.subscribe("MC_CHANNEL")
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
yield
# Close docker connections
dockerapi.sync_docker_client.close()
await dockerapi.async_docker_client.close()
# Close redis
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
await dockerapi.redis_client.close()
app = FastAPI(lifespan=lifespan)
# Define Routes
@app.get("/host/stats")
async def get_host_update_stats():
global dockerapi
if dockerapi.host_stats_isUpdating == False:
asyncio.create_task(dockerapi.get_host_stats())
dockerapi.host_stats_isUpdating = True
while True:
if await dockerapi.redis_client.exists('host_stats'):
break
await asyncio.sleep(1.5)
stats = json.loads(await dockerapi.redis_client.get('host_stats'))
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
@app.get("/containers/{container_id}/json")
async def get_container(container_id : str):
global dockerapi
if container_id and container_id.isalnum():
try:
for container in (await dockerapi.async_docker_client.containers.list()):
if container._id == container_id:
container_info = await container.show()
return Response(content=json.dumps(container_info, indent=4), media_type="application/json")
res = {
"type": "danger",
"msg": "no container found"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
except Exception as e:
res = {
"type": "danger",
"msg": str(e)
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = {
"type": "danger",
"msg": "no or invalid id defined"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
@app.get("/containers/json")
async def get_containers():
global dockerapi
containers = {}
try:
for container in (await dockerapi.async_docker_client.containers.list()):
container_info = await container.show()
containers.update({container_info['Id']: container_info})
return Response(content=json.dumps(containers, indent=4), media_type="application/json")
except Exception as e:
res = {
"type": "danger",
"msg": str(e)
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
@app.post("/containers/{container_id}/{post_action}")
async def post_containers(container_id : str, post_action : str, request: Request):
global dockerapi
try:
request_json = await request.json()
except Exception as err:
request_json = {}
if container_id and container_id.isalnum() and post_action:
try:
"""Dispatch container_post api call"""
if post_action == 'exec':
if not request_json or not 'cmd' in request_json:
res = {
"type": "danger",
"msg": "cmd is missing"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
if not request_json or not 'task' in request_json:
res = {
"type": "danger",
"msg": "task is missing"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
api_call_method_name = '__'.join(['container_post', str(post_action), str(request_json['cmd']), str(request_json['task']) ])
else:
api_call_method_name = '__'.join(['container_post', str(post_action) ])
api_call_method = getattr(dockerapi, api_call_method_name, lambda container_id: Response(content=json.dumps({'type': 'danger', 'msg':'container_post - unknown api call' }, indent=4), media_type="application/json"))
dockerapi.logger.info("api call: %s, container_id: %s" % (api_call_method_name, container_id))
return api_call_method(request_json, container_id=container_id)
except Exception as e:
dockerapi.logger.error("error - container_post: %s" % str(e))
res = {
"type": "danger",
"msg": str(e)
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = {
"type": "danger",
"msg": "invalid container id or missing action"
}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
@app.post("/container/{container_id}/stats/update")
async def post_container_update_stats(container_id : str):
global dockerapi
# start update task for container if no task is running
if container_id not in dockerapi.containerIds_to_update:
asyncio.create_task(dockerapi.get_container_stats(container_id))
dockerapi.containerIds_to_update.append(container_id)
while True:
if await dockerapi.redis_client.exists(container_id + '_stats'):
break
await asyncio.sleep(1.5)
stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
# PubSub Handler
async def handle_pubsub_messages(channel: aioredis.client.PubSub):
global dockerapi
while True:
try:
async with async_timeout.timeout(60):
message = await channel.get_message(ignore_subscribe_messages=True, timeout=30)
if message is not None:
# Parse message
data_json = json.loads(message['data'].decode('utf-8'))
dockerapi.logger.info(f"PubSub Received - {json.dumps(data_json)}")
# Handle api_call
if 'api_call' in data_json:
# api_call: container_post
if data_json['api_call'] == "container_post":
if 'post_action' in data_json and 'container_name' in data_json:
try:
"""Dispatch container_post api call"""
request_json = {}
if data_json['post_action'] == 'exec':
if 'request' in data_json:
request_json = data_json['request']
if 'cmd' in request_json:
if 'task' in request_json:
api_call_method_name = '__'.join(['container_post', str(data_json['post_action']), str(request_json['cmd']), str(request_json['task']) ])
else:
dockerapi.logger.error("api call: task missing")
else:
dockerapi.logger.error("api call: cmd missing")
else:
dockerapi.logger.error("api call: request missing")
else:
api_call_method_name = '__'.join(['container_post', str(data_json['post_action'])])
if api_call_method_name:
api_call_method = getattr(dockerapi, api_call_method_name)
if api_call_method:
dockerapi.logger.info("api call: %s, container_name: %s" % (api_call_method_name, data_json['container_name']))
api_call_method(request_json, container_name=data_json['container_name'])
else:
dockerapi.logger.error("api call not found: %s, container_name: %s" % (api_call_method_name, data_json['container_name']))
except Exception as e:
dockerapi.logger.error("container_post: %s" % str(e))
else:
dockerapi.logger.error("api call: missing container_name, post_action or request")
else:
dockerapi.logger.error("Unknown PubSub received - %s" % json.dumps(data_json))
else:
dockerapi.logger.error("Unknown PubSub received - %s" % json.dumps(data_json))
await asyncio.sleep(0.0)
except asyncio.TimeoutError:
pass
if __name__ == '__main__':
uvicorn.run(
app,
host="0.0.0.0",
port=443,
ssl_certfile="/app/dockerapi_cert.pem",
ssl_keyfile="/app/dockerapi_key.pem",
log_level="info",
loop="none"
)

View File

@@ -0,0 +1,626 @@
import psutil
import sys
import os
import re
import time
import json
import asyncio
import platform
from datetime import datetime
from fastapi import FastAPI, Response, Request
class DockerApi:
def __init__(self, redis_client, sync_docker_client, async_docker_client, logger):
self.redis_client = redis_client
self.sync_docker_client = sync_docker_client
self.async_docker_client = async_docker_client
self.logger = logger
self.host_stats_isUpdating = False
self.containerIds_to_update = []
# api call: container_post - post_action: stop
def container_post__stop(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(all=True, filters=filters):
container.stop()
res = { 'type': 'success', 'msg': 'command completed successfully'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: start
def container_post__start(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(all=True, filters=filters):
container.start()
res = { 'type': 'success', 'msg': 'command completed successfully'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: restart
def container_post__restart(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(all=True, filters=filters):
container.restart()
res = { 'type': 'success', 'msg': 'command completed successfully'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: top
def container_post__top(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(all=True, filters=filters):
res = { 'type': 'success', 'msg': container.top()}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: stats
def container_post__stats(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(all=True, filters=filters):
for stat in container.stats(decode=True, stream=True):
res = { 'type': 'success', 'msg': stat}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: mailq - task: delete
def container_post__exec__mailq__delete(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request_json['items'])
if filtered_qids:
flagged_qids = ['-d %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids))
for container in self.sync_docker_client.containers.list(filters=filters):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return self.exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: hold
def container_post__exec__mailq__hold(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request_json['items'])
if filtered_qids:
flagged_qids = ['-h %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids))
for container in self.sync_docker_client.containers.list(filters=filters):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return self.exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: cat
def container_post__exec__mailq__cat(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request_json['items'])
if filtered_qids:
sanitized_string = str(' '.join(filtered_qids))
for container in self.sync_docker_client.containers.list(filters=filters):
postcat_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
if not postcat_return:
postcat_return = 'err: invalid'
return self.exec_run_handler('utf8_text_only', postcat_return)
# api call: container_post - post_action: exec - cmd: mailq - task: unhold
def container_post__exec__mailq__unhold(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request_json['items'])
if filtered_qids:
flagged_qids = ['-H %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids))
for container in self.sync_docker_client.containers.list(filters=filters):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
return self.exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: mailq - task: deliver
def container_post__exec__mailq__deliver(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'items' in request_json:
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request_json['items'])
if filtered_qids:
flagged_qids = ['-i %s' % i for i in filtered_qids]
for container in self.sync_docker_client.containers.list(filters=filters):
for i in flagged_qids:
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
# todo: check each exit code
res = { 'type': 'success', 'msg': 'Scheduled immediate delivery'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: mailq - task: list
def container_post__exec__mailq__list(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix')
return self.exec_run_handler('utf8_text_only', mailq_return)
# api call: container_post - post_action: exec - cmd: mailq - task: flush
def container_post__exec__mailq__flush(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix')
return self.exec_run_handler('generic', postqueue_r)
# api call: container_post - post_action: exec - cmd: mailq - task: super_delete
def container_post__exec__mailq__super_delete(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"])
return self.exec_run_handler('generic', postsuper_r)
# api call: container_post - post_action: exec - cmd: system - task: fts_rescan
def container_post__exec__system__fts_rescan(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'username' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request_json['username'].replace("'", "'\\''") + "'"], user='vmail')
if rescan_return.exit_code == 0:
res = { 'type': 'success', 'msg': 'fts_rescan: rescan triggered'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = { 'type': 'warning', 'msg': 'fts_rescan error'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
if 'all' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
if rescan_return.exit_code == 0:
res = { 'type': 'success', 'msg': 'fts_rescan: rescan triggered'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = { 'type': 'warning', 'msg': 'fts_rescan error'}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: system - task: df
def container_post__exec__system__df(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'dir' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
df_return = container.exec_run(["/bin/bash", "-c", "/bin/df -H '" + request_json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
if df_return.exit_code == 0:
return df_return.output.decode('utf-8').rstrip()
else:
return "0,0,0,0,0,0"
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
def container_post__exec__system__mysql_upgrade(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
if sql_return.exit_code == 0:
matched = False
for line in sql_return.output.decode('utf-8').split("\n"):
if 'is already upgraded to' in line:
matched = True
if matched:
res = { 'type': 'success', 'msg':'mysql_upgrade: already upgraded', 'text': sql_return.output.decode('utf-8')}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
container.restart()
res = { 'type': 'warning', 'msg':'mysql_upgrade: upgrade was applied', 'text': sql_return.output.decode('utf-8')}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = { 'type': 'error', 'msg': 'mysql_upgrade: error running command', 'text': sql_return.output.decode('utf-8')}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
def container_post__exec__system__mysql_tzinfo_to_sql(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
if sql_return.exit_code == 0:
res = { 'type': 'info', 'msg': 'mysql_tzinfo_to_sql: command completed successfully', 'text': sql_return.output.decode('utf-8')}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = { 'type': 'error', 'msg': 'mysql_tzinfo_to_sql: error running command', 'text': sql_return.output.decode('utf-8')}
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: reload - task: dovecot
def container_post__exec__reload__dovecot(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
return self.exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: reload - task: postfix
def container_post__exec__reload__postfix(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
return self.exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: reload - task: nginx
def container_post__exec__reload__nginx(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
reload_return = container.exec_run(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
return self.exec_run_handler('generic', reload_return)
# api call: container_post - post_action: exec - cmd: sieve - task: list
def container_post__exec__sieve__list(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'username' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request_json['username'].replace("'", "'\\''") + "'"])
return self.exec_run_handler('utf8_text_only', sieve_return)
# api call: container_post - post_action: exec - cmd: sieve - task: print
def container_post__exec__sieve__print(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'username' in request_json and 'script_name' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
sieve_return = container.exec_run(cmd)
return self.exec_run_handler('utf8_text_only', sieve_return)
# api call: container_post - post_action: exec - cmd: maildir - task: cleanup
def container_post__exec__maildir__cleanup(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'maildir' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
sane_name = re.sub(r'\W+', '', request_json['maildir'])
vmail_name = request_json['maildir'].replace("'", "'\\''")
cmd_vmail = "if [[ -d '/var/vmail/" + vmail_name + "' ]]; then /bin/mv '/var/vmail/" + vmail_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"
index_name = request_json['maildir'].split("/")
if len(index_name) > 1:
index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''")
cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "_index'; fi"
cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index]
else:
cmd = ["/bin/bash", "-c", cmd_vmail]
maildir_cleanup = container.exec_run(cmd, user='vmail')
return self.exec_run_handler('generic', maildir_cleanup)
# api call: container_post - post_action: exec - cmd: maildir - task: move
def container_post__exec__maildir__move(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'old_maildir' in request_json and 'new_maildir' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
vmail_name = request_json['old_maildir'].replace("'", "'\\''")
new_vmail_name = request_json['new_maildir'].replace("'", "'\\''")
cmd_vmail = f"if [[ -d '/var/vmail/{vmail_name}' ]]; then /bin/mv '/var/vmail/{vmail_name}' '/var/vmail/{new_vmail_name}'; fi"
index_name = request_json['old_maildir'].split("/")
new_index_name = request_json['new_maildir'].split("/")
if len(index_name) > 1 and len(new_index_name) > 1:
index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''")
new_index_name = new_index_name[1].replace("'", "'\\''") + "@" + new_index_name[0].replace("'", "'\\''")
cmd_vmail_index = f"if [[ -d '/var/vmail_index/{index_name}' ]]; then /bin/mv '/var/vmail_index/{index_name}' '/var/vmail_index/{new_index_name}_index'; fi"
cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index]
else:
cmd = ["/bin/bash", "-c", cmd_vmail]
maildir_move = container.exec_run(cmd, user='vmail')
return self.exec_run_handler('generic', maildir_move)
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
def container_post__exec__rspamd__worker_password(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'raw' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
cmd = "/usr/bin/rspamadm pw -e -p '" + request_json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
cmd_response = self.exec_cmd_container(container, cmd, user="_rspamd")
matched = False
for line in cmd_response.split("\n"):
if '$2$' in line:
hash = line.strip()
hash_out = re.search(r'\$2\$.+$', hash).group(0)
rspamd_passphrase_hash = re.sub(r'[^0-9a-zA-Z\$]+', '', hash_out.rstrip())
rspamd_password_filename = "/etc/rspamd/override.d/worker-controller-password.inc"
cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename)
cmd_response = self.exec_cmd_container(container, cmd, user="_rspamd")
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
container.restart()
matched = True
if matched:
res = { 'type': 'success', 'msg': 'command completed successfully' }
self.logger.info('success changing Rspamd password')
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
self.logger.error('failed changing Rspamd password')
res = { 'type': 'danger', 'msg': 'command did not complete' }
return Response(content=json.dumps(res, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: sogo - task: rename
def container_post__exec__sogo__rename_user(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
if 'old_username' in request_json and 'new_username' in request_json:
for container in self.sync_docker_client.containers.list(filters=filters):
old_username = request_json['old_username'].replace("'", "'\\''")
new_username = request_json['new_username'].replace("'", "'\\''")
sogo_return = container.exec_run(["/bin/bash", "-c", f"sogo-tool rename-user '{old_username}' '{new_username}'"], user='sogo')
return self.exec_run_handler('generic', sogo_return)
# api call: container_post - post_action: exec - cmd: doveadm - task: get_acl
def container_post__exec__doveadm__get_acl(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
id = request_json['id'].replace("'", "'\\''")
shared_folders = container.exec_run(["/bin/bash", "-c", f"doveadm mailbox list -u '{id}'"])
shared_folders = shared_folders.output.decode('utf-8')
shared_folders = shared_folders.splitlines()
formatted_acls = []
mailbox_seen = []
for shared_folder in shared_folders:
if "Shared" not in shared_folder:
mailbox = shared_folder.replace("'", "'\\''")
if mailbox in mailbox_seen:
continue
acls = container.exec_run(["/bin/bash", "-c", f"doveadm acl get -u '{id}' '{mailbox}'"])
acls = acls.output.decode('utf-8').strip().splitlines()
if len(acls) >= 2:
for acl in acls[1:]:
user_id, rights = acl.split(maxsplit=1)
user_id = user_id.split('=')[1]
mailbox_seen.append(mailbox)
formatted_acls.append({ 'user': id, 'id': user_id, 'mailbox': mailbox, 'rights': rights.split() })
elif "Shared" in shared_folder and "/" in shared_folder:
shared_folder = shared_folder.split("/")
if len(shared_folder) < 3:
continue
user = shared_folder[1].replace("'", "'\\''")
mailbox = '/'.join(shared_folder[2:]).replace("'", "'\\''")
if mailbox in mailbox_seen:
continue
acls = container.exec_run(["/bin/bash", "-c", f"doveadm acl get -u '{user}' '{mailbox}'"])
acls = acls.output.decode('utf-8').strip().splitlines()
if len(acls) >= 2:
for acl in acls[1:]:
user_id, rights = acl.split(maxsplit=1)
user_id = user_id.split('=')[1].replace("'", "'\\''")
if user_id == id and mailbox not in mailbox_seen:
mailbox_seen.append(mailbox)
formatted_acls.append({ 'user': user, 'id': id, 'mailbox': mailbox, 'rights': rights.split() })
return Response(content=json.dumps(formatted_acls, indent=4), media_type="application/json")
# api call: container_post - post_action: exec - cmd: doveadm - task: delete_acl
def container_post__exec__doveadm__delete_acl(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
user = request_json['user'].replace("'", "'\\''")
mailbox = request_json['mailbox'].replace("'", "'\\''")
id = request_json['id'].replace("'", "'\\''")
if user and mailbox and id:
acl_delete_return = container.exec_run(["/bin/bash", "-c", f"doveadm acl delete -u '{user}' '{mailbox}' 'user={id}'"])
return self.exec_run_handler('generic', acl_delete_return)
# api call: container_post - post_action: exec - cmd: doveadm - task: set_acl
def container_post__exec__doveadm__set_acl(self, request_json, **kwargs):
if 'container_id' in kwargs:
filters = {"id": kwargs['container_id']}
elif 'container_name' in kwargs:
filters = {"name": kwargs['container_name']}
for container in self.sync_docker_client.containers.list(filters=filters):
user = request_json['user'].replace("'", "'\\''")
mailbox = request_json['mailbox'].replace("'", "'\\''")
id = request_json['id'].replace("'", "'\\''")
rights = ""
available_rights = [
"admin",
"create",
"delete",
"expunge",
"insert",
"lookup",
"post",
"read",
"write",
"write-deleted",
"write-seen"
]
for right in request_json['rights']:
right = right.replace("'", "'\\''").lower()
if right in available_rights:
rights += right + " "
if user and mailbox and id and rights:
acl_set_return = container.exec_run(["/bin/bash", "-c", f"doveadm acl set -u '{user}' '{mailbox}' 'user={id}' {rights}"])
return self.exec_run_handler('generic', acl_set_return)
# Collect host stats
async def get_host_stats(self, wait=5):
try:
system_time = datetime.now()
host_stats = {
"cpu": {
"cores": psutil.cpu_count(),
"usage": psutil.cpu_percent()
},
"memory": {
"total": psutil.virtual_memory().total,
"usage": psutil.virtual_memory().percent,
"swap": psutil.swap_memory()
},
"uptime": time.time() - psutil.boot_time(),
"system_time": system_time.strftime("%d.%m.%Y %H:%M:%S"),
"architecture": platform.machine()
}
await self.redis_client.set('host_stats', json.dumps(host_stats), ex=10)
except Exception as e:
res = {
"type": "danger",
"msg": str(e)
}
await asyncio.sleep(wait)
self.host_stats_isUpdating = False
# Collect container stats
async def get_container_stats(self, container_id, wait=5, stop=False):
if container_id and container_id.isalnum():
try:
for container in (await self.async_docker_client.containers.list()):
if container._id == container_id:
res = await container.stats(stream=False)
if await self.redis_client.exists(container_id + '_stats'):
stats = json.loads(await self.redis_client.get(container_id + '_stats'))
else:
stats = []
stats.append(res[0])
if len(stats) > 3:
del stats[0]
await self.redis_client.set(container_id + '_stats', json.dumps(stats), ex=60)
except Exception as e:
res = {
"type": "danger",
"msg": str(e)
}
else:
res = {
"type": "danger",
"msg": "no or invalid id defined"
}
await asyncio.sleep(wait)
if stop == True:
# update task was called second time, stop
self.containerIds_to_update.remove(container_id)
else:
# call update task a second time
await self.get_container_stats(container_id, wait=0, stop=True)
def exec_cmd_container(self, container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
def recv_socket_data(c_socket, timeout):
c_socket.setblocking(0)
total_data=[]
data=''
begin=time.time()
while True:
if total_data and time.time()-begin > timeout:
break
elif time.time()-begin > timeout*2:
break
try:
data = c_socket.recv(8192)
if data:
total_data.append(data.decode('utf-8'))
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
break
except:
pass
return ''.join(total_data)
try :
socket = container.exec_run([shell_cmd], stdin=True, socket=True, user=user).output._sock
if not cmd.endswith("\n"):
cmd = cmd + "\n"
socket.send(cmd.encode('utf-8'))
data = recv_socket_data(socket, timeout)
socket.close()
return data
except Exception as e:
self.logger.error("error - exec_cmd_container: %s" % str(e))
traceback.print_exc(file=sys.stdout)
def exec_run_handler(self, type, output):
if type == 'generic':
if output.exit_code == 0:
res = { 'type': 'success', 'msg': 'command completed successfully' }
return Response(content=json.dumps(res, indent=4), media_type="application/json")
else:
res = { 'type': 'danger', 'msg': 'command failed: ' + output.output.decode('utf-8') }
return Response(content=json.dumps(res, indent=4), media_type="application/json")
if type == 'utf8_text_only':
return Response(content=output.output.decode('utf-8'), media_type="text/plain")

View File

@@ -1,131 +1,150 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM alpine:3.21
ARG DEBIAN_FRONTEND=noninteractive
ARG DOVECOT=2.3.18
ENV LC_ALL C
ENV GOSU_VERSION 1.14
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.16
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
# Add groups and users before installing Dovecot to not break compatibility
RUN groupadd -g 5000 vmail \
&& groupadd -g 401 dovecot \
&& groupadd -g 402 dovenull \
&& groupadd -g 999 sogo \
&& usermod -a -G sogo nobody \
&& useradd -g vmail -u 5000 vmail -d /var/vmail \
&& useradd -c "Dovecot unprivileged user" -d /dev/null -u 401 -g dovecot -s /bin/false dovecot \
&& useradd -c "Dovecot login user" -d /dev/null -u 402 -g dovenull -s /bin/false dovenull \
&& touch /etc/default/locale \
&& apt-get update \
&& apt-get -y --no-install-recommends install \
apt-transport-https \
RUN addgroup -g 5000 vmail \
&& addgroup -g 401 dovecot \
&& addgroup -g 402 dovenull \
&& sed -i "s/999/99/" /etc/group \
&& addgroup -g 999 sogo \
&& addgroup nobody sogo \
&& adduser -D -u 5000 -G vmail -h /var/vmail vmail \
&& adduser -D -G dovecot -u 401 -h /dev/null -s /sbin/nologin dovecot \
&& adduser -D -G dovenull -u 402 -h /dev/null -s /sbin/nologin dovenull \
&& apk add --no-cache --update \
bash \
bind-tools \
findutils \
envsubst \
ca-certificates \
cpanminus \
curl \
dnsutils \
dirmngr \
gettext \
gnupg2 \
coreutils \
jq \
libauthen-ntlm-perl \
libcgi-pm-perl \
libcrypt-openssl-rsa-perl \
libcrypt-ssleay-perl \
libdata-uniqid-perl \
libdbd-mysql-perl \
libdbi-perl \
libdigest-hmac-perl \
libdist-checkconflicts-perl \
libencode-imaputf7-perl \
libfile-copy-recursive-perl \
libfile-tail-perl \
libhtml-parser-perl \
libio-compress-perl \
libio-socket-inet6-perl \
libio-socket-ssl-perl \
libio-tee-perl \
libipc-run-perl \
libjson-webtoken-perl \
liblockfile-simple-perl \
libmail-imapclient-perl \
libmodule-implementation-perl \
libmodule-scandeps-perl \
libnet-ssleay-perl \
libpackage-stash-perl \
libpackage-stash-xs-perl \
libpar-packer-perl \
libparse-recdescent-perl \
libproc-processtable-perl \
libreadonly-perl \
libregexp-common-perl \
libsys-meminfo-perl \
libterm-readkey-perl \
libtest-deep-perl \
libtest-fatal-perl \
libtest-mock-guard-perl \
libtest-mockobject-perl \
libtest-nowarnings-perl \
libtest-pod-perl \
libtest-requires-perl \
libtest-simple-perl \
libtest-warn-perl \
libtry-tiny-perl \
libunicode-string-perl \
liburi-perl \
libwww-perl \
lua-sql-mysql \
lua \
lua-cjson \
lua-socket \
lua-sql-mysql \
lua5.3-sql-mysql \
icu-data-full \
mariadb-connector-c \
lua-sec \
mariadb-dev \
glib-dev \
gcompat \
mariadb-client \
perl \
perl-dev \
perl-ntlm \
perl-cgi \
perl-crypt-openssl-rsa \
perl-utils \
perl-crypt-ssleay \
perl-data-uniqid \
perl-dbd-mysql \
perl-dbi \
perl-digest-hmac \
perl-dist-checkconflicts \
perl-encode-imaputf7 \
perl-file-copy-recursive \
perl-file-tail \
perl-io-socket-inet6 \
perl-io-gzip \
perl-io-socket-ssl \
perl-io-tee \
perl-ipc-run \
perl-json-webtoken \
perl-mail-imapclient \
perl-module-implementation \
perl-module-scandeps \
perl-net-ssleay \
perl-package-stash \
perl-package-stash-xs \
perl-par-packer \
perl-parse-recdescent \
perl-lockfile-simple \
libproc2 \
perl-readonly \
perl-regexp-common \
perl-sys-meminfo \
perl-term-readkey \
perl-test-deep \
perl-test-fatal \
perl-test-mockobject \
perl-test-mock-guard \
perl-test-pod \
perl-test-requires \
perl-test-simple \
perl-test-warn \
perl-try-tiny \
perl-unicode-string \
perl-proc-processtable \
perl-app-cpanminus \
procps \
python3-pip \
redis-server \
supervisor \
python3 py3-pip python3-dev \
py3-html2text \
linux-headers \
musl-dev \
gcc \
redis \
syslog-ng \
syslog-ng-core \
syslog-ng-mod-redis \
syslog-ng-redis \
syslog-ng-json \
supervisor \
tzdata \
wget \
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& apt-key adv --fetch-keys https://repo.dovecot.org/DOVECOT-REPO-GPG \
&& echo "deb https://repo.dovecot.org/ce-${DOVECOT}/debian/bullseye bullseye main" > /etc/apt/sources.list.d/dovecot.list \
&& apt-get update \
&& apt-get -y --no-install-recommends install \
dovecot-lua \
dovecot-managesieved \
dovecot-sieve \
dovecot \
dovecot-dev \
dovecot-lmtpd \
dovecot-lua \
dovecot-ldap \
dovecot-mysql \
dovecot-core \
dovecot-sql \
dovecot-submissiond \
dovecot-pigeonhole-plugin \
dovecot-pop3d \
dovecot-imapd \
dovecot-solr \
&& pip3 install mysql-connector-python html2text jinja2 redis \
&& apt-get autoremove --purge -y \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* /var/tmp/* /root/.cache/
dovecot-fts-flatcurve \
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$arch" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY imapsync /usr/local/bin/imapsync
COPY imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
COPY report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
COPY report-ham.sieve /usr/lib/dovecot/sieve/report-ham.sieve
COPY rspamd-pipe-ham /usr/lib/dovecot/sieve/rspamd-pipe-ham
COPY rspamd-pipe-spam /usr/lib/dovecot/sieve/rspamd-pipe-spam
COPY sa-rules.sh /usr/local/bin/sa-rules.sh
COPY maildir_gc.sh /usr/local/bin/maildir_gc.sh
COPY docker-entrypoint.sh /
COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY quarantine_notify.py /usr/local/bin/quarantine_notify.py
COPY quota_notify.py /usr/local/bin/quota_notify.py
COPY repl_health.sh /usr/local/bin/repl_health.sh
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython \
psutil
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/dovecot/trim_logs.sh /usr/local/bin/trim_logs.sh
COPY data/Dockerfiles/dovecot/clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
COPY data/Dockerfiles/dovecot/syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY data/Dockerfiles/dovecot/imapsync /usr/local/bin/imapsync
COPY data/Dockerfiles/dovecot/imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
COPY data/Dockerfiles/dovecot/report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
COPY data/Dockerfiles/dovecot/report-ham.sieve /usr/lib/dovecot/sieve/report-ham.sieve
COPY data/Dockerfiles/dovecot/rspamd-pipe-ham /usr/lib/dovecot/sieve/rspamd-pipe-ham
COPY data/Dockerfiles/dovecot/rspamd-pipe-spam /usr/lib/dovecot/sieve/rspamd-pipe-spam
COPY data/Dockerfiles/dovecot/sa-rules.sh /usr/local/bin/sa-rules.sh
COPY data/Dockerfiles/dovecot/docker-entrypoint.sh /
COPY data/Dockerfiles/dovecot/supervisord.conf /etc/supervisor/supervisord.conf
COPY data/Dockerfiles/dovecot/stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY data/Dockerfiles/dovecot/quarantine_notify.py /usr/local/bin/quarantine_notify.py
COPY data/Dockerfiles/dovecot/quota_notify.py /usr/local/bin/quota_notify.py
COPY data/Dockerfiles/dovecot/repl_health.sh /usr/local/bin/repl_health.sh
COPY data/Dockerfiles/dovecot/optimize-fts.sh /usr/local/bin/optimize-fts.sh
RUN chmod +x /docker-entrypoint.sh \
/usr/local/sbin/stop-supervisor.sh
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -2,7 +2,7 @@
source /source_env.sh
MAX_AGE=$(redis-cli --raw -h redis-mailcow GET Q_MAX_AGE)
MAX_AGE=$(redis-cli --raw -h redis-mailcow -a ${REDISPASS} --no-auth-warning GET Q_MAX_AGE)
if [[ -z ${MAX_AGE} ]]; then
echo "Max age for quarantine items not defined"
@@ -15,6 +15,6 @@ if ! [[ ${MAX_AGE} =~ ${NUM_REGEXP} ]] ; then
exit 1
fi
TO_DELETE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN)
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY"
TO_DELETE=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT COUNT(id) FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY" -BN)
mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM quarantine WHERE created < NOW() - INTERVAL ${MAX_AGE//[!0-9]/} DAY"
echo "Deleted ${TO_DELETE} items from quarantine table (max age is ${MAX_AGE//[!0-9]/} days)"

View File

@@ -1,415 +1,4 @@
#!/bin/bash
set -e
# Wait for MySQL to warm-up
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for database to come up..."
sleep 2
done
until dig +short mailcow.email > /dev/null; do
echo "Waiting for DNS..."
sleep 1
done
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
echo "Waiting for Redis..."
sleep 2
done
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
# Create missing directories
[[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/
[[ ! -d /etc/dovecot/lua/ ]] && mkdir -p /etc/dovecot/lua/
[[ ! -d /var/vmail/_garbage ]] && mkdir -p /var/vmail/_garbage
[[ ! -d /var/vmail/sieve ]] && mkdir -p /var/vmail/sieve
[[ ! -d /etc/sogo ]] && mkdir -p /etc/sogo
[[ ! -d /var/volatile ]] && mkdir -p /var/volatile
# Set Dovecot sql config parameters, escape " in db password
DBPASS=$(echo ${DBPASS} | sed 's/"/\\"/g')
# Create quota dict for Dovecot
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
QUOTA_TABLE=quota2
else
QUOTA_TABLE=quota2replica
fi
cat <<EOF > /etc/dovecot/sql/dovecot-dict-sql-quota.conf
# Autogenerated by mailcow
connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}"
map {
pattern = priv/quota/storage
table = ${QUOTA_TABLE}
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = ${QUOTA_TABLE}
username_field = username
value_field = messages
}
EOF
# Create dict used for sieve pre and postfilters
cat <<EOF > /etc/dovecot/sql/dovecot-dict-sql-sieve_before.conf
# Autogenerated by mailcow
connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}"
map {
pattern = priv/sieve/name/\$script_name
table = sieve_before
username_field = username
value_field = id
fields {
script_name = \$script_name
}
}
map {
pattern = priv/sieve/data/\$id
table = sieve_before
username_field = username
value_field = script_data
fields {
id = \$id
}
}
EOF
cat <<EOF > /etc/dovecot/sql/dovecot-dict-sql-sieve_after.conf
# Autogenerated by mailcow
connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}"
map {
pattern = priv/sieve/name/\$script_name
table = sieve_after
username_field = username
value_field = id
fields {
script_name = \$script_name
}
}
map {
pattern = priv/sieve/data/\$id
table = sieve_after
username_field = username
value_field = script_data
fields {
id = \$id
}
}
EOF
echo -n ${ACL_ANYONE} > /etc/dovecot/acl_anyone
if [[ "${SKIP_SOLR}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify listescape replication' > /etc/dovecot/mail_plugins
echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify listescape replication mail_log' > /etc/dovecot/mail_plugins_imap
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl notify listescape replication' > /etc/dovecot/mail_plugins_lmtp
else
echo -n 'quota acl zlib mail_crypt mail_crypt_acl mail_log notify fts fts_solr listescape replication' > /etc/dovecot/mail_plugins
echo -n 'quota imap_quota imap_acl acl zlib imap_zlib imap_sieve mail_crypt mail_crypt_acl notify mail_log fts fts_solr listescape replication' > /etc/dovecot/mail_plugins_imap
echo -n 'quota sieve acl zlib mail_crypt mail_crypt_acl fts fts_solr notify listescape replication' > /etc/dovecot/mail_plugins_lmtp
fi
chmod 644 /etc/dovecot/mail_plugins /etc/dovecot/mail_plugins_imap /etc/dovecot/mail_plugins_lmtp /templates/quarantine.tpl
cat <<EOF > /etc/dovecot/sql/dovecot-dict-sql-userdb.conf
# Autogenerated by mailcow
driver = mysql
connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}"
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';
EOF
cat <<EOF > /etc/dovecot/lua/passwd-verify.lua
function auth_password_verify(req, pass)
if req.domain == nil then
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "No such user"
end
if cur == nil then
script_init()
end
if req.user == nil then
req.user = ''
end
respbody = {}
-- check against mailbox passwds
local cur,errorString = con:execute(string.format([[SELECT password FROM mailbox
WHERE username = '%s'
AND active = '1'
AND domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')
AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.force_pw_update')), 0) != '1'
AND IFNULL(JSON_UNQUOTE(JSON_VALUE(attributes, '$.%s_access')), 1) = '1']], con:escape(req.user), con:escape(req.domain), con:escape(req.service)))
local row = cur:fetch ({}, "a")
while row do
if req.password_verify(req, row.password, pass) == 1 then
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
VALUES ("%s", 0, "%s", "%s")]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip)))
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
end
row = cur:fetch (row, "a")
end
-- check against app passwds for imap and smtp
-- app passwords are only available for imap, smtp, sieve and pop3 when using sasl
if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then
local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, %s_access AS has_prot_access, app_passwd.password FROM app_passwd
INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox
WHERE mailbox = '%s'
AND app_passwd.active = '1'
AND mailbox.active = '1'
AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.service), con:escape(req.user), con:escape(req.domain)))
local row = cur:fetch ({}, "a")
while row do
if req.password_verify(req, row.password, pass) == 1 then
-- if password is valid and protocol access is 1 OR real_rip matches SOGo, proceed
if tostring(req.real_rip) == "__IPV4_SOGO__" then
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
elseif row.has_prot_access == "1" then
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
end
end
row = cur:fetch (row, "a")
end
end
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
-- PoC
-- local reqbody = string.format([[{
-- "success":0,
-- "service":"%s",
-- "app_password":false,
-- "username":"%s",
-- "real_rip":"%s"
-- }]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip))
-- http.request {
-- method = "POST",
-- url = "http://nginx:8081/sasl_log.php",
-- source = ltn12.source.string(reqbody),
-- headers = {
-- ["content-type"] = "application/json",
-- ["content-length"] = tostring(#reqbody)
-- },
-- sink = ltn12.sink.table(respbody)
-- }
end
function auth_passdb_lookup(req)
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, ""
end
function script_init()
mysql = require "luasql.mysql"
http = require "socket.http"
http.TIMEOUT = 5
ltn12 = require "ltn12"
env = mysql.mysql()
con = env:connect("__DBNAME__","__DBUSER__","__DBPASS__","localhost")
return 0
end
function script_deinit()
con:close()
env:close()
end
EOF
# Replace patterns in app-passdb.lua
sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBNAME__/${DBNAME}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__IPV4_SOGO__/${IPV4_NETWORK}.248/g" /etc/dovecot/lua/passwd-verify.lua
# Migrate old sieve_after file
[[ -f /etc/dovecot/sieve_after ]] && mv /etc/dovecot/sieve_after /etc/dovecot/global_sieve_after
# Create global sieve scripts
cat /etc/dovecot/global_sieve_after > /var/vmail/sieve/global_sieve_after.sieve
cat /etc/dovecot/global_sieve_before > /var/vmail/sieve/global_sieve_before.sieve
# Check permissions of vmail/index/garbage directories.
# Do not do this every start-up, it may take a very long time. So we use a stat check here.
if [[ $(stat -c %U /var/vmail/) != "vmail" ]] ; then chown -R vmail:vmail /var/vmail ; fi
if [[ $(stat -c %U /var/vmail/_garbage) != "vmail" ]] ; then chown -R vmail:vmail /var/vmail/_garbage ; fi
if [[ $(stat -c %U /var/vmail_index) != "vmail" ]] ; then chown -R vmail:vmail /var/vmail_index ; fi
# Cleanup random user maildirs
rm -rf /var/vmail/mailcow.local/*
# Cleanup PIDs
[[ -f /tmp/quarantine_notify.pid ]] && rm /tmp/quarantine_notify.pid
# create sni configuration
echo "" > /etc/dovecot/sni.conf
for cert_dir in /etc/ssl/mail/*/ ; do
if [[ ! -f ${cert_dir}domains ]] || [[ ! -f ${cert_dir}cert.pem ]] || [[ ! -f ${cert_dir}key.pem ]]; then
continue
fi
domains=($(cat ${cert_dir}domains))
for domain in ${domains[@]}; do
echo 'local_name '${domain}' {' >> /etc/dovecot/sni.conf;
echo ' ssl_cert = <'${cert_dir}'cert.pem' >> /etc/dovecot/sni.conf;
echo ' ssl_key = <'${cert_dir}'key.pem' >> /etc/dovecot/sni.conf;
echo '}' >> /etc/dovecot/sni.conf;
done
done
# Create random master for SOGo sieve features
RAND_USER=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1)
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 24 | head -n 1)
if [[ ! -z ${DOVECOT_MASTER_USER} ]] && [[ ! -z ${DOVECOT_MASTER_PASS} ]]; then
RAND_USER=${DOVECOT_MASTER_USER}
RAND_PASS=${DOVECOT_MASTER_PASS}
fi
echo ${RAND_USER}@mailcow.local:{SHA1}$(echo -n ${RAND_PASS} | sha1sum | awk '{print $1}'):::::: > /etc/dovecot/dovecot-master.passwd
echo ${RAND_USER}@mailcow.local::5000:5000:::: > /etc/dovecot/dovecot-master.userdb
echo ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/sieve.creds
if [[ -z ${MAILDIR_SUB} ]]; then
MAILDIR_SUB_SHARED=
else
MAILDIR_SUB_SHARED=/${MAILDIR_SUB}
fi
cat <<EOF > /etc/dovecot/shared_namespace.conf
# Autogenerated by mailcow
namespace {
type = shared
separator = /
prefix = Shared/%%u/
location = maildir:%%h${MAILDIR_SUB_SHARED}:INDEX=~${MAILDIR_SUB_SHARED}/Shared/%%u
subscriptions = no
list = children
}
EOF
cat <<EOF > /etc/dovecot/sogo_trusted_ip.conf
# Autogenerated by mailcow
remote ${IPV4_NETWORK}.248 {
disable_plaintext_auth = no
}
EOF
# Create random master Password for SOGo SSO
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass
cat <<EOF > /etc/dovecot/sogo-sso.conf
# Autogenerated by mailcow
passdb {
driver = static
args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
}
EOF
if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
cat <<'EOF' > /usr/local/bin/quota_notify.py
#!/usr/bin/python3
import sys
sys.exit()
EOF
fi
# 401 is user dovecot
if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then
openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem
openssl pkey -in /mail_crypt/ecprivkey.pem -pubout -out /mail_crypt/ecpubkey.pem
chown 401 /mail_crypt/ecprivkey.pem /mail_crypt/ecpubkey.pem
else
chown 401 /mail_crypt/ecprivkey.pem /mail_crypt/ecpubkey.pem
fi
# Compile sieve scripts
sievec /var/vmail/sieve/global_sieve_before.sieve
sievec /var/vmail/sieve/global_sieve_after.sieve
sievec /usr/lib/dovecot/sieve/report-spam.sieve
sievec /usr/lib/dovecot/sieve/report-ham.sieve
# Fix permissions
chown root:root /etc/dovecot/sql/*.conf
chown root:dovecot /etc/dovecot/sql/dovecot-dict-sql-sieve* /etc/dovecot/sql/dovecot-dict-sql-quota* /etc/dovecot/lua/passwd-verify.lua
chmod 640 /etc/dovecot/sql/*.conf /etc/dovecot/lua/passwd-verify.lua
chown -R vmail:vmail /var/vmail/sieve
chown -R vmail:vmail /var/volatile
chown -R vmail:vmail /var/vmail_index
adduser vmail tty
chmod g+rw /dev/console
chown root:tty /dev/console
chmod +x /usr/lib/dovecot/sieve/rspamd-pipe-ham \
/usr/lib/dovecot/sieve/rspamd-pipe-spam \
/usr/local/bin/imapsync_runner.pl \
/usr/local/bin/imapsync \
/usr/local/bin/trim_logs.sh \
/usr/local/bin/sa-rules.sh \
/usr/local/bin/clean_q_aged.sh \
/usr/local/bin/maildir_gc.sh \
/usr/local/sbin/stop-supervisor.sh \
/usr/local/bin/quota_notify.py \
/usr/local/bin/repl_health.sh
# Prepare environment file for cronjobs
printenv | sed 's/^\(.*\)$/export \1/g' > /source_env.sh
# Clean old PID if any
[[ -f /var/run/dovecot/master.pid ]] && rm /var/run/dovecot/master.pid
# Clean stopped imapsync jobs
rm -f /tmp/imapsync_busy.lock
IMAPSYNC_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'imapsync'" -Bs)
[[ ! -z ${IMAPSYNC_TABLE} ]] && mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "UPDATE imapsync SET is_running='0'"
# Envsubst maildir_gc
echo "$(envsubst < /usr/local/bin/maildir_gc.sh)" > /usr/local/bin/maildir_gc.sh
# GUID generation
while [[ ${VERSIONS_OK} != 'OK' ]]; do
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"${DBNAME}\" AND TABLE_NAME = 'versions'") ]]; then
VERSIONS_OK=OK
else
echo "Waiting for versions table to be created..."
sleep 3
fi
done
PUBKEY_MCRYPT=$(doveconf -P 2> /dev/null | grep -i mail_crypt_global_public_key | cut -d '<' -f2)
if [ -f ${PUBKEY_MCRYPT} ]; then
GUID=$(cat <(echo ${MAILCOW_HOSTNAME}) /mail_crypt/ecpubkey.pem | sha256sum | cut -d ' ' -f1 | tr -cd "[a-fA-F0-9.:/] ")
if [ ${#GUID} -eq 64 ]; then
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
REPLACE INTO versions (application, version) VALUES ("GUID", "${GUID}");
EOF
else
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
REPLACE INTO versions (application, version) VALUES ("GUID", "INVALID");
EOF
fi
fi
# Collect SA rules once now
/usr/local/bin/sa-rules.sh
# Run hooks
for file in /hooks/*; do
@@ -419,8 +8,24 @@ for file in /hooks/*; do
fi
done
# For some strange, unknown and stupid reason, Dovecot may run into a race condition, when this file is not touched before it is read by dovecot/auth
# May be related to something inside Docker, I seriously don't know
touch /etc/dovecot/lua/passwd-verify.lua
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
exec "$@"
# Fix OpenSSL 3.X TLS1.0, 1.1 support (https://community.mailcow.email/d/4062-hi-all/20)
if grep -qE 'ssl_min_protocol\s*=\s*(TLSv1|TLSv1\.1)\s*$' /etc/dovecot/dovecot.conf /etc/dovecot/extra.conf; then
sed -i '/\[openssl_init\]/a ssl_conf = ssl_configuration' /etc/ssl/openssl.cnf
echo "[ssl_configuration]" >> /etc/ssl/openssl.cnf
echo "system_default = tls_system_default" >> /etc/ssl/openssl.cnf
echo "[tls_system_default]" >> /etc/ssl/openssl.cnf
echo "MinProtocol = TLSv1" >> /etc/ssl/openssl.cnf
echo "CipherString = DEFAULT@SECLEVEL=0" >> /etc/ssl/openssl.cnf
fi
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Dovecot."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting Dovecot..."
/usr/sbin/dovecot -F

View File

@@ -8492,6 +8492,7 @@ sub xoauth2
require HTML::Entities ;
require JSON ;
require JSON::WebToken::Crypt::RSA ;
require Crypt::OpenSSL::PKCS12;
require Crypt::OpenSSL::RSA ;
require Encode::Byte ;
require IO::Socket::SSL ;
@@ -8532,8 +8533,9 @@ sub xoauth2
$sync->{ debug } and myprint( "Service account: $iss\nKey file: $keyfile\nKey password: $keypass\n");
# Get private key from p12 file (would be better in perl...)
$key = `openssl pkcs12 -in "$keyfile" -nodes -nocerts -passin pass:$keypass -nomacver`;
# Get private key from p12 file
my $pkcs12 = Crypt::OpenSSL::PKCS12->new_from_file($keyfile);
$key = $pkcs12->private_key($keypass);
$sync->{ debug } and myprint( "Private key:\n$key\n");
}

View File

@@ -51,8 +51,8 @@ sub sig_handler {
die "sig_handler received signal, preparing to exit...\n";
};
open my $file, '<', "/etc/sogo/sieve.creds";
my $creds = <$file>;
open my $file, '<', "/etc/sogo/sieve.creds";
my $creds = <$file>;
close $file;
my ($master_user, $master_pass) = split /:/, $creds;
my $sth = $dbh->prepare("SELECT id,
@@ -75,7 +75,8 @@ my $sth = $dbh->prepare("SELECT id,
custom_params,
subscribeall,
timeout1,
timeout2
timeout2,
dry
FROM imapsync
WHERE active = 1
AND is_running = 0
@@ -111,13 +112,16 @@ while ($row = $sth->fetchrow_arrayref()) {
$subscribeall = @$row[18];
$timeout1 = @$row[19];
$timeout2 = @$row[20];
$dry = @$row[21];
if ($enc1 eq "TLS") { $enc1 = "--tls1"; } elsif ($enc1 eq "SSL") { $enc1 = "--ssl1"; } else { undef $enc1; }
my $template = $run_dir . '/imapsync.XXXXXXX';
my $passfile1 = File::Temp->new(TEMPLATE => $template);
my $passfile2 = File::Temp->new(TEMPLATE => $template);
binmode( $passfile1, ":utf8" );
print $passfile1 "$password1\n";
print $passfile2 trim($master_pass) . "\n";
@@ -148,6 +152,7 @@ while ($row = $sth->fetchrow_arrayref()) {
"--host2", "localhost",
"--user2", $user2 . '*' . trim($master_user),
"--passfile2", $passfile2->filename,
($dry eq "1" ? ('--dry') : ()),
'--no-modulesversion',
'--noreleasecheck'];
@@ -166,17 +171,11 @@ while ($row = $sth->fetchrow_arrayref()) {
$success = 1;
}
$keep_job_active = 1;
if (defined $exit_status && $exit_status eq "EXIT_AUTHENTICATION_FAILURE_USER1") {
$keep_job_active = 0;
}
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ?, active = ? WHERE id = ?");
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
$update->bind_param( 1, ${stdout} );
$update->bind_param( 2, ${success} );
$update->bind_param( 3, ${exit_status} );
$update->bind_param( 4, ${keep_job_active} );
$update->bind_param( 5, ${id} );
$update->bind_param( 4, ${id} );
$update->execute();
} catch {
$update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");

View File

@@ -1,2 +0,0 @@
#!/bin/bash
[ -d /var/vmail/_garbage/ ] && /usr/bin/find /var/vmail/_garbage/ -mindepth 1 -maxdepth 1 -type d -cmin +${MAILDIR_GC_TIME} -exec rm -r {} \;

View File

@@ -0,0 +1,7 @@
#!/bin/bash
if [[ "${SKIP_FTS}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
exit 0
else
doveadm fts optimize -A
fi

View File

@@ -3,11 +3,10 @@
import smtplib
import os
import sys
import mysql.connector
import MySQLdb
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
import cgi
import jinja2
from jinja2 import Template
import json
@@ -32,7 +31,7 @@ try:
while True:
try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0)
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
r.ping()
except Exception as ex:
print('%s - trying again...' % (ex))
@@ -50,7 +49,7 @@ try:
def query_mysql(query, headers = True, update = False):
while True:
try:
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8")
cnx = MySQLdb.connect(user=os.environ.get('DBUSER'), password=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8mb4", collation="utf8mb4_general_ci")
except Exception as ex:
print('%s - trying again...' % (ex))
time.sleep(3)
@@ -166,4 +165,4 @@ try:
notify_rcpt(record['rcpt'], record['counter'], record['quarantine_acl'], attrs['quarantine_category'])
finally:
os.unlink(pidfile)
os.unlink(pidfile)

View File

@@ -14,6 +14,11 @@ import sys
import html2text
from subprocess import Popen, PIPE, STDOUT
# Don't run if role is not master
if os.getenv("MASTER").lower() in ["n", "no"]:
sys.exit()
if len(sys.argv) > 2:
percent = int(sys.argv[1])
username = str(sys.argv[2])
@@ -23,7 +28,7 @@ else:
while True:
try:
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0)
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
r.ping()
except Exception as ex:
print('%s - trying again...' % (ex))
@@ -55,7 +60,7 @@ try:
msg.attach(text_part)
msg.attach(html_part)
msg['To'] = username
p = Popen(['/usr/lib/dovecot/dovecot-lda', '-d', username, '-o', '"plugin/quota=maildir:User quota:noenforcing"'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
p = Popen(['/usr/libexec/dovecot/dovecot-lda', '-d', username, '-o', '"plugin/quota=maildir:User quota:noenforcing"'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
p.communicate(input=bytes(msg.as_string(), 'utf-8'))
domain = username.split("@")[-1]

View File

@@ -4,14 +4,14 @@ source /source_env.sh
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
# Is replication active?
# grep on file is less expensive than doveconf
if ! grep -qi mail_replica /etc/dovecot/dovecot.conf; then
if [ -n ${MAILCOW_REPLICA_IP} ]; then
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
exit
fi

View File

@@ -3,8 +3,8 @@ FILE=/tmp/mail$$
cat > $FILE
trap "/bin/rm -f $FILE" 0 1 2 3 13 15
cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzydel
cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/learnham
cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzyadd
cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzydel
cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/learnham
cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzyadd
exit 0

View File

@@ -3,8 +3,8 @@ FILE=/tmp/mail$$
cat > $FILE
trap "/bin/rm -f $FILE" 0 1 2 3 13 15
cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzydel
cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/learnspam
cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd/fuzzyadd
cat ${FILE} | /usr/bin/curl -H "Flag: 13" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzydel
cat ${FILE} | /usr/bin/curl -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/learnspam
cat ${FILE} | /usr/bin/curl -H "Flag: 11" -s --data-binary @- --unix-socket /var/lib/rspamd/rspamd.sock http://rspamd.${COMPOSE_PROJECT_NAME}_mailcow-network/fuzzyadd
exit 0

View File

@@ -11,21 +11,25 @@ else
fi
# Deploy
curl --connect-timeout 15 --retry 10 --max-time 30 http://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz
if gzip -t /tmp/sa-rules-heinlein.tar.gz; then
tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein
cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules
if curl --connect-timeout 15 --retry 5 --max-time 30 https://www.spamassassin.heinlein-support.de/$(dig txt 1.4.3.spamassassin.heinlein-support.de +short | tr -d '"' | tr -dc '0-9').tar.gz --output /tmp/sa-rules-heinlein.tar.gz; then
if gzip -t /tmp/sa-rules-heinlein.tar.gz; then
tar xfvz /tmp/sa-rules-heinlein.tar.gz -C /tmp/sa-rules-heinlein
cat /tmp/sa-rules-heinlein/*cf > /etc/rspamd/custom/sa-rules
fi
else
echo "Failed to download SA rules. Exiting."
exit 0 # Must be 0 otherwise dovecot would not start at all
fi
sed -i -e 's/\([^\\]\)\$\([^\/]\)/\1\\$\2/g' /etc/rspamd/custom/sa-rules
if [[ "$(cat /etc/rspamd/custom/sa-rules | md5sum | cut -d' ' -f1)" != "${HASH_SA_RULES}" ]]; then
CONTAINER_NAME=rspamd-mailcow
CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | \
CONTAINER_ID=$(curl --silent --insecure https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/json | \
jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" | \
jq -rc "select( .name | tostring | contains(\"${CONTAINER_NAME}\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id")
if [[ ! -z ${CONTAINER_ID} ]]; then
curl --silent --insecure -XPOST --connect-timeout 15 --max-time 120 https://dockerapi/containers/${CONTAINER_ID}/restart
curl --silent --insecure -XPOST --connect-timeout 15 --max-time 120 https://dockerapi.${COMPOSE_PROJECT_NAME}_mailcow-network/containers/${CONTAINER_ID}/restart
fi
fi

View File

@@ -11,8 +11,12 @@ stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
[program:dovecot]
command=/usr/sbin/dovecot -F
[program:bootstrap]
command=/docker-entrypoint.sh
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
[eventlistener:processes]

View File

@@ -1,4 +1,4 @@
@version: 3.28
@version: 4.5
@include "scl.conf"
options {
chain_hostnames(off);
@@ -6,11 +6,12 @@ options {
use_dns(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
stats(freq(0));
keep_timestamp(no);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
source s_dgram {
unix-dgram("/dev/log");
internal();
};
destination d_stdout { pipe("/dev/stdout"); };
@@ -19,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -27,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};
@@ -35,8 +38,13 @@ filter f_replica {
not match("User has no mail_replica in userdb" value("MESSAGE"));
not match("Error: sync: Unknown user in remote" value("MESSAGE"));
};
filter f_dovecot_auth_try {
not match("- trying the next passdb" value("MESSAGE")) and
not match("- trying the next userdb" value("MESSAGE"));
};
log {
source(s_src);
source(s_dgram);
filter(f_dovecot_auth_try);
filter(f_replica);
destination(d_stdout);
filter(f_mail);

View File

@@ -1,4 +1,4 @@
@version: 3.28
@version: 4.5
@include "scl.conf"
options {
chain_hostnames(off);
@@ -6,11 +6,12 @@ options {
use_dns(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
stats(freq(0));
keep_timestamp(no);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
source s_dgram {
unix-dgram("/dev/log");
internal();
};
destination d_stdout { pipe("/dev/stdout"); };
@@ -19,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -27,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};
@@ -35,8 +38,13 @@ filter f_replica {
not match("User has no mail_replica in userdb" value("MESSAGE"));
not match("Error: sync: Unknown user in remote" value("MESSAGE"));
};
filter f_dovecot_auth_try {
not match("- trying the next passdb" value("MESSAGE")) and
not match("- trying the next userdb" value("MESSAGE"));
};
log {
source(s_src);
source(s_dgram);
filter(f_dovecot_auth_try);
filter(f_replica);
destination(d_stdout);
filter(f_mail);

View File

@@ -10,9 +10,9 @@ catch_non_zero() {
source /source_env.sh
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
@@ -23,3 +23,4 @@ catch_non_zero "${REDIS_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
catch_non_zero "${REDIS_CMDLINE} LTRIM CRON_LOG 0 ${LOG_LINES}"

View File

@@ -0,0 +1,28 @@
FROM mariadb:10.11
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
RUN apt-get update && \
apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN pip install \
mysql-connector-python \
jinja2 \
redis \
dnspython \
psutil
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/mariadb/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["mysqld"]

View File

@@ -0,0 +1,20 @@
#!/bin/bash
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
echo "Running hook ${file}"
"${file}"
fi
done
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting MariaDB."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting MariaDB..."
exec /usr/local/bin/docker-entrypoint.sh "$@"

View File

@@ -1,6 +1,10 @@
FROM alpine:3.15
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM alpine:3.21
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
WORKDIR /app
ARG PIP_BREAK_SYSTEM_PACKAGES=1
ENV XTABLES_LIBDIR /usr/lib/xtables
ENV PYTHON_IPTABLES_XTABLES_VERSION 12
ENV IPTABLES_LIBDIR /usr/lib
@@ -12,12 +16,16 @@ RUN apk add --virtual .build-deps \
openssl-dev \
&& apk add -U python3 \
iptables \
iptables-dev \
ip6tables \
xtables-addons \
nftables \
tzdata \
py3-pip \
py3-nftables \
musl-dev \
&& pip3 install --ignore-installed --upgrade pip \
jsonschema \
python-iptables \
redis \
ipaddress \
@@ -26,5 +34,10 @@ RUN apk add --virtual .build-deps \
# && pip3 install --upgrade pip python-iptables==0.13.0 redis ipaddress dnspython \
COPY server.py /
CMD ["python3", "-u", "/server.py"]
COPY modules /app/modules
COPY main.py /app/
COPY ./docker-entrypoint.sh /app/
RUN chmod +x /app/docker-entrypoint.sh
CMD ["/bin/sh", "-c", "/app/docker-entrypoint.sh"]

View File

@@ -0,0 +1,29 @@
#!/bin/sh
backend=iptables
nft list table ip filter &>/dev/null
nftables_found=$?
iptables -L -n &>/dev/null
iptables_found=$?
if [ $nftables_found -lt $iptables_found ]; then
backend=nftables
fi
if [ $nftables_found -gt $iptables_found ]; then
backend=iptables
fi
if [ $nftables_found -eq 0 ] && [ $nftables_found -eq $iptables_found ]; then
nftables_lines=$(nft list ruleset | wc -l)
iptables_lines=$(iptables-save | wc -l)
if [ $nftables_lines -gt $iptables_lines ]; then
backend=nftables
else
backend=iptables
fi
fi
exec python -u /app/main.py $backend

View File

@@ -0,0 +1,502 @@
#!/usr/bin/env python3
import re
import os
import sys
import time
import atexit
import signal
import ipaddress
from collections import Counter
from random import randint
from threading import Thread
from threading import Lock
import redis
import json
import dns.resolver
import dns.exception
import uuid
from modules.Logger import Logger
from modules.IPTables import IPTables
from modules.NFTables import NFTables
# globals
WHITELIST = []
BLACKLIST= []
bans = {}
quit_now = False
exit_code = 0
lock = Lock()
chain_name = "MAILCOW"
r = None
pubsub = None
clear_before_quit = False
def refreshF2boptions():
global f2boptions
global quit_now
global exit_code
f2boptions = {}
if not r.get('F2B_OPTIONS'):
f2boptions['ban_time'] = r.get('F2B_BAN_TIME')
f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME')
f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT')
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS')
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW')
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4')
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6')
else:
try:
f2boptions = json.loads(r.get('F2B_OPTIONS'))
except ValueError:
logger.logCrit('Error loading F2B options: F2B_OPTIONS is not json')
quit_now = True
exit_code = 2
verifyF2boptions(f2boptions)
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
def verifyF2boptions(f2boptions):
verifyF2boption(f2boptions,'ban_time', 1800)
verifyF2boption(f2boptions,'max_ban_time', 10000)
verifyF2boption(f2boptions,'ban_time_increment', True)
verifyF2boption(f2boptions,'max_attempts', 10)
verifyF2boption(f2boptions,'retry_window', 600)
verifyF2boption(f2boptions,'netban_ipv4', 32)
verifyF2boption(f2boptions,'netban_ipv6', 128)
verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4()))
verifyF2boption(f2boptions,'manage_external', 0)
def verifyF2boption(f2boptions, f2boption, f2bdefault):
f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
def refreshF2bregex():
global f2bregex
global quit_now
global exit_code
if not r.get('F2B_REGEX'):
f2bregex = {}
f2bregex[1] = r'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
f2bregex[2] = r'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
f2bregex[3] = r'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
f2bregex[4] = r'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
f2bregex[5] = r'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
f2bregex[6] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): Password mismatch \(SHA1 of given password: [a-f0-9]+\)'
f2bregex[7] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): unknown user \(SHA1 of given password: [a-f0-9]+\)'
f2bregex[8] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
else:
try:
f2bregex = {}
f2bregex = json.loads(r.get('F2B_REGEX'))
except ValueError:
logger.logCrit('Error loading F2B options: F2B_REGEX is not json')
quit_now = True
exit_code = 2
def get_ip(address):
ip = ipaddress.ip_address(address)
if type(ip) is ipaddress.IPv6Address and ip.ipv4_mapped:
ip = ip.ipv4_mapped
if ip.is_private or ip.is_loopback:
return False
return ip
def ban(address):
global f2boptions
global lock
refreshF2boptions()
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
RETRY_WINDOW = int(f2boptions['retry_window'])
NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4'])
NETBAN_IPV6 = '/' + str(f2boptions['netban_ipv6'])
ip = get_ip(address)
if not ip: return
address = str(ip)
self_network = ipaddress.ip_network(address)
with lock:
temp_whitelist = set(WHITELIST)
if temp_whitelist:
for wl_key in temp_whitelist:
wl_net = ipaddress.ip_network(wl_key, False)
if wl_net.overlaps(self_network):
logger.logInfo('Address %s is whitelisted by rule %s' % (self_network, wl_net))
return
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
net = str(net)
if not net in bans:
bans[net] = {'attempts': 0, 'last_attempt': 0, 'ban_counter': 0}
current_attempt = time.time()
if current_attempt - bans[net]['last_attempt'] > RETRY_WINDOW:
bans[net]['attempts'] = 0
bans[net]['attempts'] += 1
bans[net]['last_attempt'] = current_attempt
if bans[net]['attempts'] >= MAX_ATTEMPTS:
cur_time = int(round(time.time()))
NET_BAN_TIME = calcNetBanTime(bans[net]['ban_counter'])
logger.logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
if type(ip) is ipaddress.IPv4Address and int(f2boptions['manage_external']) != 1:
with lock:
tables.banIPv4(net)
elif int(f2boptions['manage_external']) != 1:
with lock:
tables.banIPv6(net)
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
else:
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
def unban(net):
global lock
if not net in bans:
logger.logInfo('%s is not banned, skipping unban and deleting from queue (if any)' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
return
logger.logInfo('Unbanning %s' % net)
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
with lock:
tables.unbanIPv4(net)
else:
with lock:
tables.unbanIPv6(net)
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
if net in bans:
bans[net]['attempts'] = 0
bans[net]['ban_counter'] += 1
def permBan(net, unban=False):
global f2boptions
global lock
is_unbanned = False
is_banned = False
if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network:
with lock:
if unban:
is_unbanned = tables.unbanIPv4(net)
elif int(f2boptions['manage_external']) != 1:
is_banned = tables.banIPv4(net)
else:
with lock:
if unban:
is_unbanned = tables.unbanIPv6(net)
elif int(f2boptions['manage_external']) != 1:
is_banned = tables.banIPv6(net)
if is_unbanned:
r.hdel('F2B_PERM_BANS', '%s' % net)
logger.logCrit('Removed host/network %s from blacklist' % net)
elif is_banned:
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
logger.logCrit('Added host/network %s to blacklist' % net)
def clear():
global lock
logger.logInfo('Clearing all bans')
for net in bans.copy():
unban(net)
with lock:
tables.clearIPv4Table()
tables.clearIPv6Table()
try:
if r is not None:
r.delete('F2B_ACTIVE_BANS')
r.delete('F2B_PERM_BANS')
except Exception as ex:
logger.logWarn('Error clearing redis keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex)
def watch():
global pubsub
global quit_now
global exit_code
logger.logInfo('Watching Redis channel F2B_CHANNEL')
pubsub.subscribe('F2B_CHANNEL')
while not quit_now:
try:
for item in pubsub.listen():
refreshF2bregex()
for rule_id, rule_regex in f2bregex.items():
if item['data'] and item['type'] == 'message':
try:
result = re.search(rule_regex, item['data'])
except re.error:
result = False
if result:
addr = result.group(1)
ip = ipaddress.ip_address(addr)
if ip.is_private or ip.is_loopback:
continue
logger.logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
ban(addr)
except Exception as ex:
logger.logWarn('Error reading log line from pubsub: %s' % ex)
pubsub = None
quit_now = True
exit_code = 2
def snat4(snat_target):
global lock
global quit_now
while not quit_now:
time.sleep(10)
with lock:
tables.snat4(snat_target, os.getenv('IPV4_NETWORK', '172.22.1') + '.0/24')
def snat6(snat_target):
global lock
global quit_now
while not quit_now:
time.sleep(10)
with lock:
tables.snat6(snat_target, os.getenv('IPV6_NETWORK', 'fd4d:6169:6c63:6f77::/64'))
def autopurge():
global f2boptions
while not quit_now:
time.sleep(10)
refreshF2boptions()
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
if QUEUE_UNBAN:
for net in QUEUE_UNBAN:
unban(str(net))
for net in bans.copy():
if bans[net]['attempts'] >= MAX_ATTEMPTS:
NET_BAN_TIME = calcNetBanTime(bans[net]['ban_counter'])
TIME_SINCE_LAST_ATTEMPT = time.time() - bans[net]['last_attempt']
if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME:
unban(net)
def mailcowChainOrder():
global lock
global quit_now
global exit_code
while not quit_now:
time.sleep(10)
with lock:
quit_now, exit_code = tables.checkIPv4ChainOrder()
if quit_now: return
quit_now, exit_code = tables.checkIPv6ChainOrder()
def calcNetBanTime(ban_counter):
global f2boptions
BAN_TIME = int(f2boptions['ban_time'])
MAX_BAN_TIME = int(f2boptions['max_ban_time'])
BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment'])
NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** ban_counter
NET_BAN_TIME = max([BAN_TIME, min([NET_BAN_TIME, MAX_BAN_TIME])])
return NET_BAN_TIME
def isIpNetwork(address):
try:
ipaddress.ip_network(address, False)
except ValueError:
return False
return True
def genNetworkList(list):
resolver = dns.resolver.Resolver()
hostnames = []
networks = []
for key in list:
if isIpNetwork(key):
networks.append(key)
else:
hostnames.append(key)
for hostname in hostnames:
hostname_ips = []
for rdtype in ['A', 'AAAA']:
try:
answer = resolver.resolve(qname=hostname, rdtype=rdtype, lifetime=3)
except dns.exception.Timeout:
logger.logInfo('Hostname %s timedout on resolve' % hostname)
break
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
continue
except dns.exception.DNSException as dnsexception:
logger.logInfo('%s' % dnsexception)
continue
for rdata in answer:
hostname_ips.append(rdata.to_text())
networks.extend(hostname_ips)
return set(networks)
def whitelistUpdate():
global lock
global quit_now
global WHITELIST
while not quit_now:
start_time = time.time()
list = r.hgetall('F2B_WHITELIST')
new_whitelist = []
if list:
new_whitelist = genNetworkList(list)
with lock:
if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist
logger.logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate():
global quit_now
global BLACKLIST
while not quit_now:
start_time = time.time()
list = r.hgetall('F2B_BLACKLIST')
new_blacklist = []
if list:
new_blacklist = genNetworkList(list)
if Counter(new_blacklist) != Counter(BLACKLIST):
addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist
logger.logInfo('Blacklist was changed, it has %s entries' % len(BLACKLIST))
if addban:
for net in addban:
permBan(net=net)
if delban:
for net in delban:
permBan(net=net, unban=True)
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def sigterm_quit(signum, frame):
global clear_before_quit
clear_before_quit = True
sys.exit(exit_code)
def berfore_quit():
if clear_before_quit:
clear()
if pubsub is not None:
pubsub.unsubscribe()
if __name__ == '__main__':
atexit.register(berfore_quit)
signal.signal(signal.SIGTERM, sigterm_quit)
# init Logger
logger = Logger()
# init backend
backend = sys.argv[1]
if backend == "nftables":
logger.logInfo('Using NFTables backend')
tables = NFTables(chain_name, logger)
else:
logger.logInfo('Using IPTables backend')
tables = IPTables(chain_name, logger)
# In case a previous session was killed without cleanup
clear()
# Reinit MAILCOW chain
# Is called before threads start, no locking
logger.logInfo("Initializing mailcow netfilter chain")
tables.initChainIPv4()
tables.initChainIPv6()
if os.getenv("DISABLE_NETFILTER_ISOLATION_RULE").lower() in ("y", "yes"):
logger.logInfo(f"Skipping {chain_name} isolation")
else:
logger.logInfo(f"Setting {chain_name} isolation")
tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP"))
# connect to redis
while True:
try:
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
if "".__eq__(redis_slaveof_ip):
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
else:
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
r.ping()
pubsub = r.pubsub()
except Exception as ex:
print('%s - trying again in 3 seconds' % (ex))
time.sleep(3)
else:
break
logger.set_redis(r)
# rename fail2ban to netfilter
if r.exists('F2B_LOG'):
r.rename('F2B_LOG', 'NETFILTER_LOG')
# clear bans in redis
r.delete('F2B_ACTIVE_BANS')
r.delete('F2B_PERM_BANS')
refreshF2boptions()
watch_thread = Thread(target=watch)
watch_thread.daemon = True
watch_thread.start()
if os.getenv('SNAT_TO_SOURCE') and os.getenv('SNAT_TO_SOURCE') != 'n':
try:
snat_ip = os.getenv('SNAT_TO_SOURCE')
snat_ipo = ipaddress.ip_address(snat_ip)
if type(snat_ipo) is ipaddress.IPv4Address:
snat4_thread = Thread(target=snat4,args=(snat_ip,))
snat4_thread.daemon = True
snat4_thread.start()
except ValueError:
print(os.getenv('SNAT_TO_SOURCE') + ' is not a valid IPv4 address')
if os.getenv('SNAT6_TO_SOURCE') and os.getenv('SNAT6_TO_SOURCE') != 'n':
try:
snat_ip = os.getenv('SNAT6_TO_SOURCE')
snat_ipo = ipaddress.ip_address(snat_ip)
if type(snat_ipo) is ipaddress.IPv6Address:
snat6_thread = Thread(target=snat6,args=(snat_ip,))
snat6_thread.daemon = True
snat6_thread.start()
except ValueError:
print(os.getenv('SNAT6_TO_SOURCE') + ' is not a valid IPv6 address')
autopurge_thread = Thread(target=autopurge)
autopurge_thread.daemon = True
autopurge_thread.start()
mailcowchainwatch_thread = Thread(target=mailcowChainOrder)
mailcowchainwatch_thread.daemon = True
mailcowchainwatch_thread.start()
blacklistupdate_thread = Thread(target=blacklistUpdate)
blacklistupdate_thread.daemon = True
blacklistupdate_thread.start()
whitelistupdate_thread = Thread(target=whitelistUpdate)
whitelistupdate_thread.daemon = True
whitelistupdate_thread.start()
while not quit_now:
time.sleep(0.5)
sys.exit(exit_code)

View File

@@ -0,0 +1,252 @@
import iptc
import time
import os
class IPTables:
def __init__(self, chain_name, logger):
self.chain_name = chain_name
self.logger = logger
def initChainIPv4(self):
if not iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name) in iptc.Table(iptc.Table.FILTER).chains:
iptc.Table(iptc.Table.FILTER).create_chain(self.chain_name)
for c in ['FORWARD', 'INPUT']:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), c)
rule = iptc.Rule()
rule.src = '0.0.0.0/0'
rule.dst = '0.0.0.0/0'
target = iptc.Target(rule, self.chain_name)
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
def initChainIPv6(self):
if not iptc.Chain(iptc.Table6(iptc.Table6.FILTER), self.chain_name) in iptc.Table6(iptc.Table6.FILTER).chains:
iptc.Table6(iptc.Table6.FILTER).create_chain(self.chain_name)
for c in ['FORWARD', 'INPUT']:
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), c)
rule = iptc.Rule6()
rule.src = '::/0'
rule.dst = '::/0'
target = iptc.Target(rule, self.chain_name)
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
def checkIPv4ChainOrder(self):
filter_table = iptc.Table(iptc.Table.FILTER)
filter_table.refresh()
return self.checkChainOrder(filter_table)
def checkIPv6ChainOrder(self):
filter_table = iptc.Table6(iptc.Table6.FILTER)
filter_table.refresh()
return self.checkChainOrder(filter_table)
def checkChainOrder(self, filter_table):
err = False
exit_code = None
forward_chain = iptc.Chain(filter_table, 'FORWARD')
input_chain = iptc.Chain(filter_table, 'INPUT')
for chain in [forward_chain, input_chain]:
target_found = False
for position, item in enumerate(chain.rules):
if item.target.name == self.chain_name:
target_found = True
if position > 2:
self.logger.logCrit('Error in %s chain: %s target not found, restarting container' % (chain.name, self.chain_name))
err = True
exit_code = 2
if not target_found:
self.logger.logCrit('Error in %s chain: %s target not found, restarting container' % (chain.name, self.chain_name))
err = True
exit_code = 2
return err, exit_code
def clearIPv4Table(self):
self.clearTable(iptc.Table(iptc.Table.FILTER))
def clearIPv6Table(self):
self.clearTable(iptc.Table6(iptc.Table6.FILTER))
def clearTable(self, filter_table):
filter_table.autocommit = False
forward_chain = iptc.Chain(filter_table, "FORWARD")
input_chain = iptc.Chain(filter_table, "INPUT")
mailcow_chain = iptc.Chain(filter_table, self.chain_name)
if mailcow_chain in filter_table.chains:
for rule in mailcow_chain.rules:
mailcow_chain.delete_rule(rule)
for rule in forward_chain.rules:
if rule.target.name == self.chain_name:
forward_chain.delete_rule(rule)
for rule in input_chain.rules:
if rule.target.name == self.chain_name:
input_chain.delete_rule(rule)
filter_table.delete_chain(self.chain_name)
filter_table.commit()
filter_table.refresh()
filter_table.autocommit = True
def banIPv4(self, source):
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name)
rule = iptc.Rule()
rule.src = source
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule in chain.rules:
return False
chain.insert_rule(rule)
return True
def banIPv6(self, source):
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), self.chain_name)
rule = iptc.Rule6()
rule.src = source
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule in chain.rules:
return False
chain.insert_rule(rule)
return True
def unbanIPv4(self, source):
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name)
rule = iptc.Rule()
rule.src = source
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules:
return False
chain.delete_rule(rule)
return True
def unbanIPv6(self, source):
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), self.chain_name)
rule = iptc.Rule6()
rule.src = source
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules:
return False
chain.delete_rule(rule)
return True
def snat4(self, snat_target, source):
try:
table = iptc.Table('nat')
table.refresh()
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
new_rule = self.getSnat4Rule(snat_target, source)
if not chain.rules:
# if there are no rules in the chain, insert the new rule directly
self.logger.logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else:
for position, rule in enumerate(chain.rules):
if not hasattr(rule.target, 'parameter'):
continue
match = all((
new_rule.get_src() == rule.get_src(),
new_rule.get_dst() == rule.get_dst(),
new_rule.target.parameters == rule.target.parameters,
new_rule.target.name == rule.target.name
))
if position == 0:
if not match:
self.logger.logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else:
if match:
self.logger.logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
chain.delete_rule(rule)
table.commit()
table.autocommit = True
return True
except:
self.logger.logCrit('Error running SNAT4, retrying...')
return False
def snat6(self, snat_target, source):
try:
table = iptc.Table6('nat')
table.refresh()
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
new_rule = self.getSnat6Rule(snat_target, source)
if new_rule not in chain.rules:
self.logger.logInfo('Added POSTROUTING rule for source network %s to SNAT target %s' % (new_rule.src, snat_target))
chain.insert_rule(new_rule)
else:
for position, item in enumerate(chain.rules):
if item == new_rule:
if position != 0:
chain.delete_rule(new_rule)
table.commit()
table.autocommit = True
except:
self.logger.logCrit('Error running SNAT6, retrying...')
def getSnat4Rule(self, snat_target, source):
rule = iptc.Rule()
rule.src = source
rule.dst = '!' + rule.src
target = rule.create_target("SNAT")
target.to_source = snat_target
match = rule.create_match("comment")
match.comment = f'{int(round(time.time()))}'
return rule
def getSnat6Rule(self, snat_target, source):
rule = iptc.Rule6()
rule.src = source
rule.dst = '!' + rule.src
target = rule.create_target("SNAT")
target.to_source = snat_target
return rule
def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""):
try:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name)
# insert mailcow isolation rule
rule = iptc.Rule()
rule.in_interface = f'!{_interface}'
rule.out_interface = _interface
rule.protocol = 'tcp'
rule.create_target("DROP")
match = rule.create_match("multiport")
match.dports = ','.join(map(str, _dports))
if rule in chain.rules:
chain.delete_rule(rule)
chain.insert_rule(rule, position=0)
# insert mailcow isolation exception rule
if _allow != "":
rule = iptc.Rule()
rule.src = _allow
rule.in_interface = f'!{_interface}'
rule.out_interface = _interface
rule.protocol = 'tcp'
rule.create_target("ACCEPT")
match = rule.create_match("multiport")
match.dports = ','.join(map(str, _dports))
if rule in chain.rules:
chain.delete_rule(rule)
chain.insert_rule(rule, position=0)
return True
except Exception as e:
self.logger.logCrit(f"Error adding {self.chain_name} isolation: {e}")
return False

View File

@@ -0,0 +1,30 @@
import time
import json
class Logger:
def __init__(self):
self.r = None
def set_redis(self, redis):
self.r = redis
def log(self, priority, message):
tolog = {}
tolog['time'] = int(round(time.time()))
tolog['priority'] = priority
tolog['message'] = message
print(message)
if self.r is not None:
try:
self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
except Exception as ex:
print('Failed logging to redis: %s' % (ex))
def logWarn(self, message):
self.log('warn', message)
def logCrit(self, message):
self.log('crit', message)
def logInfo(self, message):
self.log('info', message)

View File

@@ -0,0 +1,659 @@
import nftables
import ipaddress
import os
class NFTables:
def __init__(self, chain_name, logger):
self.chain_name = chain_name
self.logger = logger
self.nft = nftables.Nftables()
self.nft.set_json_output(True)
self.nft.set_handle_output(True)
self.nft_chain_names = {'ip': {'filter': {'input': '', 'forward': ''}, 'nat': {'postrouting': ''} },
'ip6': {'filter': {'input': '', 'forward': ''}, 'nat': {'postrouting': ''} } }
self.search_current_chains()
def initChainIPv4(self):
self.insert_mailcow_chains("ip")
def initChainIPv6(self):
self.insert_mailcow_chains("ip6")
def checkIPv4ChainOrder(self):
return self.checkChainOrder("ip")
def checkIPv6ChainOrder(self):
return self.checkChainOrder("ip6")
def checkChainOrder(self, filter_table):
err = False
exit_code = None
for chain in ['input', 'forward']:
chain_position = self.check_mailcow_chains(filter_table, chain)
if chain_position is None: continue
if chain_position is False:
self.logger.logCrit(f'MAILCOW target not found in {filter_table} {chain} table, restarting container to fix it...')
err = True
exit_code = 2
if chain_position > 0:
chain_position += 1
self.logger.logCrit(f'MAILCOW target is in position {chain_position} in the {filter_table} {chain} table, restarting container to fix it...')
err = True
exit_code = 2
return err, exit_code
def clearIPv4Table(self):
self.clearTable("ip")
def clearIPv6Table(self):
self.clearTable("ip6")
def clearTable(self, _family):
is_empty_dict = True
json_command = self.get_base_dict()
chain_handle = self.get_chain_handle(_family, "filter", self.chain_name)
# if no handle, the chain doesn't exists
if chain_handle is not None:
is_empty_dict = False
# flush chain
mailcow_chain = {'family': _family, 'table': 'filter', 'name': self.chain_name}
flush_chain = {'flush': {'chain': mailcow_chain}}
json_command["nftables"].append(flush_chain)
# remove rule in forward chain
# remove rule in input chain
chains_family = [self.nft_chain_names[_family]['filter']['input'],
self.nft_chain_names[_family]['filter']['forward'] ]
for chain_base in chains_family:
if not chain_base: continue
rules_handle = self.get_rules_handle(_family, "filter", chain_base)
if rules_handle is not None:
for r_handle in rules_handle:
is_empty_dict = False
mailcow_rule = {'family':_family,
'table': 'filter',
'chain': chain_base,
'handle': r_handle }
delete_rules = {'delete': {'rule': mailcow_rule} }
json_command["nftables"].append(delete_rules)
# remove chain
# after delete all rules referencing this chain
if chain_handle is not None:
mc_chain_handle = {'family':_family,
'table': 'filter',
'name': self.chain_name,
'handle': chain_handle }
delete_chain = {'delete': {'chain': mc_chain_handle} }
json_command["nftables"].append(delete_chain)
if is_empty_dict == False:
if self.nft_exec_dict(json_command):
self.logger.logInfo(f"Clear completed: {_family}")
def banIPv4(self, source):
ban_dict = self.get_ban_ip_dict(source, "ip")
return self.nft_exec_dict(ban_dict)
def banIPv6(self, source):
ban_dict = self.get_ban_ip_dict(source, "ip6")
return self.nft_exec_dict(ban_dict)
def unbanIPv4(self, source):
unban_dict = self.get_unban_ip_dict(source, "ip")
if not unban_dict:
return False
return self.nft_exec_dict(unban_dict)
def unbanIPv6(self, source):
unban_dict = self.get_unban_ip_dict(source, "ip6")
if not unban_dict:
return False
return self.nft_exec_dict(unban_dict)
def snat4(self, snat_target, source):
self.snat_rule("ip", snat_target, source)
def snat6(self, snat_target, source):
self.snat_rule("ip6", snat_target, source)
def nft_exec_dict(self, query: dict):
if not query: return False
rc, output, error = self.nft.json_cmd(query)
if rc != 0:
#self.logger.logCrit(f"Nftables Error: {error}")
return False
# Prevent returning False or empty string on commands that do not produce output
if rc == 0 and len(output) == 0:
return True
return output
def get_base_dict(self):
return {'nftables': [{ 'metainfo': { 'json_schema_version': 1} } ] }
def search_current_chains(self):
nft_chain_priority = {'ip': {'filter': {'input': None, 'forward': None}, 'nat': {'postrouting': None} },
'ip6': {'filter': {'input': None, 'forward': None}, 'nat': {'postrouting': None} } }
# Command: 'nft list chains'
_list = {'list' : {'chains': 'null'} }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if kernel_ruleset:
for _object in kernel_ruleset['nftables']:
chain = _object.get("chain")
if not chain: continue
_family = chain['family']
_table = chain['table']
_hook = chain.get("hook")
_priority = chain.get("prio")
_name = chain['name']
if _family not in self.nft_chain_names: continue
if _table not in self.nft_chain_names[_family]: continue
if _hook not in self.nft_chain_names[_family][_table]: continue
if _priority is None: continue
_saved_priority = nft_chain_priority[_family][_table][_hook]
if _saved_priority is None or _priority < _saved_priority:
# at this point, we know the chain has:
# hook and priority set
# and it has the lowest priority
nft_chain_priority[_family][_table][_hook] = _priority
self.nft_chain_names[_family][_table][_hook] = _name
def search_for_chain(self, kernel_ruleset: dict, chain_name: str):
found = False
for _object in kernel_ruleset["nftables"]:
chain = _object.get("chain")
if not chain:
continue
ch_name = chain.get("name")
if ch_name == chain_name:
found = True
break
return found
def get_chain_dict(self, _family: str, _name: str):
# nft (add | create) chain [<family>] <table> <name>
_chain_opts = {'family': _family, 'table': 'filter', 'name': _name }
_add = {'add': {'chain': _chain_opts} }
final_chain = self.get_base_dict()
final_chain["nftables"].append(_add)
return final_chain
def get_mailcow_jump_rule_dict(self, _family: str, _chain: str):
_jump_rule = self.get_base_dict()
_expr_opt=[]
_expr_counter = {'family': _family, 'table': 'filter', 'packets': 0, 'bytes': 0}
_counter_dict = {'counter': _expr_counter}
_expr_opt.append(_counter_dict)
_jump_opts = {'jump': {'target': self.chain_name} }
_expr_opt.append(_jump_opts)
_rule_params = {'family': _family,
'table': 'filter',
'chain': _chain,
'expr': _expr_opt,
'comment': "mailcow" }
_add_rule = {'insert': {'rule': _rule_params} }
_jump_rule["nftables"].append(_add_rule)
return _jump_rule
def insert_mailcow_chains(self, _family: str):
nft_input_chain = self.nft_chain_names[_family]['filter']['input']
nft_forward_chain = self.nft_chain_names[_family]['filter']['forward']
# Command: 'nft list table <family> filter'
_table_opts = {'family': _family, 'name': 'filter'}
_list = {'list': {'table': _table_opts} }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if kernel_ruleset:
# chain
if not self.search_for_chain(kernel_ruleset, self.chain_name):
cadena = self.get_chain_dict(_family, self.chain_name)
if self.nft_exec_dict(cadena):
self.logger.logInfo(f"MAILCOW {_family} chain created successfully.")
input_jump_found, forward_jump_found = False, False
for _object in kernel_ruleset["nftables"]:
if not _object.get("rule"):
continue
rule = _object["rule"]
if nft_input_chain and rule["chain"] == nft_input_chain:
if rule.get("comment") and rule["comment"] == "mailcow":
input_jump_found = True
if nft_forward_chain and rule["chain"] == nft_forward_chain:
if rule.get("comment") and rule["comment"] == "mailcow":
forward_jump_found = True
if not input_jump_found:
command = self.get_mailcow_jump_rule_dict(_family, nft_input_chain)
self.nft_exec_dict(command)
if not forward_jump_found:
command = self.get_mailcow_jump_rule_dict(_family, nft_forward_chain)
self.nft_exec_dict(command)
def delete_nat_rule(self, _family:str, _chain: str, _handle:str):
delete_command = self.get_base_dict()
_rule_opts = {'family': _family,
'table': 'nat',
'chain': _chain,
'handle': _handle }
_delete = {'delete': {'rule': _rule_opts} }
delete_command["nftables"].append(_delete)
return self.nft_exec_dict(delete_command)
def delete_filter_rule(self, _family:str, _chain: str, _handle:str):
delete_command = self.get_base_dict()
_rule_opts = {'family': _family,
'table': 'filter',
'chain': _chain,
'handle': _handle }
_delete = {'delete': {'rule': _rule_opts} }
delete_command["nftables"].append(_delete)
return self.nft_exec_dict(delete_command)
def snat_rule(self, _family: str, snat_target: str, source_address: str):
chain_name = self.nft_chain_names[_family]['nat']['postrouting']
# no postrouting chain, may occur if docker has ipv6 disabled.
if not chain_name: return
# Command: nft list chain <family> nat <chain_name>
_chain_opts = {'family': _family, 'table': 'nat', 'name': chain_name}
_list = {'list':{'chain': _chain_opts} }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if not kernel_ruleset:
return
rule_position = 0
rule_handle = None
rule_found = False
for _object in kernel_ruleset["nftables"]:
if not _object.get("rule"):
continue
rule = _object["rule"]
if not rule.get("comment") or not rule["comment"] == "mailcow":
rule_position +=1
continue
rule_found = True
rule_handle = rule["handle"]
break
dest_net = ipaddress.ip_network(source_address, strict=False)
target_net = ipaddress.ip_network(snat_target, strict=False)
if rule_found:
saddr_ip = rule["expr"][0]["match"]["right"]["prefix"]["addr"]
saddr_len = int(rule["expr"][0]["match"]["right"]["prefix"]["len"])
daddr_ip = rule["expr"][1]["match"]["right"]["prefix"]["addr"]
daddr_len = int(rule["expr"][1]["match"]["right"]["prefix"]["len"])
target_ip = rule["expr"][3]["snat"]["addr"]
saddr_net = ipaddress.ip_network(saddr_ip + '/' + str(saddr_len), strict=False)
daddr_net = ipaddress.ip_network(daddr_ip + '/' + str(daddr_len), strict=False)
current_target_net = ipaddress.ip_network(target_ip, strict=False)
match = all((
dest_net == saddr_net,
dest_net == daddr_net,
target_net == current_target_net
))
try:
if rule_position == 0:
if not match:
# Position 0 , it is a mailcow rule , but it does not have the same parameters
if self.delete_nat_rule(_family, chain_name, rule_handle):
self.logger.logInfo(f'Remove rule for source network {saddr_net} to SNAT target {target_net} from {_family} nat {chain_name} chain, rule does not match configured parameters')
else:
# Position > 0 and is mailcow rule
if self.delete_nat_rule(_family, chain_name, rule_handle):
self.logger.logInfo(f'Remove rule for source network {saddr_net} to SNAT target {target_net} from {_family} nat {chain_name} chain, rule is at position {rule_position}')
except:
self.logger.logCrit(f"Error running SNAT on {_family}, retrying..." )
else:
# rule not found
json_command = self.get_base_dict()
try:
snat_dict = {'snat': {'addr': str(target_net.network_address)} }
expr_counter = {'family': _family, 'table': 'nat', 'packets': 0, 'bytes': 0}
counter_dict = {'counter': expr_counter}
prefix_dict = {'prefix': {'addr': str(dest_net.network_address), 'len': int(dest_net.prefixlen)} }
payload_dict = {'payload': {'protocol': _family, 'field': "saddr"} }
match_dict1 = {'match': {'op': '==', 'left': payload_dict, 'right': prefix_dict} }
payload_dict2 = {'payload': {'protocol': _family, 'field': "daddr"} }
match_dict2 = {'match': {'op': '!=', 'left': payload_dict2, 'right': prefix_dict } }
expr_list = [
match_dict1,
match_dict2,
counter_dict,
snat_dict
]
rule_fields = {'family': _family,
'table': 'nat',
'chain': chain_name,
'comment': "mailcow",
'expr': expr_list }
insert_dict = {'insert': {'rule': rule_fields} }
json_command["nftables"].append(insert_dict)
if self.nft_exec_dict(json_command):
self.logger.logInfo(f'Added {_family} nat {chain_name} rule for source network {dest_net} to {target_net}')
except:
self.logger.logCrit(f"Error running SNAT on {_family}, retrying...")
def get_chain_handle(self, _family: str, _table: str, chain_name: str):
chain_handle = None
# Command: 'nft list chains {family}'
_list = {'list': {'chains': {'family': _family} } }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if kernel_ruleset:
for _object in kernel_ruleset["nftables"]:
if not _object.get("chain"):
continue
chain = _object["chain"]
if chain["family"] == _family and chain["table"] == _table and chain["name"] == chain_name:
chain_handle = chain["handle"]
break
return chain_handle
def get_rules_handle(self, _family: str, _table: str, chain_name: str, _comment_filter = "mailcow"):
rule_handle = []
# Command: 'nft list chain {family} {table} {chain_name}'
_chain_opts = {'family': _family, 'table': _table, 'name': chain_name}
_list = {'list': {'chain': _chain_opts} }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if kernel_ruleset:
for _object in kernel_ruleset["nftables"]:
if not _object.get("rule"):
continue
rule = _object["rule"]
if rule["family"] == _family and rule["table"] == _table and rule["chain"] == chain_name:
if rule.get("comment") and rule["comment"] == _comment_filter:
rule_handle.append(rule["handle"])
return rule_handle
def get_ban_ip_dict(self, ipaddr: str, _family: str):
json_command = self.get_base_dict()
expr_opt = []
ipaddr_net = ipaddress.ip_network(ipaddr, strict=False)
right_dict = {'prefix': {'addr': str(ipaddr_net.network_address), 'len': int(ipaddr_net.prefixlen) } }
left_dict = {'payload': {'protocol': _family, 'field': 'saddr'} }
match_dict = {'op': '==', 'left': left_dict, 'right': right_dict }
expr_opt.append({'match': match_dict})
counter_dict = {'counter': {'family': _family, 'table': "filter", 'packets': 0, 'bytes': 0} }
expr_opt.append(counter_dict)
expr_opt.append({'drop': "null"})
rule_dict = {'family': _family, 'table': "filter", 'chain': self.chain_name, 'expr': expr_opt}
base_dict = {'insert': {'rule': rule_dict} }
json_command["nftables"].append(base_dict)
return json_command
def get_unban_ip_dict(self, ipaddr:str, _family: str):
json_command = self.get_base_dict()
# Command: 'nft list chain {s_family} filter MAILCOW'
_chain_opts = {'family': _family, 'table': 'filter', 'name': self.chain_name}
_list = {'list': {'chain': _chain_opts} }
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
rule_handle = None
if kernel_ruleset:
for _object in kernel_ruleset["nftables"]:
if not _object.get("rule"):
continue
rule = _object["rule"]["expr"][0]["match"]
if not "payload" in rule["left"]:
continue
left_opt = rule["left"]["payload"]
if not left_opt["protocol"] == _family:
continue
if not left_opt["field"] =="saddr":
continue
# ip currently banned
rule_right = rule["right"]
if isinstance(rule_right, dict):
current_rule_ip = rule_right["prefix"]["addr"] + '/' + str(rule_right["prefix"]["len"])
else:
current_rule_ip = rule_right
current_rule_net = ipaddress.ip_network(current_rule_ip)
# ip to ban
candidate_net = ipaddress.ip_network(ipaddr, strict=False)
if current_rule_net == candidate_net:
rule_handle = _object["rule"]["handle"]
break
if rule_handle is not None:
mailcow_rule = {'family': _family, 'table': 'filter', 'chain': self.chain_name, 'handle': rule_handle}
delete_rule = {'delete': {'rule': mailcow_rule} }
json_command["nftables"].append(delete_rule)
else:
return False
return json_command
def check_mailcow_chains(self, family: str, chain: str):
position = 0
rule_found = False
chain_name = self.nft_chain_names[family]['filter'][chain]
if not chain_name: return None
_chain_opts = {'family': family, 'table': 'filter', 'name': chain_name}
_list = {'list': {'chain': _chain_opts}}
command = self.get_base_dict()
command['nftables'].append(_list)
kernel_ruleset = self.nft_exec_dict(command)
if kernel_ruleset:
for _object in kernel_ruleset["nftables"]:
if not _object.get("rule"):
continue
rule = _object["rule"]
if rule.get("comment") and rule["comment"] == "mailcow":
rule_found = True
break
position+=1
return position if rule_found else False
def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""):
family = "ip"
table = "filter"
comment_filter_drop = "mailcow isolation"
comment_filter_allow = "mailcow isolation allow"
json_command = self.get_base_dict()
# Delete old mailcow isolation rules
handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_drop)
for handle in handles:
self.delete_filter_rule(family, self.chain_name, handle)
handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_allow)
for handle in handles:
self.delete_filter_rule(family, self.chain_name, handle)
# insert mailcow isolation rule
_match_dict_drop = [
{
"match": {
"op": "!=",
"left": {
"meta": {
"key": "iifname"
}
},
"right": _interface
}
},
{
"match": {
"op": "==",
"left": {
"meta": {
"key": "oifname"
}
},
"right": _interface
}
},
{
"match": {
"op": "==",
"left": {
"payload": {
"protocol": "tcp",
"field": "dport"
}
},
"right": {
"set": _dports
}
}
},
{
"counter": {
"packets": 0,
"bytes": 0
}
},
{
"drop": None
}
]
rule_drop = { "insert": { "rule": {
"family": family,
"table": table,
"chain": self.chain_name,
"comment": comment_filter_drop,
"expr": _match_dict_drop
}}}
json_command["nftables"].append(rule_drop)
# insert mailcow isolation allow rule
if _allow != "":
_match_dict_allow = [
{
"match": {
"op": "==",
"left": {
"payload": {
"protocol": "ip",
"field": "saddr"
}
},
"right": _allow
}
},
{
"match": {
"op": "!=",
"left": {
"meta": {
"key": "iifname"
}
},
"right": _interface
}
},
{
"match": {
"op": "==",
"left": {
"meta": {
"key": "oifname"
}
},
"right": _interface
}
},
{
"match": {
"op": "==",
"left": {
"payload": {
"protocol": "tcp",
"field": "dport"
}
},
"right": {
"set": _dports
}
}
},
{
"counter": {
"packets": 0,
"bytes": 0
}
},
{
"accept": None
}
]
rule_allow = { "insert": { "rule": {
"family": family,
"table": table,
"chain": self.chain_name,
"comment": comment_filter_allow,
"expr": _match_dict_allow
}}}
json_command["nftables"].append(rule_allow)
success = self.nft_exec_dict(json_command)
if success == False:
self.logger.logCrit(f"Error adding {self.chain_name} isolation")
return False
return True

View File

@@ -1,578 +0,0 @@
#!/usr/bin/env python3
import re
import os
import sys
import time
import atexit
import signal
import ipaddress
from collections import Counter
from random import randint
from threading import Thread
from threading import Lock
import redis
import json
import iptc
import dns.resolver
import dns.exception
while True:
try:
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
if "".__eq__(redis_slaveof_ip):
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0)
else:
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0)
r.ping()
except Exception as ex:
print('%s - trying again in 3 seconds' % (ex))
time.sleep(3)
else:
break
pubsub = r.pubsub()
WHITELIST = []
BLACKLIST= []
bans = {}
quit_now = False
exit_code = 0
lock = Lock()
def log(priority, message):
tolog = {}
tolog['time'] = int(round(time.time()))
tolog['priority'] = priority
tolog['message'] = message
r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
print(message)
def logWarn(message):
log('warn', message)
def logCrit(message):
log('crit', message)
def logInfo(message):
log('info', message)
def refreshF2boptions():
global f2boptions
global quit_now
global exit_code
if not r.get('F2B_OPTIONS'):
f2boptions = {}
f2boptions['ban_time'] = int
f2boptions['max_attempts'] = int
f2boptions['retry_window'] = int
f2boptions['netban_ipv4'] = int
f2boptions['netban_ipv6'] = int
f2boptions['ban_time'] = r.get('F2B_BAN_TIME') or 1800
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS') or 10
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') or 600
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') or 32
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6') or 128
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
else:
try:
f2boptions = {}
f2boptions = json.loads(r.get('F2B_OPTIONS'))
except ValueError:
print('Error loading F2B options: F2B_OPTIONS is not json')
quit_now = True
exit_code = 2
def refreshF2bregex():
global f2bregex
global quit_now
global exit_code
if not r.get('F2B_REGEX'):
f2bregex = {}
f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
f2bregex[6] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
f2bregex[7] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
f2bregex[8] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
else:
try:
f2bregex = {}
f2bregex = json.loads(r.get('F2B_REGEX'))
except ValueError:
print('Error loading F2B options: F2B_REGEX is not json')
quit_now = True
exit_code = 2
if r.exists('F2B_LOG'):
r.rename('F2B_LOG', 'NETFILTER_LOG')
def mailcowChainOrder():
global lock
global quit_now
global exit_code
while not quit_now:
time.sleep(10)
with lock:
filter4_table = iptc.Table(iptc.Table.FILTER)
filter6_table = iptc.Table6(iptc.Table6.FILTER)
filter4_table.refresh()
filter6_table.refresh()
for f in [filter4_table, filter6_table]:
forward_chain = iptc.Chain(f, 'FORWARD')
input_chain = iptc.Chain(f, 'INPUT')
for chain in [forward_chain, input_chain]:
target_found = False
for position, item in enumerate(chain.rules):
if item.target.name == 'MAILCOW':
target_found = True
if position > 2:
logCrit('Error in %s chain order: MAILCOW on position %d, restarting container' % (chain.name, position))
quit_now = True
exit_code = 2
if not target_found:
logCrit('Error in %s chain: MAILCOW target not found, restarting container' % (chain.name))
quit_now = True
exit_code = 2
def ban(address):
global lock
refreshF2boptions()
BAN_TIME = int(f2boptions['ban_time'])
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
RETRY_WINDOW = int(f2boptions['retry_window'])
NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4'])
NETBAN_IPV6 = '/' + str(f2boptions['netban_ipv6'])
ip = ipaddress.ip_address(address)
if type(ip) is ipaddress.IPv6Address and ip.ipv4_mapped:
ip = ip.ipv4_mapped
address = str(ip)
if ip.is_private or ip.is_loopback:
return
self_network = ipaddress.ip_network(address)
with lock:
temp_whitelist = set(WHITELIST)
if temp_whitelist:
for wl_key in temp_whitelist:
wl_net = ipaddress.ip_network(wl_key, False)
if wl_net.overlaps(self_network):
logInfo('Address %s is whitelisted by rule %s' % (self_network, wl_net))
return
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
net = str(net)
if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW:
bans[net] = { 'attempts': 0 }
active_window = RETRY_WINDOW
else:
active_window = time.time() - bans[net]['last_attempt']
bans[net]['attempts'] += 1
bans[net]['last_attempt'] = time.time()
active_window = time.time() - bans[net]['last_attempt']
if bans[net]['attempts'] >= MAX_ATTEMPTS:
cur_time = int(round(time.time()))
logCrit('Banning %s for %d minutes' % (net, BAN_TIME / 60))
if type(ip) is ipaddress.IPv4Address:
with lock:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
rule = iptc.Rule()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
else:
with lock:
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
rule = iptc.Rule6()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME)
else:
logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
def unban(net):
global lock
if not net in bans:
logInfo('%s is not banned, skipping unban and deleting from queue (if any)' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
return
logInfo('Unbanning %s' % net)
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
with lock:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
rule = iptc.Rule()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule in chain.rules:
chain.delete_rule(rule)
else:
with lock:
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
rule = iptc.Rule6()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule in chain.rules:
chain.delete_rule(rule)
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
if net in bans:
del bans[net]
def permBan(net, unban=False):
global lock
if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network:
with lock:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
rule = iptc.Rule()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule)
r.hdel('F2B_PERM_BANS', '%s' % net)
else:
with lock:
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
rule = iptc.Rule6()
rule.src = net
target = iptc.Target(rule, "REJECT")
rule.target = target
if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule)
r.hdel('F2B_PERM_BANS', '%s' % net)
def quit(signum, frame):
global quit_now
quit_now = True
def clear():
global lock
logInfo('Clearing all bans')
for net in bans.copy():
unban(net)
with lock:
filter4_table = iptc.Table(iptc.Table.FILTER)
filter6_table = iptc.Table6(iptc.Table6.FILTER)
for filter_table in [filter4_table, filter6_table]:
filter_table.autocommit = False
forward_chain = iptc.Chain(filter_table, "FORWARD")
input_chain = iptc.Chain(filter_table, "INPUT")
mailcow_chain = iptc.Chain(filter_table, "MAILCOW")
if mailcow_chain in filter_table.chains:
for rule in mailcow_chain.rules:
mailcow_chain.delete_rule(rule)
for rule in forward_chain.rules:
if rule.target.name == 'MAILCOW':
forward_chain.delete_rule(rule)
for rule in input_chain.rules:
if rule.target.name == 'MAILCOW':
input_chain.delete_rule(rule)
filter_table.delete_chain("MAILCOW")
filter_table.commit()
filter_table.refresh()
filter_table.autocommit = True
r.delete('F2B_ACTIVE_BANS')
r.delete('F2B_PERM_BANS')
pubsub.unsubscribe()
def watch():
logInfo('Watching Redis channel F2B_CHANNEL')
pubsub.subscribe('F2B_CHANNEL')
global quit_now
global exit_code
while not quit_now:
try:
for item in pubsub.listen():
refreshF2bregex()
for rule_id, rule_regex in f2bregex.items():
if item['data'] and item['type'] == 'message':
try:
result = re.search(rule_regex, item['data'])
except re.error:
result = False
if result:
addr = result.group(1)
ip = ipaddress.ip_address(addr)
if ip.is_private or ip.is_loopback:
continue
logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data']))
ban(addr)
except Exception as ex:
logWarn('Error reading log line from pubsub')
quit_now = True
exit_code = 2
def snat4(snat_target):
global lock
global quit_now
def get_snat4_rule():
rule = iptc.Rule()
rule.src = os.getenv('IPV4_NETWORK', '172.22.1') + '.0/24'
rule.dst = '!' + rule.src
target = rule.create_target("SNAT")
target.to_source = snat_target
return rule
while not quit_now:
time.sleep(10)
with lock:
try:
table = iptc.Table('nat')
table.refresh()
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
if get_snat4_rule() not in chain.rules:
logCrit('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat4_rule().src, snat_target))
chain.insert_rule(get_snat4_rule())
table.commit()
else:
for position, item in enumerate(chain.rules):
if item == get_snat4_rule():
if position != 0:
chain.delete_rule(get_snat4_rule())
table.commit()
table.autocommit = True
except:
print('Error running SNAT4, retrying...')
def snat6(snat_target):
global lock
global quit_now
def get_snat6_rule():
rule = iptc.Rule6()
rule.src = os.getenv('IPV6_NETWORK', 'fd4d:6169:6c63:6f77::/64')
rule.dst = '!' + rule.src
target = rule.create_target("SNAT")
target.to_source = snat_target
return rule
while not quit_now:
time.sleep(10)
with lock:
try:
table = iptc.Table6('nat')
table.refresh()
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
if get_snat6_rule() not in chain.rules:
logInfo('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat6_rule().src, snat_target))
chain.insert_rule(get_snat6_rule())
table.commit()
else:
for position, item in enumerate(chain.rules):
if item == get_snat6_rule():
if position != 0:
chain.delete_rule(get_snat6_rule())
table.commit()
table.autocommit = True
except:
print('Error running SNAT6, retrying...')
def autopurge():
while not quit_now:
time.sleep(10)
refreshF2boptions()
BAN_TIME = int(f2boptions['ban_time'])
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
if QUEUE_UNBAN:
for net in QUEUE_UNBAN:
unban(str(net))
for net in bans.copy():
if bans[net]['attempts'] >= MAX_ATTEMPTS:
if time.time() - bans[net]['last_attempt'] > BAN_TIME:
unban(net)
def isIpNetwork(address):
try:
ipaddress.ip_network(address, False)
except ValueError:
return False
return True
def genNetworkList(list):
resolver = dns.resolver.Resolver()
hostnames = []
networks = []
for key in list:
if isIpNetwork(key):
networks.append(key)
else:
hostnames.append(key)
for hostname in hostnames:
hostname_ips = []
for rdtype in ['A', 'AAAA']:
try:
answer = resolver.resolve(qname=hostname, rdtype=rdtype, lifetime=3)
except dns.exception.Timeout:
logInfo('Hostname %s timedout on resolve' % hostname)
break
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
continue
except dns.exception.DNSException as dnsexception:
logInfo('%s' % dnsexception)
continue
for rdata in answer:
hostname_ips.append(rdata.to_text())
networks.extend(hostname_ips)
return set(networks)
def whitelistUpdate():
global lock
global quit_now
global WHITELIST
while not quit_now:
start_time = time.time()
list = r.hgetall('F2B_WHITELIST')
new_whitelist = []
if list:
new_whitelist = genNetworkList(list)
with lock:
if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate():
global quit_now
global BLACKLIST
while not quit_now:
start_time = time.time()
list = r.hgetall('F2B_BLACKLIST')
new_blacklist = []
if list:
new_blacklist = genNetworkList(list)
if Counter(new_blacklist) != Counter(BLACKLIST):
addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist
logInfo('Blacklist was changed, it has %s entries' % len(BLACKLIST))
if addban:
for net in addban:
permBan(net=net)
if delban:
for net in delban:
permBan(net=net, unban=True)
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def initChain():
# Is called before threads start, no locking
print("Initializing mailcow netfilter chain")
# IPv4
if not iptc.Chain(iptc.Table(iptc.Table.FILTER), "MAILCOW") in iptc.Table(iptc.Table.FILTER).chains:
iptc.Table(iptc.Table.FILTER).create_chain("MAILCOW")
for c in ['FORWARD', 'INPUT']:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), c)
rule = iptc.Rule()
rule.src = '0.0.0.0/0'
rule.dst = '0.0.0.0/0'
target = iptc.Target(rule, "MAILCOW")
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
# IPv6
if not iptc.Chain(iptc.Table6(iptc.Table6.FILTER), "MAILCOW") in iptc.Table6(iptc.Table6.FILTER).chains:
iptc.Table6(iptc.Table6.FILTER).create_chain("MAILCOW")
for c in ['FORWARD', 'INPUT']:
chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), c)
rule = iptc.Rule6()
rule.src = '::/0'
rule.dst = '::/0'
target = iptc.Target(rule, "MAILCOW")
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
if __name__ == '__main__':
# In case a previous session was killed without cleanup
clear()
# Reinit MAILCOW chain
initChain()
watch_thread = Thread(target=watch)
watch_thread.daemon = True
watch_thread.start()
if os.getenv('SNAT_TO_SOURCE') and os.getenv('SNAT_TO_SOURCE') != 'n':
try:
snat_ip = os.getenv('SNAT_TO_SOURCE')
snat_ipo = ipaddress.ip_address(snat_ip)
if type(snat_ipo) is ipaddress.IPv4Address:
snat4_thread = Thread(target=snat4,args=(snat_ip,))
snat4_thread.daemon = True
snat4_thread.start()
except ValueError:
print(os.getenv('SNAT_TO_SOURCE') + ' is not a valid IPv4 address')
if os.getenv('SNAT6_TO_SOURCE') and os.getenv('SNAT6_TO_SOURCE') != 'n':
try:
snat_ip = os.getenv('SNAT6_TO_SOURCE')
snat_ipo = ipaddress.ip_address(snat_ip)
if type(snat_ipo) is ipaddress.IPv6Address:
snat6_thread = Thread(target=snat6,args=(snat_ip,))
snat6_thread.daemon = True
snat6_thread.start()
except ValueError:
print(os.getenv('SNAT6_TO_SOURCE') + ' is not a valid IPv6 address')
autopurge_thread = Thread(target=autopurge)
autopurge_thread.daemon = True
autopurge_thread.start()
mailcowchainwatch_thread = Thread(target=mailcowChainOrder)
mailcowchainwatch_thread.daemon = True
mailcowchainwatch_thread.start()
blacklistupdate_thread = Thread(target=blacklistUpdate)
blacklistupdate_thread.daemon = True
blacklistupdate_thread.start()
whitelistupdate_thread = Thread(target=whitelistUpdate)
whitelistupdate_thread.daemon = True
whitelistupdate_thread.start()
signal.signal(signal.SIGTERM, quit)
atexit.register(clear)
while not quit_now:
time.sleep(0.5)
sys.exit(exit_code)

View File

@@ -0,0 +1,36 @@
FROM nginx:alpine
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN apk add --no-cache nginx \
python3 py3-pip \
supervisor
RUN apk add --no-cache --virtual .build-deps \
gcc \
musl-dev \
python3-dev \
linux-headers \
&& pip install --break-system-packages psutil \
&& apk del .build-deps
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython
RUN mkdir -p /etc/nginx/includes
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/nginx/docker-entrypoint.sh /
COPY data/Dockerfiles/nginx/supervisord.conf /etc/supervisor/supervisord.conf
COPY data/Dockerfiles/nginx/stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
RUN chmod +x /docker-entrypoint.sh
RUN chmod +x /usr/local/sbin/stop-supervisor.sh
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -0,0 +1,20 @@
#!/bin/sh
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
echo "Running hook ${file}"
"${file}"
fi
done
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Nginx."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting Nginx..."
nginx -g "daemon off;"

View File

@@ -0,0 +1,8 @@
#!/bin/bash
printf "READY\n";
while read line; do
echo "Processing Event: $line" >&2;
kill -3 $(cat "/var/run/supervisord.pid")
done < /dev/stdin

View File

@@ -0,0 +1,27 @@
[supervisord]
nodaemon=true
user=root
[program:syslog-ng]
command=/usr/sbin/syslog-ng --foreground --no-caps
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
priority=1
[program:bootstrap]
command=/docker-entrypoint.sh
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
priority=2
startretries=10
autorestart=true
stopwaitsecs=120
[eventlistener:processes]
command=/usr/local/sbin/stop-supervisor.sh
events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL

View File

@@ -1,6 +1,8 @@
FROM alpine:3.15
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM alpine:3.21
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
ARG PIP_BREAK_SYSTEM_PACKAGES=1
WORKDIR /app
#RUN addgroup -S olefy && adduser -S olefy -G olefy \

View File

@@ -32,6 +32,13 @@ import time
import magic
import re
skip_olefy = os.getenv('SKIP_OLEFY', '')
if skip_olefy.lower() in ['yes', 'y']:
print("SKIP_OLEFY=y, skipping Olefy...")
time.sleep(365 * 24 * 60 * 60)
sys.exit(0)
# merge variables from /etc/olefy.conf and the defaults
olefy_listen_addr_string = os.getenv('OLEFY_BINDADDRESS', '127.0.0.1,::1')
olefy_listen_port = int(os.getenv('OLEFY_BINDPORT', '10050'))
@@ -113,7 +120,7 @@ def oletools( stream, tmp_file_name, lid ):
out = bytes(out.decode('utf-8', 'ignore').replace(' ', ' ').replace('\t', '').replace('\n', '').replace('XLMMacroDeobfuscator: pywin32 is not installed (only is required if you want to use MS Excel)', ''), encoding="utf-8")
failed = False
if out.__len__() < 30:
logger.error('{} olevba returned <30 chars - rc: {!r}, response: {!r}, error: {!r}'.format(lid,cmd_tmp.returncode,
logger.error('{} olevba returned <30 chars - rc: {!r}, response: {!r}, error: {!r}'.format(lid,cmd_tmp.returncode,
out.decode('utf-8', 'ignore'), err.decode('utf-8', 'ignore')))
out = b'[ { "error": "Unhandled error - too short olevba response" } ]'
failed = True

View File

@@ -1,12 +1,19 @@
FROM php:8.0-fpm-alpine3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM php:8.2-fpm-alpine3.21
ENV APCU_PECL 5.1.20
ENV IMAGICK_PECL 3.5.1
# Mailparse is pulled from master branch
#ENV MAILPARSE_PECL 3.0.2
ENV MEMCACHED_PECL 3.1.5
ENV REDIS_PECL 5.3.4
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG APCU_PECL_VERSION=5.1.24
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
ARG IMAGICK_PECL_VERSION=3.8.0
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MAILPARSE_PECL_VERSION=3.1.8
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MEMCACHED_PECL_VERSION=3.2.0
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
ARG REDIS_PECL_VERSION=6.1.0
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
ARG COMPOSER_VERSION=2.8.6
RUN apk add -U --no-cache autoconf \
aspell-dev \
@@ -18,6 +25,7 @@ RUN apk add -U --no-cache autoconf \
freetype-dev \
g++ \
git \
gettext \
gettext-dev \
gmp-dev \
gnupg \
@@ -27,8 +35,11 @@ RUN apk add -U --no-cache autoconf \
imagemagick-dev \
imap-dev \
jq \
libavif \
libavif-dev \
libjpeg-turbo \
libjpeg-turbo-dev \
libmemcached \
libmemcached-dev \
libpng \
libpng-dev \
@@ -38,8 +49,11 @@ RUN apk add -U --no-cache autoconf \
libtool \
libwebp-dev \
libxml2-dev \
libxpm \
libxpm-dev \
libzip \
libzip-dev \
linux-headers \
make \
mysql-client \
openldap-dev \
@@ -49,22 +63,25 @@ RUN apk add -U --no-cache autoconf \
samba-client \
zlib-dev \
tzdata \
&& git clone https://github.com/php/pecl-mail-mailparse \
&& cd pecl-mail-mailparse \
&& pecl install package.xml \
&& cd .. \
&& rm -r pecl-mail-mailparse \
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} \
python3 py3-pip \
&& pecl install APCu-${APCU_PECL_VERSION} \
&& pecl install imagick-${IMAGICK_PECL_VERSION} \
&& pecl install mailparse-${MAILPARSE_PECL_VERSION} \
&& pecl install memcached-${MEMCACHED_PECL_VERSION} \
&& pecl install redis-${REDIS_PECL_VERSION} \
&& docker-php-ext-enable apcu imagick memcached mailparse redis \
&& pecl clear-cache \
&& docker-php-ext-configure intl \
&& docker-php-ext-configure exif \
&& docker-php-ext-configure gd --with-freetype=/usr/include/ \
&& docker-php-ext-configure gd --with-freetype=/usr/include/ \
--with-jpeg=/usr/include/ \
--with-webp \
--with-xpm \
--with-avif \
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
&& docker-php-ext-install -j 4 imap \
&& curl --silent --show-error https://getcomposer.org/installer | php \
&& curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \
&& mv composer.phar /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer \
&& apk del --purge autoconf \
@@ -72,20 +89,45 @@ RUN apk add -U --no-cache autoconf \
cyrus-sasl-dev \
freetype-dev \
g++ \
gettext-dev \
icu-dev \
imagemagick-dev \
imap-dev \
libavif-dev \
libjpeg-turbo-dev \
libmemcached-dev \
libpng-dev \
libressl-dev \
libwebp-dev \
libxml2-dev \
libxpm-dev \
libzip-dev \
linux-headers \
make \
openldap-dev \
pcre-dev \
zlib-dev
COPY ./docker-entrypoint.sh /
RUN apk add --no-cache --virtual .build-deps \
gcc \
musl-dev \
python3-dev \
linux-headers \
&& pip install --break-system-packages psutil \
&& apk del .build-deps
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/phpfpm/docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["php-fpm"]

View File

@@ -1,191 +1,5 @@
#!/bin/bash
function array_by_comma { local IFS=","; echo "$*"; }
# Wait for containers
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for SQL..."
sleep 2
done
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT}"
else
REDIS_CMDLINE="redis-cli -h redis -p 6379"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
echo "Waiting for Redis..."
sleep 2
done
# Check mysql_upgrade (master and slave)
CONTAINER_ID=
until [[ ! -z "${CONTAINER_ID}" ]] && [[ "${CONTAINER_ID}" =~ ^[[:alnum:]]*$ ]]; do
CONTAINER_ID=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"mysql-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null)
sleep 2
done
echo "MySQL @ ${CONTAINER_ID}"
SQL_LOOP_C=0
SQL_CHANGED=0
until [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; do
if [ ${SQL_LOOP_C} -gt 4 ]; then
echo "Tried to upgrade MySQL and failed, giving up after ${SQL_LOOP_C} retries and starting container (oops, not good)"
break
fi
SQL_FULL_UPGRADE_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_upgrade"}' --silent -H 'Content-type: application/json')
SQL_UPGRADE_STATUS=$(echo ${SQL_FULL_UPGRADE_RETURN} | jq -r .type)
SQL_LOOP_C=$((SQL_LOOP_C+1))
echo "SQL upgrade iteration #${SQL_LOOP_C}"
if [[ ${SQL_UPGRADE_STATUS} == 'warning' ]]; then
SQL_CHANGED=1
echo "MySQL applied an upgrade, debug output:"
echo ${SQL_FULL_UPGRADE_RETURN}
sleep 3
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for SQL to return, please wait"
sleep 2
done
continue
elif [[ ${SQL_UPGRADE_STATUS} == 'success' ]]; then
echo "MySQL is up-to-date - debug output:"
echo ${SQL_FULL_UPGRADE_RETURN}
else
echo "No valid reponse for mysql_upgrade was received, debug output:"
echo ${SQL_FULL_UPGRADE_RETURN}
fi
done
# doing post-installation stuff, if SQL was upgraded (master and slave)
if [ ${SQL_CHANGED} -eq 1 ]; then
POSTFIX=$(curl --silent --insecure https://dockerapi/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], project: .Config.Labels[\"com.docker.compose.project\"], id: .Id}" 2> /dev/null | jq -rc "select( .name | tostring | contains(\"postfix-mailcow\")) | select( .project | tostring | contains(\"${COMPOSE_PROJECT_NAME,,}\")) | .id" 2> /dev/null)
if [[ -z "${POSTFIX}" ]] || ! [[ "${POSTFIX}" =~ ^[[:alnum:]]*$ ]]; then
echo "Could not determine Postfix container ID, skipping Postfix restart."
else
echo "Restarting Postfix"
curl -X POST --silent --insecure https://dockerapi/containers/${POSTFIX}/restart | jq -r '.msg'
echo "Sleeping 5 seconds..."
sleep 5
fi
fi
# Check mysql tz import (master and slave)
TZ_CHECK=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC') AS time;" -BN 2> /dev/null)
if [[ -z ${TZ_CHECK} ]] || [[ "${TZ_CHECK}" == "NULL" ]]; then
SQL_FULL_TZINFO_IMPORT_RETURN=$(curl --silent --insecure -XPOST https://dockerapi/containers/${CONTAINER_ID}/exec -d '{"cmd":"system", "task":"mysql_tzinfo_to_sql"}' --silent -H 'Content-type: application/json')
echo "MySQL mysql_tzinfo_to_sql - debug output:"
echo ${SQL_FULL_TZINFO_IMPORT_RETURN}
fi
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "We are master, preparing..."
# Set a default release format
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
${REDIS_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
fi
# Set max age of q items - if unset
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
${REDIS_CMDLINE} --raw SET Q_MAX_AGE 365
fi
# Set default password policy - if unset
if [[ -z $(${REDIS_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY length 6
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY chars 0
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
fi
# Trigger db init
echo "Running DB init..."
php -c /usr/local/etc/php -f /web/inc/init_db.inc.php
# Recreating domain map
echo "Rebuilding domain map in Redis..."
declare -a DOMAIN_ARR
${REDIS_CMDLINE} DEL DOMAIN_MAP > /dev/null
while read line
do
DOMAIN_ARR+=("$line")
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain" -Bs)
while read line
do
DOMAIN_ARR+=("$line")
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs)
if [[ ! -z ${DOMAIN_ARR} ]]; then
for domain in "${DOMAIN_ARR[@]}"; do
${REDIS_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
done
fi
# Set API options if env vars are not empty
if [[ ${API_ALLOW_FROM} != "invalid" ]] && [[ ! -z ${API_ALLOW_FROM} ]]; then
IFS=',' read -r -a API_ALLOW_FROM_ARR <<< "${API_ALLOW_FROM}"
declare -a VALIDATED_API_ALLOW_FROM_ARR
REGEX_IP6='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$'
REGEX_IP4='^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/([0-9]|[1-2][0-9]|3[0-2]))?$'
for IP in "${API_ALLOW_FROM_ARR[@]}"; do
if [[ ${IP} =~ ${REGEX_IP6} ]] || [[ ${IP} =~ ${REGEX_IP4} ]]; then
VALIDATED_API_ALLOW_FROM_ARR+=("${IP}")
fi
done
VALIDATED_IPS=$(array_by_comma ${VALIDATED_API_ALLOW_FROM_ARR[*]})
if [[ ! -z ${VALIDATED_IPS} ]]; then
if [[ ${API_KEY} != "invalid" ]] && [[ ! -z ${API_KEY} ]]; then
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
DELETE FROM api WHERE access = 'rw';
INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY}", "1", "${VALIDATED_IPS}", "rw");
EOF
fi
if [[ ${API_KEY_READ_ONLY} != "invalid" ]] && [[ ! -z ${API_KEY_READ_ONLY} ]]; then
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
DELETE FROM api WHERE access = 'ro';
INSERT INTO api (api_key, active, allow_from, access) VALUES ("${API_KEY_READ_ONLY}", "1", "${VALIDATED_IPS}", "ro");
EOF
fi
fi
fi
# Create events (master only, STATUS for event on slave will be SLAVESIDE_DISABLED)
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
DROP EVENT IF EXISTS clean_spamalias;
DELIMITER //
CREATE EVENT clean_spamalias
ON SCHEDULE EVERY 1 DAY DO
BEGIN
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
END;
//
DELIMITER ;
DROP EVENT IF EXISTS clean_oauth2;
DELIMITER //
CREATE EVENT clean_oauth2
ON SCHEDULE EVERY 1 DAY DO
BEGIN
DELETE FROM oauth_refresh_tokens WHERE expires < NOW();
DELETE FROM oauth_access_tokens WHERE expires < NOW();
DELETE FROM oauth_authorization_codes WHERE expires < NOW();
END;
//
DELIMITER ;
EOF
fi
# Create dummy for custom overrides of mailcow style
[[ ! -f /web/css/build/0081-custom-mailcow.css ]] && echo '/* Autogenerated by mailcow */' > /web/css/build/0081-custom-mailcow.css
# Fix permissions for global filters
chown -R 82:82 /global_sieve/*
# Fix permissions on twig cache folder
chown -R 82:82 /web/templates/cache
# Clear cache
find /web/templates/cache/* -not -name '.gitkeep' -delete
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
@@ -194,4 +8,13 @@ for file in /hooks/*; do
fi
done
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting PHP-FPM."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting PHP-FPM..."
exec "$@"

View File

@@ -1,5 +1,6 @@
FROM debian:buster-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM debian:bookworm-slim
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ENV LC_ALL C
@@ -17,10 +18,10 @@ RUN groupadd -g 102 postfix \
ca-certificates \
curl \
dirmngr \
dnsutils \
dnsutils \
gnupg \
libsasl2-modules \
mariadb-client \
mariadb-client \
perl \
postfix \
postfix-mysql \
@@ -32,24 +33,32 @@ RUN groupadd -g 102 postfix \
syslog-ng \
syslog-ng-core \
syslog-ng-mod-redis \
tzdata \
tzdata \
python3 python3-pip \
&& rm -rf /var/lib/apt/lists/* \
&& touch /etc/default/locale \
&& printf '#!/bin/bash\n/usr/sbin/postconf -c /opt/postfix/conf "$@"' > /usr/local/sbin/postconf \
&& chmod +x /usr/local/sbin/postconf
COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY postfix.sh /opt/postfix.sh
COPY rspamd-pipe-ham /usr/local/bin/rspamd-pipe-ham
COPY rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
COPY whitelist_forwardinghosts.sh /usr/local/bin/whitelist_forwardinghosts.sh
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython \
psutil
RUN chmod +x /opt/postfix.sh \
/usr/local/bin/rspamd-pipe-ham \
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/postfix/supervisord.conf /etc/supervisor/supervisord.conf
COPY data/Dockerfiles/postfix/syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY data/Dockerfiles/postfix/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY data/Dockerfiles/postfix/rspamd-pipe-ham /usr/local/bin/rspamd-pipe-ham
COPY data/Dockerfiles/postfix/rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
COPY data/Dockerfiles/postfix/whitelist_forwardinghosts.sh /usr/local/bin/whitelist_forwardinghosts.sh
COPY data/Dockerfiles/postfix/stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY data/Dockerfiles/postfix/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /usr/local/bin/rspamd-pipe-ham \
/docker-entrypoint.sh \
/usr/local/bin/rspamd-pipe-spam \
/usr/local/bin/whitelist_forwardinghosts.sh \
/usr/local/sbin/stop-supervisor.sh
@@ -57,6 +66,5 @@ RUN rm -rf /tmp/* /var/tmp/*
EXPOSE 588
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -8,8 +8,33 @@ for file in /hooks/*; do
fi
done
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Postfix."
exit $BOOTSTRAP_EXIT_CODE
fi
exec "$@"
# Fix OpenSSL 3.X TLS1.0, 1.1 support (https://community.mailcow.email/d/4062-hi-all/20)
if grep -qE '\!SSLv2|\!SSLv3|>=TLSv1(\.[0-1])?$' /opt/postfix/conf/main.cf /opt/postfix/conf/extra.cf; then
sed -i '/\[openssl_init\]/a ssl_conf = ssl_configuration' /etc/ssl/openssl.cnf
echo "[ssl_configuration]" >> /etc/ssl/openssl.cnf
echo "system_default = tls_system_default" >> /etc/ssl/openssl.cnf
echo "[tls_system_default]" >> /etc/ssl/openssl.cnf
echo "MinProtocol = TLSv1" >> /etc/ssl/openssl.cnf
echo "CipherString = DEFAULT@SECLEVEL=0" >> /etc/ssl/openssl.cnf
fi
# Start Postfix
postconf -c /opt/postfix/conf > /dev/null
if [[ $? != 0 ]]; then
echo "Postfix configuration error, refusing to start."
exit 1
else
echo "Bootstrap succeeded. Starting Postfix..."
postfix -c /opt/postfix/conf start
sleep 126144000
fi

View File

@@ -1,424 +0,0 @@
#!/bin/bash
trap "postfix stop" EXIT
[[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
# Wait for MySQL to warm-up
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for database to come up..."
sleep 2
done
until dig +short mailcow.email > /dev/null; do
echo "Waiting for DNS..."
sleep 1
done
cat <<EOF > /etc/aliases
# Autogenerated by mailcow
null: /dev/null
watchdog: /dev/null
ham: "|/usr/local/bin/rspamd-pipe-ham"
spam: "|/usr/local/bin/rspamd-pipe-spam"
EOF
newaliases;
# create sni configuration
if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo -n "" > /opt/postfix/conf/sni.map
else
echo -n "" > /opt/postfix/conf/sni.map;
for cert_dir in /etc/ssl/mail/*/ ; do
if [[ ! -f ${cert_dir}domains ]] || [[ ! -f ${cert_dir}cert.pem ]] || [[ ! -f ${cert_dir}key.pem ]]; then
continue;
fi
IFS=" " read -r -a domains <<< "$(cat "${cert_dir}domains")"
for domain in "${domains[@]}"; do
echo -n "${domain} ${cert_dir}key.pem ${cert_dir}cert.pem" >> /opt/postfix/conf/sni.map;
echo "" >> /opt/postfix/conf/sni.map;
done
done
fi
postmap -F hash:/opt/postfix/conf/sni.map;
cat <<EOF > /opt/postfix/conf/sql/mysql_relay_ne.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT IF(EXISTS(SELECT address, domain FROM alias
WHERE address = '%s'
AND domain IN (
SELECT domain FROM domain
WHERE backupmx = '1'
AND relay_all_recipients = '1'
AND relay_unknown_only = '1')
), 'lmtp:inet:dovecot:24', NULL) AS 'transport'
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT DISTINCT
CASE WHEN '%d' IN (
SELECT domain FROM domain
WHERE relay_all_recipients=1
AND domain='%d'
AND backupmx=1
)
THEN '%s' ELSE (
SELECT goto FROM alias WHERE address='%s' AND active='1'
)
END AS result;
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT(policy, ' ', parameters) AS tls_policy FROM tls_policy_override WHERE active = '1' AND dest = '%s'
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT IF(EXISTS(
SELECT 'TLS_ACTIVE' FROM alias
LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
WHERE (address='%s'
OR address IN (
SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
WHERE alias_domain='%d'
)
) AND JSON_UNQUOTE(JSON_VALUE(attributes, '$.tls_enforce_in')) = '1' AND mailbox.active = '1'
), 'reject_plaintext_session', NULL) AS 'tls_enforce_in';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps
FROM (
SELECT IF(EXISTS(SELECT 'smtp_type' FROM alias
LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
WHERE (address = '%s'
OR address IN (
SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
WHERE alias_domain = '%d'
)
)
AND JSON_UNQUOTE(JSON_VALUE(attributes, '$.tls_enforce_out')) = '1'
AND mailbox.active = '1'
), 'smtp_enforced_tls:', 'smtp:') AS 'transport'
UNION ALL
SELECT COALESCE(
(SELECT hostname FROM relayhosts
LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
WHERE relayhosts.active = '1'
AND (
mailbox.username IN (SELECT alias.goto from alias
JOIN mailbox ON mailbox.username = alias.goto
WHERE alias.active = '1'
AND alias.address = '%s'
AND alias.address NOT LIKE '@%%'
)
)
),
(SELECT hostname FROM relayhosts
LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
WHERE relayhosts.active = '1'
AND (domain.domain = '%d'
OR domain.domain IN (
SELECT target_domain FROM alias_domain
WHERE alias_domain = '%d'
)
)
)
)
) AS transport_view;
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_transport_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT('smtp_via_transport_maps:', nexthop) AS transport FROM transports
WHERE active = '1'
AND destination = '%s';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_resource_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT 'null@localhost' FROM mailbox
WHERE kind REGEXP 'location|thing|group' AND username = '%s';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_sasl_passwd_maps_sender_dependent.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM relayhosts
WHERE id IN (
SELECT COALESCE(
(SELECT id FROM relayhosts
LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
WHERE relayhosts.active = '1'
AND (domain.domain = '%d'
OR domain.domain IN (
SELECT target_domain FROM alias_domain
WHERE alias_domain = '%d'
)
)
),
(SELECT id FROM relayhosts
LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
WHERE relayhosts.active = '1'
AND (
mailbox.username IN (
SELECT alias.goto from alias
JOIN mailbox ON mailbox.username = alias.goto
WHERE alias.active = '1'
AND alias.address = '%s'
AND alias.address NOT LIKE '@%%'
)
)
)
)
)
AND active = '1'
AND username != '';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_sasl_passwd_maps_transport_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM transports
WHERE nexthop = '%s'
AND active = '1'
AND username != ''
LIMIT 1;
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT username FROM mailbox, alias_domain
WHERE alias_domain.alias_domain = '%d'
AND mailbox.username = CONCAT('%u', '@', alias_domain.target_domain)
AND (mailbox.active = '1' OR mailbox.active = '2')
AND alias_domain.active='1'
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT goto FROM alias
WHERE address='%s'
AND (active='1' OR active='2');
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT bcc_dest FROM bcc_maps
WHERE local_dest='%s'
AND type='rcpt'
AND active='1';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_sender_bcc_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT bcc_dest FROM bcc_maps
WHERE local_dest='%s'
AND type='sender'
AND active='1';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_canonical_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT new_dest FROM recipient_maps
WHERE old_dest='%s'
AND active='1';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1'
UNION
SELECT domain FROM domain
WHERE domain='%s'
AND active = '1'
AND backupmx = '0'
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT(JSON_UNQUOTE(JSON_VALUE(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%u/') FROM mailbox WHERE username='%s' AND (active = '1' OR active = '2')
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
# First select queries domain and alias_domain to determine if domains are active.
query = SELECT goto FROM alias
WHERE address='%s'
AND active='1'
AND (domain IN
(SELECT domain FROM domain
WHERE domain='%d'
AND active='1')
OR domain in (
SELECT alias_domain FROM alias_domain
WHERE alias_domain='%d'
AND active='1'
)
)
UNION
SELECT logged_in_as FROM sender_acl
WHERE send_as='@%d'
OR send_as='%s'
OR send_as='*'
OR send_as IN (
SELECT CONCAT('@',target_domain) FROM alias_domain
WHERE alias_domain = '%d')
OR send_as IN (
SELECT CONCAT('%u','@',target_domain) FROM alias_domain
WHERE alias_domain = '%d')
AND logged_in_as NOT IN (
SELECT goto FROM alias
WHERE address='%s')
UNION
SELECT username FROM mailbox, alias_domain
WHERE alias_domain.alias_domain = '%d'
AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
AND (mailbox.active = '1' OR mailbox.active ='2')
AND alias_domain.active='1'
EOF
# MX based routing
cat <<EOF > /opt/postfix/conf/sql/mysql_mbr_access_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT CONCAT('FILTER smtp_via_transport_maps:', nexthop) as transport FROM transports
WHERE '%s' REGEXP destination
AND active='1'
AND is_mx_based='1';
EOF
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
# Autogenerated by mailcow
user = ${DBUSER}
password = ${DBPASS}
hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
query = SELECT goto FROM spamalias
WHERE address='%s'
AND validity >= UNIX_TIMESTAMP()
EOF
sed -i '/User overrides/q' /opt/postfix/conf/main.cf
echo >> /opt/postfix/conf/main.cf
touch /opt/postfix/conf/extra.cf
sed -i '/myhostname/d' /opt/postfix/conf/extra.cf
echo -e "myhostname = ${MAILCOW_HOSTNAME}\n$(cat /opt/postfix/conf/extra.cf)" > /opt/postfix/conf/extra.cf
cat /opt/postfix/conf/extra.cf >> /opt/postfix/conf/main.cf
if [ ! -f /opt/postfix/conf/custom_transport.pcre ]; then
echo "Creating dummy custom_transport.pcre"
touch /opt/postfix/conf/custom_transport.pcre
fi
if [[ ! -f /opt/postfix/conf/custom_postscreen_whitelist.cidr ]]; then
echo "Creating dummy custom_postscreen_whitelist.cidr"
cat <<EOF > /opt/postfix/conf/custom_postscreen_whitelist.cidr
# Autogenerated by mailcow
# Rules are evaluated in the order as specified.
# Blacklist 192.168.* except 192.168.0.1.
# 192.168.0.1 permit
# 192.168.0.0/16 reject
EOF
fi
# Fix Postfix permissions
chown -R root:postfix /opt/postfix/conf/sql/ /opt/postfix/conf/custom_transport.pcre
chmod 640 /opt/postfix/conf/sql/*.cf /opt/postfix/conf/custom_transport.pcre
chgrp -R postdrop /var/spool/postfix/public
chgrp -R postdrop /var/spool/postfix/maildrop
postfix set-permissions
# Check Postfix configuration
postconf -c /opt/postfix/conf > /dev/null
if [[ $? != 0 ]]; then
echo "Postfix configuration error, refusing to start."
exit 1
else
postfix -c /opt/postfix/conf start
sleep 126144000
fi

View File

@@ -11,13 +11,14 @@ stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
[program:postfix]
command=/opt/postfix.sh
[program:bootstrap]
command=/docker-entrypoint.sh
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startsecs=10
[eventlistener:processes]
command=/usr/local/sbin/stop-supervisor.sh

View File

@@ -1,4 +1,4 @@
@version: 3.19
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@@ -1,4 +1,4 @@
@version: 3.19
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -20,6 +20,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -28,6 +29,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@@ -1,22 +1,28 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@tinc.gmbh>"
FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG CODENAME=bullseye
ENV LC_ALL C
ARG RSPAMD_VER=rspamd_3.11.1-1~ab0b44951
ARG CODENAME=bookworm
ENV LC_ALL=C
RUN apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata \
ca-certificates \
gnupg2 \
apt-transport-https \
dnsutils \
netcat \
&& apt-key adv --fetch-keys https://rspamd.com/apt-stable/gpg.key \
&& echo "deb [arch=amd64] https://rspamd.com/apt-stable/ $CODENAME main" > /etc/apt/sources.list.d/rspamd.list \
&& apt-get update \
&& apt-get --no-install-recommends -y install rspamd redis-tools procps nano \
&& rm -rf /var/lib/apt/lists/* \
netcat-traditional \
wget \
redis-tools \
procps \
nano \
lua-cjson \
python3 python3-pip \
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
&& wget -P /tmp https://rspamd.com/apt-stable/pool/main/r/rspamd/${RSPAMD_VER}~${CODENAME}_${arch}.deb\
&& apt install -y /tmp/${RSPAMD_VER}~${CODENAME}_${arch}.deb \
&& rm -rf /var/lib/apt/lists/* /tmp/*\
&& apt-get autoremove --purge \
&& apt-get clean \
&& mkdir -p /run/rspamd \
@@ -24,12 +30,20 @@ RUN apt-get update && apt-get install -y \
&& echo 'alias ll="ls -la --color"' >> ~/.bashrc \
&& sed -i 's/#analysis_keyword_table > 0/analysis_cat_table.macro_exist == "M"/g' /usr/share/rspamd/lualib/lua_scanners/oletools.lua
COPY settings.conf /etc/rspamd/settings.conf
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython \
psutil
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/rspamd/settings.conf /etc/rspamd/settings.conf
COPY data/Dockerfiles/rspamd/set_worker_password.sh /set_worker_password.sh
COPY data/Dockerfiles/rspamd/docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
STOPSIGNAL SIGTERM
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/bin/rspamd", "-f", "-u", "_rspamd", "-g", "_rspamd"]

View File

@@ -1,118 +1,5 @@
#!/bin/bash
until nc phpfpm 9001 -z; do
echo "Waiting for PHP on port 9001..."
sleep 3
done
until nc phpfpm 9002 -z; do
echo "Waiting for PHP on port 9002..."
sleep 3
done
mkdir -p /etc/rspamd/plugins.d \
/etc/rspamd/custom
touch /etc/rspamd/rspamd.conf.local \
/etc/rspamd/rspamd.conf.override
chmod 755 /var/lib/rspamd
[[ ! -f /etc/rspamd/override.d/worker-controller-password.inc ]] && echo '# Autogenerated by mailcow' > /etc/rspamd/override.d/worker-controller-password.inc
echo ${IPV4_NETWORK}.0/24 > /etc/rspamd/custom/mailcow_networks.map
echo ${IPV6_NETWORK} >> /etc/rspamd/custom/mailcow_networks.map
DOVECOT_V4=
DOVECOT_V6=
until [[ ! -z ${DOVECOT_V4} ]]; do
DOVECOT_V4=$(dig a dovecot +short)
DOVECOT_V6=$(dig aaaa dovecot +short)
[[ ! -z ${DOVECOT_V4} ]] && break;
echo "Waiting for Dovecot..."
sleep 3
done
echo ${DOVECOT_V4}/32 > /etc/rspamd/custom/dovecot_trusted.map
if [[ ! -z ${DOVECOT_V6} ]]; then
echo ${DOVECOT_V6}/128 >> /etc/rspamd/custom/dovecot_trusted.map
fi
RSPAMD_V4=
RSPAMD_V6=
until [[ ! -z ${RSPAMD_V4} ]]; do
RSPAMD_V4=$(dig a rspamd +short)
RSPAMD_V6=$(dig aaaa rspamd +short)
[[ ! -z ${RSPAMD_V4} ]] && break;
echo "Waiting for Rspamd..."
sleep 3
done
echo ${RSPAMD_V4}/32 > /etc/rspamd/custom/rspamd_trusted.map
if [[ ! -z ${RSPAMD_V6} ]]; then
echo ${RSPAMD_V6}/128 >> /etc/rspamd/custom/rspamd_trusted.map
fi
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cat <<EOF > /etc/rspamd/local.d/redis.conf
read_servers = "redis:6379";
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
timeout = 10;
EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
echo "Waiting for Redis @redis-mailcow..."
sleep 2
done
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} PING) == "PONG" ]]; do
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
sleep 2
done
redis-cli -h redis-mailcow SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
else
cat <<EOF > /etc/rspamd/local.d/redis.conf
servers = "redis:6379";
timeout = 10;
EOF
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
echo "Waiting for Redis slave..."
sleep 2
done
redis-cli -h redis-mailcow SLAVEOF NO ONE
fi
chown -R _rspamd:_rspamd /var/lib/rspamd \
/etc/rspamd/local.d \
/etc/rspamd/override.d \
/etc/rspamd/rspamd.conf.local \
/etc/rspamd/rspamd.conf.override \
/etc/rspamd/plugins.d
# Fix missing default global maps, if any
# These exists in mailcow UI and should not be removed
touch /etc/rspamd/custom/global_mime_from_blacklist.map \
/etc/rspamd/custom/global_rcpt_blacklist.map \
/etc/rspamd/custom/global_smtp_from_blacklist.map \
/etc/rspamd/custom/global_mime_from_whitelist.map \
/etc/rspamd/custom/global_rcpt_whitelist.map \
/etc/rspamd/custom/global_smtp_from_whitelist.map \
/etc/rspamd/custom/bad_languages.map \
/etc/rspamd/custom/sa-rules \
/etc/rspamd/custom/dovecot_trusted.map \
/etc/rspamd/custom/rspamd_trusted.map \
/etc/rspamd/custom/mailcow_networks.map \
/etc/rspamd/custom/ip_wl.map \
/etc/rspamd/custom/fishy_tlds.map \
/etc/rspamd/custom/bad_words.map \
/etc/rspamd/custom/bad_asn.map \
/etc/rspamd/custom/bad_words_de.map \
/etc/rspamd/custom/bulk_header.map \
/etc/rspamd/custom/bad_header.map
# www-data (82) group needs to write to these files
chown _rspamd:_rspamd /etc/rspamd/custom/
chmod 0755 /etc/rspamd/custom/.
chown -R 82:82 /etc/rspamd/custom/*
chmod 644 -R /etc/rspamd/custom/*
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
@@ -121,4 +8,13 @@ for file in /hooks/*; do
fi
done
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting Rspamd."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting Rspamd..."
exec "$@"

View File

@@ -1,632 +0,0 @@
--[[
Copyright (c) 2016, Andrew Lewis <nerf@judo.za.org>
Copyright (c) 2016, Vsevolod Stakhov <vsevolod@highsecure.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]--
if confighelp then
return
end
-- A plugin that pushes metadata (or whole messages) to external services
local redis_params
local lua_util = require "lua_util"
local rspamd_http = require "rspamd_http"
local rspamd_util = require "rspamd_util"
local rspamd_logger = require "rspamd_logger"
local ucl = require "ucl"
local E = {}
local N = 'metadata_exporter'
local settings = {
pusher_enabled = {},
pusher_format = {},
pusher_select = {},
mime_type = 'text/plain',
defer = false,
mail_from = '',
mail_to = 'postmaster@localhost',
helo = 'rspamd',
email_template = [[From: "Rspamd" <$mail_from>
To: $mail_to
Subject: Spam alert
Date: $date
MIME-Version: 1.0
Message-ID: <$our_message_id>
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Authenticated username: $user
IP: $ip
Queue ID: $qid
SMTP FROM: $from
SMTP RCPT: $rcpt
MIME From: $header_from
MIME To: $header_to
MIME Date: $header_date
Subject: $header_subject
Message-ID: $message_id
Action: $action
Score: $score
Symbols: $symbols]],
}
local function get_general_metadata(task, flatten, no_content)
local r = {}
local ip = task:get_from_ip()
if ip and ip:is_valid() then
r.ip = tostring(ip)
else
r.ip = 'unknown'
end
r.user = task:get_user() or 'unknown'
r.qid = task:get_queue_id() or 'unknown'
r.subject = task:get_subject() or 'unknown'
r.action = task:get_metric_action('default')
local s = task:get_metric_score('default')[1]
r.score = flatten and string.format('%.2f', s) or s
local fuzzy = task:get_mempool():get_variable("fuzzy_hashes", "fstrings")
if fuzzy and #fuzzy > 0 then
local fz = {}
for _,h in ipairs(fuzzy) do
table.insert(fz, h)
end
if not flatten then
r.fuzzy = fz
else
r.fuzzy = table.concat(fz, ', ')
end
else
r.fuzzy = 'unknown'
end
local rcpt = task:get_recipients('smtp')
if rcpt then
local l = {}
for _, a in ipairs(rcpt) do
table.insert(l, a['addr'])
end
if not flatten then
r.rcpt = l
else
r.rcpt = table.concat(l, ', ')
end
else
r.rcpt = 'unknown'
end
local from = task:get_from('smtp')
if ((from or E)[1] or E).addr then
r.from = from[1].addr
else
r.from = 'unknown'
end
local syminf = task:get_symbols_all()
if flatten then
local l = {}
for _, sym in ipairs(syminf) do
local txt
if sym.options then
local topt = table.concat(sym.options, ', ')
txt = sym.name .. '(' .. string.format('%.2f', sym.score) .. ')' .. ' [' .. topt .. ']'
else
txt = sym.name .. '(' .. string.format('%.2f', sym.score) .. ')'
end
table.insert(l, txt)
end
r.symbols = table.concat(l, '\n\t')
else
r.symbols = syminf
end
local function process_header(name)
local hdr = task:get_header_full(name)
if hdr then
local l = {}
for _, h in ipairs(hdr) do
table.insert(l, h.decoded)
end
if not flatten then
return l
else
return table.concat(l, '\n')
end
else
return 'unknown'
end
end
if not no_content then
r.header_from = process_header('from')
r.header_to = process_header('to')
r.header_subject = process_header('subject')
r.header_date = process_header('date')
r.message_id = task:get_message_id()
end
return r
end
local formatters = {
default = function(task)
return task:get_content(), {}
end,
email_alert = function(task, rule, extra)
local meta = get_general_metadata(task, true)
local display_emails = {}
local mail_targets = {}
meta.mail_from = rule.mail_from or settings.mail_from
local mail_rcpt = rule.mail_to or settings.mail_to
if type(mail_rcpt) ~= 'table' then
table.insert(display_emails, string.format('<%s>', mail_rcpt))
table.insert(mail_targets, mail_rcpt)
else
for _, e in ipairs(mail_rcpt) do
table.insert(display_emails, string.format('<%s>', e))
table.insert(mail_targets, mail_rcpt)
end
end
if rule.email_alert_sender then
local x = task:get_from('smtp')
if x and string.len(x[1].addr) > 0 then
table.insert(mail_targets, x)
table.insert(display_emails, string.format('<%s>', x[1].addr))
end
end
if rule.email_alert_user then
local x = task:get_user()
if x then
table.insert(mail_targets, x)
table.insert(display_emails, string.format('<%s>', x))
end
end
if rule.email_alert_recipients then
local x = task:get_recipients('smtp')
if x then
for _, e in ipairs(x) do
if string.len(e.addr) > 0 then
table.insert(mail_targets, e.addr)
table.insert(display_emails, string.format('<%s>', e.addr))
end
end
end
end
meta.mail_to = table.concat(display_emails, ', ')
meta.our_message_id = rspamd_util.random_hex(12) .. '@rspamd'
meta.date = rspamd_util.time_to_string(rspamd_util.get_time())
return lua_util.template(rule.email_template or settings.email_template, meta), { mail_targets = mail_targets}
end,
json = function(task)
return ucl.to_format(get_general_metadata(task), 'json-compact')
end
}
local function is_spam(action)
return (action == 'reject' or action == 'add header' or action == 'rewrite subject')
end
local selectors = {
default = function(task)
return true
end,
is_spam = function(task)
local action = task:get_metric_action('default')
return is_spam(action)
end,
is_spam_authed = function(task)
if not task:get_user() then
return false
end
local action = task:get_metric_action('default')
return is_spam(action)
end,
is_reject = function(task)
local action = task:get_metric_action('default')
return (action == 'reject')
end,
is_reject_authed = function(task)
if not task:get_user() then
return false
end
local action = task:get_metric_action('default')
return (action == 'reject')
end,
}
local function maybe_defer(task, rule)
if rule.defer then
rspamd_logger.warnx(task, 'deferring message')
task:set_pre_result('soft reject', 'deferred', N)
end
end
local pushers = {
redis_pubsub = function(task, formatted, rule)
local _,ret,upstream
local function redis_pub_cb(err)
if err then
rspamd_logger.errx(task, 'got error %s when publishing on server %s',
err, upstream:get_addr())
return maybe_defer(task, rule)
end
return true
end
ret,_,upstream = rspamd_redis_make_request(task,
redis_params, -- connect params
nil, -- hash key
true, -- is write
redis_pub_cb, --callback
'PUBLISH', -- command
{rule.channel, formatted} -- arguments
)
if not ret then
rspamd_logger.errx(task, 'error connecting to redis')
maybe_defer(task, rule)
end
end,
http = function(task, formatted, rule)
local function http_callback(err, code)
if err then
rspamd_logger.errx(task, 'got error %s in http callback', err)
return maybe_defer(task, rule)
end
if code ~= 200 then
rspamd_logger.errx(task, 'got unexpected http status: %s', code)
return maybe_defer(task, rule)
end
return true
end
local hdrs = {}
if rule.meta_headers then
local gm = get_general_metadata(task, false, true)
local pfx = rule.meta_header_prefix or 'X-Rspamd-'
for k, v in pairs(gm) do
if type(v) == 'table' then
hdrs[pfx .. k] = ucl.to_format(v, 'json-compact')
else
hdrs[pfx .. k] = v
end
end
end
rspamd_http.request({
task=task,
url=rule.url,
body=formatted,
callback=http_callback,
mime_type=rule.mime_type or settings.mime_type,
headers=hdrs,
})
end,
send_mail = function(task, formatted, rule, extra)
local lua_smtp = require "lua_smtp"
local function sendmail_cb(ret, err)
if not ret then
rspamd_logger.errx(task, 'SMTP export error: %s', err)
maybe_defer(task, rule)
end
end
lua_smtp.sendmail({
task = task,
host = rule.smtp,
port = rule.smtp_port or settings.smtp_port or 25,
from = rule.mail_from or settings.mail_from,
recipients = extra.mail_targets or rule.mail_to or settings.mail_to,
helo = rule.helo or settings.helo,
timeout = rule.timeout or settings.timeout,
}, formatted, sendmail_cb)
end,
}
local opts = rspamd_config:get_all_opt(N)
if not opts then return end
local process_settings = {
select = function(val)
selectors.custom = assert(load(val))()
end,
format = function(val)
formatters.custom = assert(load(val))()
end,
push = function(val)
pushers.custom = assert(load(val))()
end,
custom_push = function(val)
if type(val) == 'table' then
for k, v in pairs(val) do
pushers[k] = assert(load(v))()
end
end
end,
custom_select = function(val)
if type(val) == 'table' then
for k, v in pairs(val) do
selectors[k] = assert(load(v))()
end
end
end,
custom_format = function(val)
if type(val) == 'table' then
for k, v in pairs(val) do
formatters[k] = assert(load(v))()
end
end
end,
pusher_enabled = function(val)
if type(val) == 'string' then
if pushers[val] then
settings.pusher_enabled[val] = true
else
rspamd_logger.errx(rspamd_config, 'Pusher type: %s is invalid', val)
end
elseif type(val) == 'table' then
for _, v in ipairs(val) do
if pushers[v] then
settings.pusher_enabled[v] = true
else
rspamd_logger.errx(rspamd_config, 'Pusher type: %s is invalid', val)
end
end
end
end,
}
for k, v in pairs(opts) do
local f = process_settings[k]
if f then
f(opts[k])
else
settings[k] = v
end
end
if type(settings.rules) ~= 'table' then
-- Legacy config
settings.rules = {}
if not next(settings.pusher_enabled) then
if pushers.custom then
rspamd_logger.infox(rspamd_config, 'Custom pusher implicitly enabled')
settings.pusher_enabled.custom = true
else
-- Check legacy options
if settings.url then
rspamd_logger.warnx(rspamd_config, 'HTTP pusher implicitly enabled')
settings.pusher_enabled.http = true
end
if settings.channel then
rspamd_logger.warnx(rspamd_config, 'Redis Pubsub pusher implicitly enabled')
settings.pusher_enabled.redis_pubsub = true
end
if settings.smtp and settings.mail_to then
rspamd_logger.warnx(rspamd_config, 'SMTP pusher implicitly enabled')
settings.pusher_enabled.send_mail = true
end
end
end
if not next(settings.pusher_enabled) then
rspamd_logger.errx(rspamd_config, 'No push backend enabled')
return
end
if settings.formatter then
settings.format = formatters[settings.formatter]
if not settings.format then
rspamd_logger.errx(rspamd_config, 'No such formatter: %s', settings.formatter)
return
end
end
if settings.selector then
settings.select = selectors[settings.selector]
if not settings.select then
rspamd_logger.errx(rspamd_config, 'No such selector: %s', settings.selector)
return
end
end
for k in pairs(settings.pusher_enabled) do
local formatter = settings.pusher_format[k]
local selector = settings.pusher_select[k]
if not formatter then
settings.pusher_format[k] = settings.formatter or 'default'
rspamd_logger.infox(rspamd_config, 'Using default formatter for %s pusher', k)
else
if not formatters[formatter] then
rspamd_logger.errx(rspamd_config, 'No such formatter: %s - disabling %s', formatter, k)
settings.pusher_enabled.k = nil
end
end
if not selector then
settings.pusher_select[k] = settings.selector or 'default'
rspamd_logger.infox(rspamd_config, 'Using default selector for %s pusher', k)
else
if not selectors[selector] then
rspamd_logger.errx(rspamd_config, 'No such selector: %s - disabling %s', selector, k)
settings.pusher_enabled.k = nil
end
end
end
if settings.pusher_enabled.redis_pubsub then
redis_params = rspamd_parse_redis_server(N)
if not redis_params then
rspamd_logger.errx(rspamd_config, 'No redis servers are specified')
settings.pusher_enabled.redis_pubsub = nil
else
local r = {}
r.backend = 'redis_pubsub'
r.channel = settings.channel
r.defer = settings.defer
r.selector = settings.pusher_select.redis_pubsub
r.formatter = settings.pusher_format.redis_pubsub
settings.rules[r.backend:upper()] = r
end
end
if settings.pusher_enabled.http then
if not settings.url then
rspamd_logger.errx(rspamd_config, 'No URL is specified')
settings.pusher_enabled.http = nil
else
local r = {}
r.backend = 'http'
r.url = settings.url
r.mime_type = settings.mime_type
r.defer = settings.defer
r.selector = settings.pusher_select.http
r.formatter = settings.pusher_format.http
settings.rules[r.backend:upper()] = r
end
end
if settings.pusher_enabled.send_mail then
if not (settings.mail_to and settings.smtp) then
rspamd_logger.errx(rspamd_config, 'No mail_to and/or smtp setting is specified')
settings.pusher_enabled.send_mail = nil
else
local r = {}
r.backend = 'send_mail'
r.mail_to = settings.mail_to
r.mail_from = settings.mail_from
r.helo = settings.hello
r.smtp = settings.smtp
r.smtp_port = settings.smtp_port
r.email_template = settings.email_template
r.defer = settings.defer
r.selector = settings.pusher_select.send_mail
r.formatter = settings.pusher_format.send_mail
settings.rules[r.backend:upper()] = r
end
end
if not next(settings.pusher_enabled) then
rspamd_logger.errx(rspamd_config, 'No push backend enabled')
return
end
elseif not next(settings.rules) then
lua_util.debugm(N, rspamd_config, 'No rules enabled')
return
end
if not settings.rules or not next(settings.rules) then
rspamd_logger.errx(rspamd_config, 'No rules enabled')
return
end
local backend_required_elements = {
http = {
'url',
},
smtp = {
'mail_to',
'smtp',
},
redis_pubsub = {
'channel',
},
}
local check_element = {
selector = function(k, v)
if not selectors[v] then
rspamd_logger.errx(rspamd_config, 'Rule %s has invalid selector %s', k, v)
return false
else
return true
end
end,
formatter = function(k, v)
if not formatters[v] then
rspamd_logger.errx(rspamd_config, 'Rule %s has invalid formatter %s', k, v)
return false
else
return true
end
end,
}
local backend_check = {
default = function(k, rule)
local reqset = backend_required_elements[rule.backend]
if reqset then
for _, e in ipairs(reqset) do
if not rule[e] then
rspamd_logger.errx(rspamd_config, 'Rule %s misses required setting %s', k, e)
settings.rules[k] = nil
end
end
end
for sett, v in pairs(rule) do
local f = check_element[sett]
if f then
if not f(sett, v) then
settings.rules[k] = nil
end
end
end
end,
}
backend_check.redis_pubsub = function(k, rule)
if not redis_params then
redis_params = rspamd_parse_redis_server(N)
end
if not redis_params then
rspamd_logger.errx(rspamd_config, 'No redis servers are specified')
settings.rules[k] = nil
else
backend_check.default(k, rule)
end
end
setmetatable(backend_check, {
__index = function()
return backend_check.default
end,
})
for k, v in pairs(settings.rules) do
if type(v) == 'table' then
local backend = v.backend
if not backend then
rspamd_logger.errx(rspamd_config, 'Rule %s has no backend', k)
settings.rules[k] = nil
elseif not pushers[backend] then
rspamd_logger.errx(rspamd_config, 'Rule %s has invalid backend %s', k, backend)
settings.rules[k] = nil
else
local f = backend_check[backend]
f(k, v)
end
else
rspamd_logger.errx(rspamd_config, 'Rule %s has bad type: %s', k, type(v))
settings.rules[k] = nil
end
end
local function gen_exporter(rule)
return function (task)
if task:has_flag('skip') then return end
local selector = rule.selector or 'default'
local selected = selectors[selector](task)
if selected then
lua_util.debugm(N, task, 'Message selected for processing')
local formatter = rule.formatter or 'default'
local formatted, extra = formatters[formatter](task, rule)
if formatted then
pushers[rule.backend](task, formatted, rule, extra)
else
lua_util.debugm(N, task, 'Formatter [%s] returned non-truthy value [%s]', formatter, formatted)
end
else
lua_util.debugm(N, task, 'Selector [%s] returned non-truthy value [%s]', selector, selected)
end
end
end
if not next(settings.rules) then
rspamd_logger.errx(rspamd_config, 'No rules enabled')
lua_util.disable_module(N, "config")
end
for k, r in pairs(settings.rules) do
rspamd_config:register_symbol({
name = 'EXPORT_METADATA_' .. k,
type = 'idempotent',
callback = gen_exporter(r),
priority = 10,
flags = 'empty,explicit_disable,ignore_passthrough',
})
end

View File

@@ -0,0 +1,12 @@
#!/bin/bash
password_file='/etc/rspamd/override.d/worker-controller-password.inc'
password_hash=`/usr/bin/rspamadm pw -e -p $1`
echo 'enable_password = "'$password_hash'";' > $password_file
if grep -q "$password_hash" "$password_file"; then
echo "OK"
else
echo "ERROR"
fi

View File

@@ -1,10 +1,13 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/
ENV LC_ALL C
ENV GOSU_VERSION 1.14
ARG DEBIAN_VERSION=bookworm
ARG SOGO_DEBIAN_REPOSITORY=https://packagingv2.sogo.nu/sogo-nightly-debian/
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.17
ENV LC_ALL=C
# Prerequisites
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
@@ -20,36 +23,41 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
syslog-ng-core \
syslog-ng-mod-redis \
dirmngr \
netcat \
netcat-traditional \
psmisc \
wget \
patch \
python3 python3-pip \
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& mkdir /usr/share/doc/sogo \
&& touch /usr/share/doc/sogo/empty.sh \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-key 0x810273C4 \
&& echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \
&& wget -O- https://keys.openpgp.org/vks/v1/by-fingerprint/74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 | gpg --dearmor | apt-key add - \
&& echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} main" > /etc/apt/sources.list.d/sogo.list \
&& apt-get update && apt-get install -y --no-install-recommends \
sogo \
sogo-activesync \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/sogo.list \
&& rm -rf /var/lib/apt/lists/* \
&& touch /etc/default/locale
COPY ./bootstrap-sogo.sh /bootstrap-sogo.sh
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY acl.diff /acl.diff
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY docker-entrypoint.sh /
RUN pip install --break-system-packages \
mysql-connector-python \
jinja2 \
redis \
dnspython \
psutil
RUN chmod +x /bootstrap-sogo.sh \
/usr/local/sbin/stop-supervisor.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
COPY data/Dockerfiles/bootstrap /bootstrap
COPY data/Dockerfiles/sogo/syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY data/Dockerfiles/sogo/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY data/Dockerfiles/sogo/supervisord.conf /etc/supervisor/supervisord.conf
COPY data/Dockerfiles/sogo/stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY data/Dockerfiles/sogo/docker-entrypoint.sh /
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
RUN chmod +x /usr/local/sbin/stop-supervisor.sh
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -1,11 +0,0 @@
--- /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox 2018-08-17 18:29:57.987504204 +0200
+++ /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox 2018-08-17 18:29:35.918291298 +0200
@@ -46,7 +46,7 @@
</md-item-template>
</md-autocomplete>
</div>
- <md-card ng-repeat="user in acl.users | orderBy:['userClass', 'cn']"
+ <md-card ng-repeat="user in acl.users | filter:{ userClass: 'normal' } | orderBy:['cn']"
class="sg-collapsed"
ng-class="{ 'sg-expanded': user.uid == acl.selectedUid }">
<a class="md-flex md-button" ng-click="acl.selectUser(user, $event)">

View File

@@ -1,247 +0,0 @@
#!/bin/bash
# Wait for MySQL to warm-up
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for database to come up..."
sleep 2
done
# Wait until port becomes free and send sig
until ! nc -z sogo-mailcow 20000;
do
killall -TERM sogod
sleep 3
done
# Wait for updated schema
DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2)
while [[ "${DBV_NOW}" != "${DBV_NEW}" ]]; do
echo "Waiting for schema update..."
DBV_NOW=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT version FROM versions WHERE application = 'db_schema';" -BN)
DBV_NEW=$(grep -oE '\$db_version = .*;' init_db.inc.php | sed 's/$db_version = //g;s/;//g' | cut -d \" -f2)
sleep 5
done
echo "DB schema is ${DBV_NOW}"
# Recreate view
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "We are master, preparing sogo_view..."
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
while [[ ${VIEW_OK} != 'OK' ]]; do
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) AS
SELECT
mailbox.username,
mailbox.domain,
mailbox.username,
IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.force_pw_update')) = '0', IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.sogo_access')) = 1, password, '{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'), '{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'),
mailbox.name,
mailbox.username,
IFNULL(GROUP_CONCAT(ga.aliases ORDER BY ga.aliases SEPARATOR ' '), ''),
IFNULL(gda.ad_alias, ''),
IFNULL(external_acl.send_as_acl, ''),
mailbox.kind,
mailbox.multiple_bookings
FROM
mailbox
LEFT OUTER JOIN
grouped_mail_aliases ga
ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)')
LEFT OUTER JOIN
grouped_domain_alias_address gda
ON gda.username = mailbox.username
LEFT OUTER JOIN
grouped_sender_acl_external external_acl
ON external_acl.username = mailbox.username
WHERE
mailbox.active = '1'
GROUP BY
mailbox.username;
EOF
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
VIEW_OK=OK
else
echo "Will retry to setup SOGo view in 3s..."
sleep 3
fi
done
else
while [[ ${VIEW_OK} != 'OK' ]]; do
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sogo_view'") ]]; then
VIEW_OK=OK
else
echo "Waiting for SOGo view to be created by master..."
sleep 3
fi
done
fi
# Wait for static view table if missing after update and update content
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "We are master, preparing _sogo_static_view..."
while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
STATIC_VIEW_OK=OK
echo "Updating _sogo_static_view content..."
# If changed, also update init_db.inc.php
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "REPLACE INTO _sogo_static_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings) SELECT c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, ext_acl, kind, multiple_bookings from sogo_view;"
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "DELETE FROM _sogo_static_view WHERE c_uid NOT IN (SELECT username FROM mailbox WHERE active = '1')"
else
echo "Waiting for database initialization..."
sleep 3
fi
done
else
while [[ ${STATIC_VIEW_OK} != 'OK' ]]; do
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '_sogo_static_view'") ]]; then
STATIC_VIEW_OK=OK
else
echo "Waiting for database initialization by master..."
sleep 3
fi
done
fi
# Recreate password update trigger
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "We are master, preparing update trigger..."
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TRIGGER IF EXISTS sogo_update_password"
while [[ ${TRIGGER_OK} != 'OK' ]]; do
mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
DELIMITER -
CREATE TRIGGER sogo_update_password AFTER UPDATE ON _sogo_static_view
FOR EACH ROW
BEGIN
UPDATE mailbox SET password = NEW.c_password WHERE NEW.c_uid = username;
END;
-
DELIMITER ;
EOF
if [[ ! -z $(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -B -e "SELECT 'OK' FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME = 'sogo_update_password'") ]]; then
TRIGGER_OK=OK
else
echo "Will retry to setup SOGo password update trigger in 3s"
sleep 3
fi
done
fi
# cat /dev/urandom seems to hang here occasionally and is not recommended anyway, better use openssl
RAND_PASS=$(openssl rand -base64 16 | tr -dc _A-Z-a-z-0-9)
# Generate plist header with timezone data
mkdir -p /var/lib/sogo/GNUstep/Defaults/
cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//GNUstep//DTD plist 0.9//EN" "http://www.gnustep.org/plist-0_9.xml">
<plist version="0.9">
<dict>
<key>OCSAclURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_acl</string>
<key>SOGoIMAPServer</key>
<string>imap://${IPV4_NETWORK}.250:143/?TLS=YES&amp;tlsVerifyMode=none</string>
<key>SOGoTrustProxyAuthentication</key>
<string>YES</string>
<key>SOGoEncryptionKey</key>
<string>${RAND_PASS}</string>
<key>OCSCacheFolderURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_cache_folder</string>
<key>OCSEMailAlarmsFolderURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_alarms_folder</string>
<key>OCSFolderInfoURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_folder_info</string>
<key>OCSSessionsFolderURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_sessions_folder</string>
<key>OCSStoreURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_store</string>
<key>SOGoProfileURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_user_profile</string>
<key>SOGoTimeZone</key>
<string>${TZ}</string>
<key>domains</key>
<dict>
EOF
# Generate multi-domain setup
while read -r line gal
do
echo " <key>${line}</key>
<dict>
<key>SOGoMailDomain</key>
<string>${line}</string>
<key>SOGoUserSources</key>
<array>
<dict>
<key>MailFieldNames</key>
<array>
<string>aliases</string>
<string>ad_aliases</string>
<string>ext_acl</string>
</array>
<key>KindFieldName</key>
<string>kind</string>
<key>DomainFieldName</key>
<string>domain</string>
<key>MultipleBookingsFieldName</key>
<string>multiple_bookings</string>
<key>listRequiresDot</key>
<string>NO</string>
<key>canAuthenticate</key>
<string>YES</string>
<key>displayName</key>
<string>GAL ${line}</string>
<key>id</key>
<string>${line}</string>
<key>isAddressBook</key>
<string>${gal}</string>
<key>type</key>
<string>sql</string>
<key>userPasswordAlgorithm</key>
<string>${MAILCOW_PASS_SCHEME}</string>
<key>prependPasswordScheme</key>
<string>YES</string>
<key>viewURL</key>
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/_sogo_static_view</string>
</dict>" >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
# Generate alternative LDAP authentication dict, when SQL authentication fails
# This will nevertheless read attributes from LDAP
line=${line} envsubst < /etc/sogo/plist_ldap >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
echo " </array>
</dict>" >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
done < <(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain, CASE gal WHEN '1' THEN 'YES' ELSE 'NO' END AS gal FROM domain;" -B -N)
# Generate footer
echo ' </dict>
</dict>
</plist>' >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
# Fix permissions
chown sogo:sogo -R /var/lib/sogo/
chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
# Patch ACLs
#if [[ ${ACL_ANYONE} == 'allow' ]]; then
# #enable any or authenticated targets for ACL
# if patch -R -sfN --dry-run /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox < /acl.diff > /dev/null; then
# patch -R /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox < /acl.diff;
# fi
#else
# #disable any or authenticated targets for ACL
# if patch -sfN --dry-run /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox < /acl.diff > /dev/null; then
# patch /usr/lib/GNUstep/SOGo/Templates/UIxAclEditor.wox < /acl.diff;
# fi
#fi
# Copy logo, if any
[[ -f /etc/sogo/sogo-full.svg ]] && cp /etc/sogo/sogo-full.svg /usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg
# Rsync web content
echo "Syncing web content with named volume"
rsync -a /usr/lib/GNUstep/SOGo/. /sogo_web/
# Chown backup path
chown -R sogo:sogo /sogo_backup
exec gosu sogo /usr/sbin/sogod

View File

@@ -1,15 +1,5 @@
#!/bin/bash
if [[ "${SKIP_SOGO}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_SOGO=y, skipping SOGo..."
sleep 365d
exit 0
fi
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
fi
# Run hooks
for file in /hooks/*; do
if [ -x "${file}" ]; then
@@ -18,4 +8,13 @@ for file in /hooks/*; do
fi
done
exec "$@"
python3 -u /bootstrap/main.py
BOOTSTRAP_EXIT_CODE=$?
if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting SOGo."
exit $BOOTSTRAP_EXIT_CODE
fi
echo "Bootstrap succeeded. Starting SOGo..."
exec gosu sogo /usr/sbin/sogod

View File

@@ -11,8 +11,8 @@ stderr_logfile_maxbytes=0
autostart=true
priority=1
[program:bootstrap-sogo]
command=/bootstrap-sogo.sh
[program:bootstrap]
command=/docker-entrypoint.sh
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr

View File

@@ -1,4 +1,4 @@
@version: 3.28
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("`REDIS_SLAVEOF_IP`")
persist-name("redis2")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

View File

@@ -1,4 +1,4 @@
@version: 3.28
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -22,6 +22,7 @@ destination d_redis_ui_log {
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
@@ -30,6 +31,7 @@ destination d_redis_f2b_channel {
host("redis-mailcow")
persist-name("redis2")
port(6379)
auth("`REDISPASS`")
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
);
};

Some files were not shown because too many files have changed in this diff Show More