Compare commits

...

563 Commits

Author SHA1 Message Date
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
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
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
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 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
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
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
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
DerLinkman a71cc759f6 Renamed some Lang Classes + Added some new Strings 2022-12-12 11:58:40 +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
DerLinkman 77f04d10c7 Update Base Images to Alpine 3.17 2022-12-01 23:02:03 +01:00
DerLinkman d55994b66a Merge branch 'staging' into nightly 2022-12-01 21:06:19 +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 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 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 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
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
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
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
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
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
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 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 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
DerLinkman a2b31cb28d Merge branch 'staging' into nightly 2022-10-25 12:25:34 +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 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 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
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
DerLinkman b8656763ec Merge branch 'staging' into nightly 2022-10-06 14:25:39 +02:00
FreddleSpl0it 10e560c5b2 fix set rspamd worker password 2022-10-01 15:56:45 +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
DerLinkman 8c80cecdfb Merge remote-tracking branch 'origin/staging' into nightly 2022-09-27 21:41:21 +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
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
DerLinkman e74af0db89 Merge branch 'staging' into nightly 2022-09-08 12:35:51 +02:00
DerLinkman 5ff62d8f22 Merge branch 'staging' into nightly 2022-09-02 10:25:28 +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
DerLinkman cf5fa96a93 Merge branch 'staging' into nightly 2022-09-01 13:57:39 +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
FreddleSpl0it 77e6124b00 [BS5] move showWhatsNewModal 2022-08-23 14:24:10 +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
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
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
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
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
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
FreddleSpl0it 8a49b50f33 [BS5] fix minor issues 2022-07-06 16:55:31 +02: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
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
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 052959f435 [BS5] remove ui theme selector - add darkmode toggler 2022-06-23 16:34:58 +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
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
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
FreddleSpl0it cdd2adbc73 [BS5] remember last nav pill fix 2022-06-07 15:28:28 +02:00
FreddleSpl0it cb6a5d4069
[BS5] add responsive tabs and more 2022-06-06 20:38:24 +02:00
FreddleSpl0it f13530d8a1 [BS5] Replace FooTable with jquery Datatables 2022-06-03 15:45:36 +02:00
FreddleSpl0it 8a86fa491e
[BS5] Replace FooTable with jquery Datatables 2022-05-20 12:03:12 +02:00
FreddleSpl0it 3e6a241c69
[BS5] Replace FooTable with jquery Datatables 2022-05-19 21:29:01 +02:00
FreddleSpl0it 160dceff3e
[BS5] Replace FooTable with jquery Datatables 2022-05-19 15:06:18 +02:00
FreddleSpl0it 0ece065cb0
[BS5] Replace FooTable with jquery Datatables 2022-05-17 14:08:22 +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
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
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
265 changed files with 66555 additions and 11461 deletions

View File

@ -26,21 +26,21 @@ 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: text
render: plain text
validations:
required: true
- type: textarea
attributes:
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: text
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."
render: text
render: plain text
placeholder: |-
1. ...
2. ...
@ -117,41 +117,41 @@ body:
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: text
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of iptables -L -vn:"
description: "#### Output of `iptables -L -vn`"
render: text
render: plain text
validations:
required: true
- type: textarea
attributes:
label: "Logs of ip6tables -L -vn:"
description: "#### Output of `ip6tables -L -vn`"
render: text
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: text
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: text
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: text
render: plain text
validations:
required: true

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

@ -0,0 +1,31 @@
{
"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\/matthiasmullie\/minify\/**"
],
"regexManagers": [
{
"fileMatch": ["^helper-scripts\/nextcloud.sh$"],
"matchStrings": [
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?( extractVersion=(?<extractVersion>.*?))?\\s.*?_VERSION=(?<currentValue>.*)"
]
},
{
"fileMatch": ["(^|/)Dockerfile[^/]*$"],
"matchStrings": [
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s(ENV|ARG) .*?_VERSION=(?<currentValue>.*)\\s"
]
}
]
}

View File

@ -10,7 +10,7 @@ jobs:
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@main
uses: thollander/actions-comment-pull-request@v2.4.0
with:
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
message: |

View File

@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v6.0.1
uses: actions/stale@v8.0.0
with:
repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60

View File

@ -33,13 +33,11 @@ jobs:
run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
sudo service docker start
sudo curl -L https://github.com/docker/compose/releases/download/v$(curl -Ls https://www.servercow.de/docker-compose/latest.php)/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
- 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}
docker compose build ${image}
env:
image: ${{ matrix.images }}

View File

@ -1,63 +0,0 @@
name: mailcow Integration Tests
on:
push:
branches: [ "master", "staging" ]
workflow_dispatch:
permissions:
contents: read
jobs:
integration_tests:
runs-on: ubuntu-latest
steps:
- name: Setup Ansible
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo apt-get install python3 python3-pip git
sudo pip3 install ansible
- name: Prepair Test Environment
run: |
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 .
./fork_check.sh
./ci.sh
./ci-pip-requirements.sh
env:
VAULT_PW: ${{ secrets.MAILCOW_TESTS_VAULT_PW }}
VAULT_FILE: ${{ secrets.MAILCOW_TESTS_VAULT_FILE }}
- name: Start Integration Test Server
run: |
./fork_check.sh
ansible-playbook mailcow-start-server.yml --diff
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
ANSIBLE_HOST_KEY_CHECKING: 'false'
- name: Setup Integration Test Server
run: |
./fork_check.sh
sleep 30
ansible-playbook mailcow-setup-server.yml --private-key id_ssh_rsa --diff
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
ANSIBLE_HOST_KEY_CHECKING: 'false'
- name: Run Integration Tests
run: |
./fork_check.sh
ansible-playbook mailcow-integration-tests.yml --private-key id_ssh_rsa --diff
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
ANSIBLE_HOST_KEY_CHECKING: 'false'
- name: Delete Integration Test Server
if: always()
run: |
./fork_check.sh
ansible-playbook mailcow-delete-server.yml --diff
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
ANSIBLE_HOST_KEY_CHECKING: 'false'

View File

@ -12,7 +12,7 @@ jobs:
with:
fetch-depth: 0
- name: Run the Action
uses: devops-infra/action-pull-request@v0.5.3
uses: devops-infra/action-pull-request@v0.5.5
with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}

View File

@ -26,7 +26,7 @@ jobs:
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
context: .
file: data/Dockerfiles/backup/Dockerfile

View File

@ -1,20 +0,0 @@
name: "Tweet trigger release"
on:
release:
types: [published]
jobs:
tweet:
runs-on: ubuntu-latest
steps:
- name: "Get Release Tag"
run: |
RELEASE_TAG=$(curl https://api.github.com/repos/mailcow/mailcow-dockerized/releases/latest | jq -r '.tag_name')
- name: Tweet-trigger-publish-release
uses: mugi111/tweet-trigger-release@v1.1
with:
consumer_key: ${{ secrets.CONSUMER_KEY }}
consumer_secret: ${{ secrets.CONSUMER_SECRET }}
access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }}
access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }}
tweet_body: 'A new mailcow update has just been released! Checkout the GitHub Page for changelog and more informations: github.com/mailcow/mailcow-dockerized/releases/tag/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@v3
- name: Generate postscreen_access.cidr
run: |
bash helper-scripts/update_postscreen_whitelist.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
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)

2
.gitignore vendored
View File

@ -36,6 +36,8 @@ data/conf/postfix/extra.cf
data/conf/postfix/sni.map
data/conf/postfix/sni.map.db
data/conf/postfix/sql
data/conf/postfix/dns_blocklists.cf
data/conf/postfix/dnsbl_reply.map
data/conf/rspamd/custom/*
data/conf/rspamd/local.d/*
data/conf/rspamd/override.d/*

View File

@ -1,8 +1,5 @@
# mailcow: dockerized - 🐮 + 🐋 = 💕
## We stand with 🇺🇦
[![Mailcow Integration Tests](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml/badge.svg?branch=master)](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml)
[![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)
@ -36,3 +33,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é)

View File

@ -1,6 +1,6 @@
FROM alpine:3.16
FROM alpine:3.17
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 \

View File

@ -213,11 +213,13 @@ while true; do
done
ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig')
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 #

View File

@ -1,4 +1,4 @@
FROM clamav/clamav:0.105.1_base
FROM clamav/clamav:1.0.1-1_base
LABEL maintainer "André Peters <andre.peters@servercow.de>"

View File

@ -1,6 +1,6 @@
FROM alpine:3.16
FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
WORKDIR /app
@ -8,11 +8,18 @@ RUN apk add --update --no-cache python3 \
py3-pip \
openssl \
tzdata \
py3-psutil \
&& pip3 install --upgrade pip \
fastapi \
uvicorn \
aiodocker \
docker \
flask \
flask-restful
aioredis
RUN mkdir /app/modules
COPY dockerapi.py /app/
COPY docker-entrypoint.sh /app/
COPY main.py /app/main.py
COPY modules/ /app/modules/
CMD ["python3", "-u", "/app/dockerapi.py"]
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
CMD exec 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,260 @@
import os
import sys
import uvicorn
import json
import uuid
import async_timeout
import asyncio
import aioredis
import aiodocker
import docker
import logging
from logging.config import dictConfig
from fastapi import FastAPI, Response, Request
from modules.DockerApi import DockerApi
dockerapi = None
app = FastAPI()
# 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")
# Events
@app.on_event("startup")
async def startup_event():
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")
else:
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0")
# 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))
@app.on_event("shutdown")
async def shutdown_event():
global dockerapi
# 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()
# PubSub Handler
async def handle_pubsub_messages(channel: aioredis.client.PubSub):
global dockerapi
while True:
try:
async with async_timeout.timeout(1):
message = await channel.get_message(ignore_subscribe_messages=True)
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("Unknwon PubSub recieved - %s" % json.dumps(data_json))
else:
dockerapi.logger.error("Unknwon PubSub recieved - %s" % json.dumps(data_json))
await asyncio.sleep(0.01)
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,487 @@
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: 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('\$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 = 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")
# 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,10 +1,13 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG DOVECOT=2.3.19.1
# renovate: datasource=github-tags depName=dovecot/core versioning=semver-coerced
ARG DOVECOT=2.3.20
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
ARG GOSU_VERSION=1.16
ENV LC_ALL C
ENV GOSU_VERSION 1.14
# Add groups and users before installing Dovecot to not break compatibility
RUN groupadd -g 5000 vmail \
@ -18,6 +21,7 @@ RUN groupadd -g 5000 vmail \
&& touch /etc/default/locale \
&& apt-get update \
&& apt-get -y --no-install-recommends install \
build-essential \
apt-transport-https \
ca-certificates \
cpanminus \
@ -58,6 +62,7 @@ RUN groupadd -g 5000 vmail \
libproc-processtable-perl \
libreadonly-perl \
libregexp-common-perl \
libssl-dev \
libsys-meminfo-perl \
libterm-readkey-perl \
libtest-deep-perl \
@ -107,6 +112,8 @@ RUN groupadd -g 5000 vmail \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* /var/tmp/* /root/.cache/
# imapsync dependencies
RUN cpan Crypt::OpenSSL::PKCS12
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh

View File

@ -159,7 +159,7 @@ function auth_password_verify(req, pass)
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
return dovecot.auth.PASSDB_RESULT_OK, ""
end
row = cur:fetch (row, "a")
end
@ -180,13 +180,13 @@ function auth_password_verify(req, pass)
if tostring(req.real_rip) == "__IPV4_SOGO__" then
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
return dovecot.auth.PASSDB_RESULT_OK, ""
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
return dovecot.auth.PASSDB_RESULT_OK, ""
end
end
row = cur:fetch (row, "a")

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

@ -1,5 +1,5 @@
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM alpine:3.17
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV XTABLES_LIBDIR /usr/lib/xtables
ENV PYTHON_IPTABLES_XTABLES_VERSION 12

View File

@ -64,28 +64,40 @@ def refreshF2boptions():
global f2boptions
global quit_now
global exit_code
f2boptions = {}
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))
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 = {}
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
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)
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
@ -97,9 +109,9 @@ def refreshF2bregex():
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[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))
@ -147,6 +159,7 @@ def ban(address):
global lock
refreshF2boptions()
BAN_TIME = int(f2boptions['ban_time'])
BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment'])
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
RETRY_WINDOW = int(f2boptions['retry_window'])
NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4'])
@ -174,20 +187,16 @@ def ban(address):
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']
if not net in bans:
bans[net] = {'attempts': 0, 'last_attempt': 0, 'ban_counter': 0}
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))
NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
if type(ip) is ipaddress.IPv4Address:
with lock:
chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
@ -206,7 +215,7 @@ def ban(address):
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME)
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
else:
logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
@ -238,7 +247,8 @@ def unban(net):
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
if net in bans:
del bans[net]
bans[net]['attempts'] = 0
bans[net]['ban_counter'] += 1
def permBan(net, unban=False):
global lock
@ -332,7 +342,7 @@ def watch():
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')
logWarn('Error reading log line from pubsub: %s' % ex)
quit_now = True
exit_code = 2
@ -359,21 +369,30 @@ def snat4(snat_target):
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
new_rule = get_snat4_rule()
for position, rule in enumerate(chain.rules):
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:
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else:
if match:
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)
if not chain.rules:
# if there are no rules in the chain, insert the new rule directly
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:
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else:
if match:
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
except:
@ -418,6 +437,8 @@ def autopurge():
time.sleep(10)
refreshF2boptions()
BAN_TIME = int(f2boptions['ban_time'])
MAX_BAN_TIME = int(f2boptions['max_ban_time'])
BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment'])
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
if QUEUE_UNBAN:
@ -425,7 +446,9 @@ def autopurge():
unban(str(net))
for net in bans.copy():
if bans[net]['attempts'] >= MAX_ATTEMPTS:
if time.time() - bans[net]['last_attempt'] > BAN_TIME:
NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
TIME_SINCE_LAST_ATTEMPT = time.time() - bans[net]['last_attempt']
if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME or TIME_SINCE_LAST_ATTEMPT > MAX_BAN_TIME:
unban(net)
def isIpNetwork(address):

View File

@ -1,5 +1,5 @@
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM alpine:3.17
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
WORKDIR /app

View File

@ -1,12 +1,18 @@
FROM php:8.1-fpm-alpine3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
FROM php:8.2-fpm-alpine3.17
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV APCU_PECL 5.1.22
ENV IMAGICK_PECL 3.7.0
ENV MAILPARSE_PECL 3.1.4
ENV MEMCACHED_PECL 3.2.0
ENV REDIS_PECL 5.3.7
ENV COMPOSER 2.4.4
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced
ARG APCU_PECL_VERSION=5.1.22
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced
ARG IMAGICK_PECL_VERSION=3.7.0
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced
ARG MAILPARSE_PECL_VERSION=3.1.4
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced
ARG MEMCACHED_PECL_VERSION=3.2.0
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced
ARG REDIS_PECL_VERSION=5.3.7
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced
ARG COMPOSER_VERSION=2.5.5
RUN apk add -U --no-cache autoconf \
aspell-dev \
@ -46,6 +52,7 @@ RUN apk add -U --no-cache autoconf \
libxpm-dev \
libzip \
libzip-dev \
linux-headers \
make \
mysql-client \
openldap-dev \
@ -55,11 +62,11 @@ RUN apk add -U --no-cache autoconf \
samba-client \
zlib-dev \
tzdata \
&& pecl install mailparse-${MAILPARSE_PECL} \
&& pecl install redis-${REDIS_PECL} \
&& pecl install memcached-${MEMCACHED_PECL} \
&& pecl install APCu-${APCU_PECL} \
&& pecl install imagick-${IMAGICK_PECL} \
&& 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 \
@ -69,10 +76,10 @@ RUN apk add -U --no-cache autoconf \
--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-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets sysvsem 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 -- --version=${COMPOSER} \
&& 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 \
@ -93,6 +100,7 @@ RUN apk add -U --no-cache autoconf \
libxml2-dev \
libxpm-dev \
libzip-dev \
linux-headers \
make \
openldap-dev \
pcre-dev \
@ -102,4 +110,4 @@ COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["php-fpm"]
CMD ["php-fpm"]

View File

@ -172,6 +172,24 @@ BEGIN
END;
//
DELIMITER ;
DROP EVENT IF EXISTS clean_sasl_log;
DELIMITER //
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;
//
DELIMITER ;
EOF
fi

View File

@ -1,5 +1,5 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ENV LC_ALL C
@ -17,10 +17,10 @@ RUN groupadd -g 102 postfix \
ca-certificates \
curl \
dirmngr \
dnsutils \
dnsutils \
gnupg \
libsasl2-modules \
mariadb-client \
mariadb-client \
perl \
postfix \
postfix-mysql \
@ -32,7 +32,7 @@ RUN groupadd -g 102 postfix \
syslog-ng \
syslog-ng-core \
syslog-ng-mod-redis \
tzdata \
tzdata \
&& 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 \

View File

@ -393,12 +393,101 @@ query = SELECT goto FROM spamalias
AND validity >= UNIX_TIMESTAMP()
EOF
sed -i '/User overrides/q' /opt/postfix/conf/main.cf
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
cat <<EOF > /opt/postfix/conf/dns_blocklists.cf
# This file can be edited.
# Delete this file and restart postfix container to revert any changes.
postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
hostkarma.junkemailfilter.com=127.0.0.1*-2
list.dnswl.org=127.0.[0..255].0*-2
list.dnswl.org=127.0.[0..255].1*-4
list.dnswl.org=127.0.[0..255].2*-6
list.dnswl.org=127.0.[0..255].3*-8
ix.dnsbl.manitu.net*2
bl.spamcop.net*2
bl.suomispam.net*2
hostkarma.junkemailfilter.com=127.0.0.2*3
hostkarma.junkemailfilter.com=127.0.0.4*2
hostkarma.junkemailfilter.com=127.0.1.2*1
backscatter.spameatingmonkey.net*2
bl.ipv6.spameatingmonkey.net*2
bl.spameatingmonkey.net*2
b.barracudacentral.org=127.0.0.2*7
bl.mailspike.net=127.0.0.2*5
bl.mailspike.net=127.0.0.[10;11;12]*4
dnsbl.sorbs.net=127.0.0.10*8
dnsbl.sorbs.net=127.0.0.5*6
dnsbl.sorbs.net=127.0.0.7*3
dnsbl.sorbs.net=127.0.0.8*2
dnsbl.sorbs.net=127.0.0.6*2
dnsbl.sorbs.net=127.0.0.9*2
EOF
fi
DNSBL_CONFIG=$(grep -v '^#' /opt/postfix/conf/dns_blocklists.cf | grep '\S')
if [ ! -z "$DNSBL_CONFIG" ]; then
echo -e "\e[33mChecking if ASN for your IP is listed for Spamhaus Bad ASN List...\e[0m"
if [ -n "$SPAMHAUS_DQS_KEY" ]; then
echo -e "\e[32mDetected SPAMHAUS_DQS_KEY variable from mailcow.conf...\e[0m"
echo -e "\e[33mUsing DQS Blocklists from Spamhaus!\e[0m"
SPAMHAUS_DNSBL_CONFIG=$(cat <<EOF
${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net=127.0.0.[4..7]*6
${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net=127.0.0.[10;11]*8
${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net=127.0.0.3*4
${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net=127.0.0.2*3
postscreen_dnsbl_reply_map = texthash:/opt/postfix/conf/dnsbl_reply.map
EOF
cat <<EOF > /opt/postfix/conf/dnsbl_reply.map
# Autogenerated by mailcow, using Spamhaus DQS reply domains
${SPAMHAUS_DQS_KEY}.sbl.dq.spamhaus.net sbl.spamhaus.org
${SPAMHAUS_DQS_KEY}.xbl.dq.spamhaus.net xbl.spamhaus.org
${SPAMHAUS_DQS_KEY}.pbl.dq.spamhaus.net pbl.spamhaus.org
${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net zen.spamhaus.org
${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net dbl.spamhaus.org
${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net zrd.spamhaus.org
EOF
)
else
if [ -f "/opt/postfix/conf/dnsbl_reply.map" ]; then
rm /opt/postfix/conf/dnsbl_reply.map
fi
response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
if [ "$response" -eq 503 ]; then
echo -e "\e[31mThe AS of your IP is listed as a banned AS from Spamhaus!\e[0m"
echo -e "\e[33mNo SPAMHAUS_DQS_KEY found... Skipping Spamhaus blocklists entirely!\e[0m"
SPAMHAUS_DNSBL_CONFIG=""
elif [ "$response" -eq 200 ]; then
echo -e "\e[32mThe AS of your IP is NOT listed as a banned AS from Spamhaus!\e[0m"
echo -e "\e[33mUsing the open Spamhaus blocklists.\e[0m"
SPAMHAUS_DNSBL_CONFIG=$(cat <<EOF
zen.spamhaus.org=127.0.0.[10;11]*8
zen.spamhaus.org=127.0.0.[4..7]*6
zen.spamhaus.org=127.0.0.3*4
zen.spamhaus.org=127.0.0.2*3
EOF
)
else
echo -e "\e[31mWe couldn't determine your AS... (maybe DNS/Network issue?) Response Code: $response\e[0m"
echo -e "\e[33mDeactivating Spamhaus DNS Blocklists to be on the safe site!\e[0m"
SPAMHAUS_DNSBL_CONFIG=""
fi
fi
fi
# Reset main.cf
sed -i '/Overrides/q' /opt/postfix/conf/main.cf
echo >> /opt/postfix/conf/main.cf
# Append postscreen dnsbl sites to main.cf
if [ ! -z "$DNSBL_CONFIG" ]; then
echo -e "${DNSBL_CONFIG}\n${SPAMHAUS_DNSBL_CONFIG}" >> /opt/postfix/conf/main.cf
fi
# Append user overrides
echo -e "\n# User Overrides" >> /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

View File

@ -1,5 +1,5 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@tinc.gmbh>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG CODENAME=bullseye
@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y \
COPY settings.conf /etc/rspamd/settings.conf
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
COPY set_worker_password.sh /set_worker_password.sh
COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]

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,11 @@
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
ARG GOSU_VERSION=1.16
ENV LC_ALL C
ENV GOSU_VERSION 1.14
# Prerequisites
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \

View File

@ -2,7 +2,8 @@ FROM solr:7.7-slim
USER root
ENV GOSU_VERSION 1.11
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
ARG GOSU_VERSION=1.16
COPY solr.sh /
COPY solr-config-7.7.0.xml /

View File

@ -1,6 +1,6 @@
FROM alpine:3.16
FROM alpine:3.17
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
RUN apk add --update --no-cache \
curl \

View File

@ -1,4 +1,4 @@
FROM alpine:3.16
FROM alpine:3.17
LABEL maintainer "André Peters <andre.peters@servercow.de>"
# Installation

View File

@ -24,7 +24,7 @@ server {
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
fastcgi_hide_header X-Powered-By;

View File

@ -24,6 +24,11 @@ mail_plugins = </etc/dovecot/mail_plugins
mail_attachment_fs = crypt:set_prefix=mail_crypt_global:posix:
mail_attachment_dir = /var/attachments
mail_attachment_min_size = 128k
# Significantly speeds up very large mailboxes, but is only safe to enable if
# you do not manually modify the files in the `cur` directories in
# mailcowdockerized_vmail-vol-1.
# https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-performance/
maildir_very_dirty_syncs = yes
# Dovecot 2.2
#ssl_protocols = !SSLv3

View File

@ -114,7 +114,7 @@
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
error_page 403 /_rspamderror.php;
error_page 401 /_rspamderror.php;
}
proxy_pass http://rspamd:11334/;
proxy_set_header Host $http_host;

View File

@ -40,34 +40,6 @@ postscreen_blacklist_action = drop
postscreen_cache_cleanup_interval = 24h
postscreen_cache_map = proxy:btree:$data_directory/postscreen_cache
postscreen_dnsbl_action = enforce
postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
hostkarma.junkemailfilter.com=127.0.0.1*-2
list.dnswl.org=127.0.[0..255].0*-2
list.dnswl.org=127.0.[0..255].1*-4
list.dnswl.org=127.0.[0..255].2*-6
list.dnswl.org=127.0.[0..255].3*-8
ix.dnsbl.manitu.net*2
bl.spamcop.net*2
bl.suomispam.net*2
hostkarma.junkemailfilter.com=127.0.0.2*3
hostkarma.junkemailfilter.com=127.0.0.4*2
hostkarma.junkemailfilter.com=127.0.1.2*1
backscatter.spameatingmonkey.net*2
bl.ipv6.spameatingmonkey.net*2
bl.spameatingmonkey.net*2
b.barracudacentral.org=127.0.0.2*7
bl.mailspike.net=127.0.0.2*5
bl.mailspike.net=127.0.0.[10;11;12]*4
dnsbl.sorbs.net=127.0.0.10*8
dnsbl.sorbs.net=127.0.0.5*6
dnsbl.sorbs.net=127.0.0.7*3
dnsbl.sorbs.net=127.0.0.8*2
dnsbl.sorbs.net=127.0.0.6*2
dnsbl.sorbs.net=127.0.0.9*2
zen.spamhaus.org=127.0.0.[10;11]*8
zen.spamhaus.org=127.0.0.[4..7]*6
zen.spamhaus.org=127.0.0.3*4
zen.spamhaus.org=127.0.0.2*3
postscreen_dnsbl_threshold = 6
postscreen_dnsbl_ttl = 5m
postscreen_greet_action = enforce
@ -197,4 +169,4 @@ smtps_smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
parent_domain_matches_subdomains = debug_peer_list,fast_flush_domains,mynetworks,qmqpd_authorized_clients
# DO NOT EDIT ANYTHING BELOW #
# User overrides #
# Overrides #

View File

@ -1,15 +1,20 @@
# Whitelist generated by Postwhite v3.4 on Mon 21 Mar 2022 06:50:26 PM CET
# Whitelist generated by Postwhite v3.4 on Mon Jul 31 10:06:06 UTC 2023
# https://github.com/stevejenkins/postwhite/
# 1898 total rules
# 2043 total rules
2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit
2a01:111:f403::/48 permit
2a01:4180:4050:0400::/64 permit
2a01:4180:4050:0800::/64 permit
2a01:4180:4051:0400::/64 permit
2a01:4180:4051:0800::/64 permit
2a01:111:f403:8000::/50 permit
2a01:111:f403::/49 permit
2a01:111:f403:c000::/51 permit
2a01:111:f403:f000::/52 permit
2a02:a60:0:5::/64 permit
2c0f:fb50:4000::/36 permit
2.207.151.53 permit
3.14.230.16 permit
3.70.123.177 permit
3.93.157.0/24 permit
3.129.120.190 permit
3.210.190.0/24 permit
8.20.114.31 permit
8.25.194.0/23 permit
8.25.196.0/23 permit
@ -19,41 +24,53 @@
13.70.32.43 permit
13.72.50.45 permit
13.74.143.28 permit
13.77.161.179 permit
13.78.233.182 permit
13.92.31.129 permit
13.110.208.0/21 permit
13.110.209.0/24 permit
13.110.216.0/22 permit
13.110.224.0/20 permit
13.111.0.0/16 permit
17.41.0.0/16 permit
15.200.21.50 permit
15.200.44.248 permit
15.200.201.185 permit
17.57.155.0/24 permit
17.57.156.0/24 permit
17.58.0.0/16 permit
17.110.0.0/15 permit
17.142.0.0/15 permit
17.162.0.0/15 permit
17.164.0.0/16 permit
17.171.37.0/24 permit
17.172.0.0/16 permit
17.179.168.0/23 permit
18.156.89.250 permit
18.157.243.190 permit
18.194.95.56 permit
18.198.96.88 permit
20.47.149.138 permit
20.48.0.0/12 permit
18.208.124.128/25 permit
18.216.232.154 permit
18.234.1.244 permit
18.236.40.242 permit
20.51.6.32/30 permit
20.52.52.2 permit
20.52.128.133 permit
20.59.80.4/30 permit
20.63.210.192/28 permit
20.64.0.0/10 permit
20.69.8.108/30 permit
20.70.246.20 permit
20.76.201.171 permit
20.83.222.104/30 permit
20.88.157.184/30 permit
20.94.180.64/28 permit
20.97.34.220/30 permit
20.98.148.156/30 permit
20.98.194.68/30 permit
20.105.209.76/30 permit
20.107.239.64/30 permit
20.112.250.133 permit
20.118.139.208/30 permit
20.185.213.160/27 permit
20.185.213.224/27 permit
20.185.214.0/27 permit
20.185.214.2 permit
20.185.214.32/27 permit
20.185.214.64/27 permit
20.192.0.0/10 permit
23.100.85.1 permit
20.231.239.246 permit
20.236.44.162 permit
23.103.224.0/19 permit
23.249.208.0/20 permit
23.251.224.0/19 permit
@ -78,46 +95,38 @@
27.123.206.56/29 permit
27.123.206.76/30 permit
27.123.206.80/28 permit
34.194.25.167 permit
34.194.144.120 permit
31.25.48.222 permit
34.195.217.107 permit
34.202.239.6 permit
34.212.163.75 permit
34.215.104.144 permit
34.225.212.172 permit
34.247.168.44 permit
35.161.32.253 permit
35.167.93.243 permit
35.176.132.251 permit
35.190.247.0/24 permit
35.191.0.0/16 permit
37.188.97.188 permit
37.218.248.47 permit
37.218.249.47 permit
37.218.251.62 permit
39.156.163.64/29 permit
40.71.187.0/24 permit
40.76.4.15 permit
40.77.102.222 permit
40.92.0.0/15 permit
40.97.116.82 permit
40.97.128.194 permit
40.97.148.226 permit
40.97.153.146 permit
40.97.156.114 permit
40.97.160.2 permit
40.97.161.50 permit
40.97.164.146 permit
40.107.0.0/16 permit
40.112.65.63 permit
40.112.72.205 permit
40.113.200.201 permit
40.117.80.0/24 permit
40.121.71.46 permit
41.74.192.0/22 permit
41.74.196.0/22 permit
41.74.200.0/23 permit
41.74.204.0/23 permit
41.74.206.0/24 permit
42.159.163.81 permit
42.159.163.82 permit
42.159.163.83 permit
43.228.184.0/22 permit
44.206.138.57 permit
44.209.42.157 permit
44.236.56.93 permit
44.238.220.251 permit
46.19.168.0/23 permit
46.226.48.0/21 permit
46.228.36.37 permit
46.228.36.38/31 permit
@ -167,6 +176,8 @@
46.243.88.175 permit
46.243.88.176 permit
46.243.88.177 permit
46.243.95.179 permit
46.243.95.180 permit
50.18.45.249 permit
50.18.121.236 permit
50.18.121.248 permit
@ -178,11 +189,6 @@
50.31.32.0/19 permit
50.31.156.96/27 permit
50.31.205.0/24 permit
51.4.71.62 permit
51.4.72.0/24 permit
51.4.80.0/27 permit
51.5.72.0/24 permit
51.5.80.0/27 permit
51.137.58.21 permit
51.140.75.55 permit
51.144.100.179 permit
@ -191,17 +197,28 @@
52.5.230.59 permit
52.27.5.72 permit
52.27.28.47 permit
52.33.191.91 permit
52.28.63.81 permit
52.36.138.31 permit
52.37.142.146 permit
52.38.191.253 permit
52.41.64.145 permit
52.58.216.183 permit
52.59.143.3 permit
52.60.41.5 permit
52.60.115.116 permit
52.61.91.9 permit
52.71.0.205 permit
52.82.172.0/22 permit
52.94.124.0/28 permit
52.95.48.152/29 permit
52.95.49.88/29 permit
52.96.91.34 permit
52.96.111.82 permit
52.96.172.98 permit
52.96.214.50 permit
52.96.222.194 permit
52.96.222.226 permit
52.96.223.2 permit
52.96.228.130 permit
52.96.229.242 permit
52.100.0.0/14 permit
52.119.213.144/28 permit
52.160.39.140 permit
@ -214,23 +231,29 @@
52.222.73.83 permit
52.222.73.120 permit
52.222.75.85 permit
52.222.89.228 permit
52.234.172.96/28 permit
52.236.28.240/28 permit
52.237.141.173 permit
52.244.206.214 permit
52.247.53.144 permit
52.250.107.196 permit
52.250.126.174 permit
52.251.55.143 permit
54.90.148.255 permit
54.156.255.69 permit
54.172.97.247 permit
54.174.52.0/24 permit
54.174.53.128/30 permit
54.174.57.0/24 permit
54.174.59.0/24 permit
54.174.60.0/23 permit
54.174.63.0/24 permit
54.186.193.102 permit
54.191.223.5 permit
54.191.223.56 permit
54.194.61.95 permit
54.195.113.45 permit
54.213.20.246 permit
54.214.39.184 permit
54.216.77.168 permit
54.221.227.204 permit
54.240.0.0/18 permit
54.240.64.0/19 permit
54.240.96.0/19 permit
@ -238,7 +261,9 @@
54.244.54.130 permit
54.244.242.0/24 permit
54.246.232.180 permit
54.255.61.23 permit
62.13.128.0/24 permit
62.13.128.150 permit
62.13.129.128/25 permit
62.13.136.0/22 permit
62.13.140.0/22 permit
@ -249,22 +274,29 @@
62.17.146.128/26 permit
62.140.7.0/24 permit
62.140.10.21 permit
62.179.121.0/24 permit
62.201.172.0/27 permit
62.201.172.32/27 permit
62.253.227.114 permit
63.32.13.159 permit
63.80.14.0/23 permit
63.111.28.137 permit
63.128.21.0/24 permit
63.143.57.128/25 permit
63.143.59.128/25 permit
64.18.0.0/20 permit
64.20.241.45 permit
64.34.47.128/27 permit
64.34.57.192/26 permit
64.69.212.0/24 permit
64.71.149.160/28 permit
64.79.155.0/24 permit
64.79.155.192 permit
64.79.155.193 permit
64.79.155.205 permit
64.79.155.206 permit
64.89.44.85 permit
64.89.45.80 permit
64.89.45.194 permit
64.89.45.196 permit
64.95.144.196 permit
64.127.115.252 permit
64.132.88.0/23 permit
64.132.92.0/24 permit
@ -290,6 +322,7 @@
64.207.219.71 permit
64.207.219.72 permit
64.207.219.73 permit
64.207.219.75 permit
64.207.219.77 permit
64.207.219.78 permit
64.207.219.79 permit
@ -300,9 +333,6 @@
64.207.219.142 permit
64.207.219.143 permit
64.233.160.0/19 permit
65.38.115.76 permit
65.38.115.84 permit
65.39.215.0/24 permit
65.52.80.137 permit
65.54.51.64/26 permit
65.54.61.64/26 permit
@ -342,6 +372,10 @@
66.111.4.225 permit
66.111.4.229 permit
66.111.4.230 permit
66.119.150.192/26 permit
66.135.202.0/27 permit
66.135.215.0/24 permit
66.135.222.1 permit
66.162.193.226/31 permit
66.163.184.0/21 permit
66.163.184.0/24 permit
@ -373,7 +407,8 @@
66.196.81.234 permit
66.211.168.230/31 permit
66.211.170.86/31 permit
66.211.170.88/30 permit
66.211.170.88/29 permit
66.211.184.0/23 permit
66.218.74.64/30 permit
66.218.74.68/31 permit
66.218.75.112/30 permit
@ -445,6 +480,8 @@
68.142.230.72/30 permit
68.142.230.76/31 permit
68.142.230.78 permit
68.232.140.138 permit
68.232.157.143 permit
68.232.192.0/20 permit
69.63.178.128/25 permit
69.63.181.0/24 permit
@ -452,6 +489,10 @@
69.65.42.195 permit
69.65.49.192/29 permit
69.72.32.0/20 permit
69.72.40.93 permit
69.72.40.94/31 permit
69.72.40.96/30 permit
69.72.47.205 permit
69.147.84.227 permit
69.162.98.0/24 permit
69.169.224.0/20 permit
@ -460,7 +501,7 @@
70.37.151.128/25 permit
70.42.149.0/24 permit
70.42.149.35 permit
72.3.185.0/24 permit
72.3.237.64/28 permit
72.14.192.0/18 permit
72.21.192.0/19 permit
72.21.217.142 permit
@ -522,15 +563,11 @@
72.30.239.228/31 permit
72.30.239.244/30 permit
72.30.239.248/31 permit
72.32.154.0/24 permit
72.32.217.0/24 permit
72.32.243.0/24 permit
72.34.168.76 permit
72.34.168.80 permit
72.34.168.85 permit
72.34.168.86 permit
72.52.72.32/28 permit
72.52.72.36 permit
74.6.128.0/21 permit
74.6.128.0/24 permit
74.6.129.0/24 permit
@ -558,8 +595,11 @@
74.112.67.243 permit
74.125.0.0/16 permit
74.202.227.40 permit
74.208.4.192/26 permit
74.208.5.64/26 permit
74.208.122.0/26 permit
74.209.250.0/24 permit
74.209.250.12 permit
76.223.128.0/19 permit
76.223.176.0/20 permit
77.238.176.0/22 permit
77.238.176.0/24 permit
@ -583,7 +623,13 @@
77.238.189.146/31 permit
77.238.189.148/30 permit
81.223.46.0/27 permit
84.16.77.1 permit
82.165.159.0/24 permit
82.165.159.0/26 permit
82.165.229.31 permit
82.165.229.130 permit
82.165.230.21 permit
82.165.230.22 permit
84.116.36.0/24 permit
85.158.136.0/21 permit
86.61.88.25 permit
87.198.219.130 permit
@ -624,11 +670,11 @@
87.248.117.201 permit
87.248.117.202 permit
87.248.117.205 permit
87.252.219.254 permit
87.253.232.0/21 permit
89.22.108.0/24 permit
91.194.248.0/23 permit
91.211.240.0/22 permit
91.220.42.0/24 permit
94.236.119.0/26 permit
94.245.112.0/27 permit
94.245.112.10/31 permit
95.131.104.0/21 permit
@ -638,6 +684,7 @@
96.43.148.64/28 permit
96.43.148.64/31 permit
96.43.151.64/28 permit
98.97.248.0/21 permit
98.136.44.181 permit
98.136.44.182/31 permit
98.136.44.184 permit
@ -1142,23 +1189,21 @@
98.139.245.212/31 permit
99.78.197.208/28 permit
103.2.140.0/22 permit
103.9.8.121 permit
103.9.8.122 permit
103.9.8.123 permit
103.9.96.0/22 permit
103.13.69.0/24 permit
103.28.42.0/24 permit
103.47.204.0/22 permit
103.96.21.0/24 permit
103.96.22.0/24 permit
103.96.23.0/24 permit
103.151.192.0/23 permit
103.237.104.0/22 permit
103.168.172.128/27 permit
104.43.243.237 permit
104.44.112.128/25 permit
104.47.0.0/17 permit
104.130.96.0/28 permit
104.130.122.0/23 permit
104.214.25.77 permit
104.215.148.63 permit
104.215.186.3 permit
104.245.209.192/26 permit
106.10.144.64/27 permit
106.10.144.100/31 permit
@ -1320,6 +1365,8 @@
117.120.16.0/21 permit
119.42.242.52/31 permit
119.42.242.156 permit
121.244.91.48 permit
122.15.156.182 permit
123.126.78.64/29 permit
124.47.150.0/24 permit
124.47.189.0/24 permit
@ -1335,20 +1382,35 @@
128.127.70.0/26 permit
128.245.0.0/20 permit
128.245.64.0/20 permit
128.245.176.0/20 permit
128.245.242.0/24 permit
128.245.242.16 permit
128.245.242.17 permit
128.245.242.18 permit
128.245.243.0/24 permit
128.245.244.0/24 permit
128.245.245.0/24 permit
128.245.246.0/24 permit
128.245.247.0/24 permit
129.41.77.70 permit
129.41.169.249 permit
129.80.5.164 permit
129.80.67.121 permit
129.146.88.28 permit
129.146.147.105 permit
129.146.236.58 permit
129.151.67.221 permit
129.153.62.216 permit
129.153.104.71 permit
129.153.168.146 permit
129.153.190.200 permit
129.153.194.228 permit
129.159.87.137 permit
129.213.195.191 permit
130.61.9.72 permit
130.211.0.0/22 permit
130.248.172.0/24 permit
130.248.173.0/24 permit
131.107.0.0/16 permit
131.253.30.0/24 permit
131.253.121.0/26 permit
131.253.121.20 permit
131.253.121.52 permit
132.145.13.209 permit
132.226.26.225 permit
132.226.49.32 permit
@ -1358,9 +1420,13 @@
134.170.141.64/26 permit
134.170.143.0/24 permit
134.170.174.0/24 permit
135.84.80.192/26 permit
135.84.80.0/24 permit
135.84.81.0/24 permit
135.84.82.0/24 permit
135.84.83.0/24 permit
135.84.216.0/22 permit
136.143.160.0/24 permit
136.143.161.0/24 permit
136.143.182.0/23 permit
136.143.184.0/24 permit
136.143.188.0/24 permit
@ -1369,34 +1435,53 @@
136.147.176.0/20 permit
136.147.176.0/24 permit
136.147.182.0/24 permit
136.179.50.206 permit
138.91.172.26 permit
139.60.152.0/22 permit
139.178.64.159 permit
139.178.64.195 permit
139.138.35.44 permit
139.138.46.121 permit
139.138.46.176 permit
139.138.46.219 permit
139.138.57.55 permit
139.138.58.119 permit
139.180.17.0/24 permit
141.148.159.229 permit
141.193.32.0/23 permit
143.55.224.0/21 permit
143.55.232.0/22 permit
143.55.236.0/22 permit
143.244.80.0/20 permit
144.24.6.140 permit
144.34.8.247 permit
144.34.9.247 permit
144.34.32.247 permit
144.34.33.247 permit
144.178.36.0/24 permit
144.178.38.0/24 permit
145.253.228.160/29 permit
145.253.239.128/29 permit
146.20.112.0/26 permit
146.20.113.0/24 permit
146.20.191.0/24 permit
146.20.215.0/24 permit
146.20.215.182 permit
146.88.28.0/24 permit
146.101.78.0/24 permit
147.75.65.173 permit
147.75.65.174 permit
147.75.98.190 permit
147.28.36.0/24 permit
147.160.158.0/24 permit
147.243.1.47 permit
147.243.1.48 permit
147.243.1.153 permit
147.243.128.24 permit
147.243.128.26 permit
148.105.0.14 permit
148.105.0.0/16 permit
148.105.8.0/21 permit
149.72.0.0/16 permit
149.97.173.180 permit
150.230.98.160 permit
152.67.105.195 permit
152.69.200.236 permit
155.248.208.51 permit
157.55.0.192/26 permit
157.55.1.128/26 permit
157.55.2.0/25 permit
@ -1412,32 +1497,43 @@
157.56.232.0/21 permit
157.56.240.0/20 permit
157.56.248.0/21 permit
157.58.30.128/25 permit
157.58.196.96/29 permit
157.58.249.3 permit
157.151.208.65 permit
157.255.1.64/29 permit
158.101.211.207 permit
158.120.80.0/21 permit
158.247.16.0/20 permit
159.92.157.0/24 permit
159.92.157.16 permit
159.92.157.17 permit
159.92.157.18 permit
159.92.158.0/24 permit
159.92.159.0/24 permit
159.92.160.0/24 permit
159.92.161.0/24 permit
159.92.162.0/24 permit
159.112.240.0/20 permit
159.112.242.162 permit
159.135.132.128/25 permit
159.135.140.80/29 permit
159.135.224.0/20 permit
159.135.228.10 permit
159.183.0.0/16 permit
160.1.62.192 permit
161.38.192.0/20 permit
161.38.204.0/22 permit
161.71.32.0/19 permit
161.71.64.0/20 permit
162.208.119.181 permit
162.247.216.0/22 permit
163.47.180.0/22 permit
163.47.180.0/23 permit
163.114.130.16 permit
163.114.132.120 permit
165.173.128.0/24 permit
166.78.68.0/22 permit
166.78.68.221 permit
166.78.69.146 permit
166.78.69.169 permit
166.78.69.170 permit
166.78.71.131 permit
@ -1457,10 +1553,13 @@
167.216.129.210 permit
167.216.131.180 permit
167.220.67.232/29 permit
167.220.67.238 permit
168.138.5.36 permit
168.138.73.51 permit
168.245.0.0/17 permit
169.148.129.0/24 permit
169.148.131.0/24 permit
170.10.68.0/22 permit
170.10.128.0/24 permit
170.10.129.0/24 permit
170.10.133.0/24 permit
172.217.0.0/19 permit
@ -1475,10 +1574,8 @@
173.194.0.0/16 permit
173.203.79.182 permit
173.203.81.39 permit
173.224.160.128/25 permit
173.224.160.188 permit
173.224.161.128/25 permit
173.228.155.0/24 permit
173.224.165.0/26 permit
174.36.84.8/29 permit
174.36.84.16/29 permit
174.36.84.32/29 permit
@ -1491,6 +1588,7 @@
174.36.114.152/29 permit
174.37.67.28/30 permit
174.129.203.189 permit
175.41.215.51 permit
176.32.105.0/24 permit
176.32.127.0/24 permit
178.236.10.128/26 permit
@ -1498,8 +1596,9 @@
182.50.76.0/22 permit
182.50.78.64/28 permit
183.240.219.64/29 permit
185.4.120.0/23 permit
185.4.122.0/24 permit
185.12.80.0/22 permit
185.28.196.0/22 permit
185.58.84.93 permit
185.58.85.0/24 permit
185.58.86.0/24 permit
@ -1509,9 +1608,13 @@
185.80.93.204 permit
185.80.93.227 permit
185.80.95.31 permit
185.90.20.0/22 permit
185.189.236.0/22 permit
185.211.120.0/22 permit
185.250.236.0/22 permit
185.250.239.148 permit
185.250.239.168 permit
185.250.239.190 permit
188.125.68.132 permit
188.125.68.152/31 permit
188.125.68.156 permit
@ -1563,7 +1666,7 @@
188.125.85.238 permit
188.172.128.0/20 permit
192.0.64.0/18 permit
192.28.128.0/18 permit
192.18.139.154 permit
192.30.252.0/22 permit
192.64.236.0/24 permit
192.64.237.0/24 permit
@ -1579,16 +1682,21 @@
192.254.113.10 permit
192.254.113.101 permit
192.254.114.176 permit
192.254.118.63 permit
193.7.206.0/25 permit
193.7.207.0/25 permit
193.109.254.0/23 permit
193.122.128.100 permit
194.64.234.128/27 permit
194.64.234.129 permit
194.104.109.0/24 permit
194.104.110.21 permit
194.104.110.240/28 permit
194.104.111.0/24 permit
194.106.220.0/23 permit
194.113.24.0/22 permit
194.154.193.192/27 permit
195.4.92.0/23 permit
195.54.172.0/23 permit
195.130.217.0/24 permit
195.234.109.226 permit
195.245.230.0/23 permit
@ -1605,19 +1713,23 @@
198.37.144.0/20 permit
198.37.152.186 permit
198.61.254.0/23 permit
198.61.254.21 permit
198.61.254.231 permit
198.74.56.28 permit
198.178.234.57 permit
198.244.48.0/20 permit
198.244.60.0/22 permit
198.245.80.0/20 permit
198.245.81.0/24 permit
199.15.176.173 permit
199.15.212.0/22 permit
199.15.213.187 permit
199.15.226.37 permit
199.16.156.0/22 permit
199.33.145.1 permit
199.33.145.32 permit
199.59.148.0/22 permit
199.67.84.0/24 permit
199.67.86.0/24 permit
199.67.88.0/24 permit
199.101.161.130 permit
199.101.162.0/25 permit
199.122.120.0/21 permit
@ -1630,8 +1742,10 @@
202.177.148.110 permit
203.31.36.0/22 permit
203.32.4.25 permit
203.55.21.0/24 permit
203.81.17.0/24 permit
203.122.32.250 permit
203.145.57.160/27 permit
203.188.194.32 permit
203.188.194.151 permit
203.188.194.203 permit
@ -1666,28 +1780,31 @@
203.209.230.76/31 permit
204.11.168.0/21 permit
204.13.11.48/29 permit
204.13.11.48/30 permit
204.14.232.0/21 permit
204.14.232.64/28 permit
204.14.234.64/28 permit
204.29.186.0/23 permit
204.75.142.0/24 permit
204.79.197.212 permit
204.92.114.187 permit
204.92.114.203 permit
204.92.114.204/31 permit
204.141.32.0/23 permit
204.141.42.0/23 permit
204.153.121.0/24 permit
204.232.168.0/24 permit
205.139.110.0/24 permit
205.201.128.0/20 permit
205.201.131.128/25 permit
205.201.134.128/25 permit
205.201.136.0/23 permit
205.201.137.229 permit
205.201.139.0/24 permit
205.207.104.0/22 permit
205.207.104.108 permit
205.220.167.17 permit
205.220.167.98 permit
205.220.179.17 permit
205.220.179.98 permit
205.251.233.32 permit
205.251.233.36 permit
206.25.247.143 permit
@ -1723,6 +1840,7 @@
207.211.31.0/25 permit
207.211.41.113 permit
207.218.90.0/24 permit
207.218.90.122 permit
207.250.68.0/24 permit
208.40.232.70 permit
208.43.21.28/30 permit
@ -1758,8 +1876,10 @@
208.71.42.212/31 permit
208.71.42.214 permit
208.72.249.240/29 permit
208.74.204.0/22 permit
208.74.204.9 permit
208.75.120.0/22 permit
208.75.121.246 permit
208.75.122.246 permit
208.82.237.96/29 permit
208.82.237.104/31 permit
@ -1773,14 +1893,13 @@
209.46.117.168 permit
209.46.117.179 permit
209.61.151.0/24 permit
209.61.151.236 permit
209.61.151.249 permit
209.61.151.251 permit
209.67.98.46 permit
209.67.98.59 permit
209.85.128.0/17 permit
212.4.136.0/26 permit
212.25.240.80 permit
212.25.240.83 permit
212.25.240.84/31 permit
212.25.240.88 permit
212.82.96.0/24 permit
212.82.96.32/27 permit
212.82.96.64/29 permit
@ -1821,6 +1940,12 @@
212.82.111.228/31 permit
212.82.111.230 permit
212.123.28.40 permit
212.227.15.0/24 permit
212.227.15.0/25 permit
212.227.17.0/27 permit
212.227.126.128/25 permit
213.46.255.0/24 permit
213.165.64.0/23 permit
213.167.75.0/25 permit
213.167.81.0/25 permit
213.199.128.139 permit
@ -1861,6 +1986,10 @@
216.46.168.0/24 permit
216.58.192.0/19 permit
216.66.217.240/29 permit
216.71.138.33 permit
216.71.152.207 permit
216.71.154.29 permit
216.71.155.89 permit
216.74.162.13 permit
216.74.162.14 permit
216.82.240.0/20 permit
@ -1870,33 +1999,49 @@
216.109.114.0/24 permit
216.109.114.32/27 permit
216.109.114.64/29 permit
216.113.160.0/24 permit
216.113.172.0/25 permit
216.113.175.0/24 permit
216.128.126.97 permit
216.136.162.65 permit
216.136.162.120/29 permit
216.136.168.80/28 permit
216.145.217.0/24 permit
216.145.221.0/24 permit
216.198.0.0/18 permit
216.203.30.55 permit
216.203.33.178/31 permit
216.205.24.0/24 permit
216.239.32.0/19 permit
217.72.192.64/26 permit
217.72.192.248/29 permit
217.72.207.0/27 permit
217.77.141.52 permit
217.77.141.59 permit
217.175.194.0/24 permit
222.73.195.64/29 permit
223.165.113.0/24 permit
223.165.115.0/24 permit
223.165.118.0/23 permit
223.165.120.0/23 permit
2001:0868:0100:0600::/64 permit
2001:4860:4000::/36 permit
2001:748:100:40::2:0/112 permit
2404:6800:4000::/36 permit
2603:1010:3:3::5b permit
2603:1020:201:10::10f permit
2603:1030:20e:3::23c permit
2603:1030:b:3::152 permit
2603:1030:c02:8::14 permit
2607:f8b0:4000::/36 permit
2620:109:c003:104::215 permit
2620:109:c003:104::/64 permit
2620:109:c006:104::215 permit
2620:109:c003:104::215 permit
2620:109:c006:104::/64 permit
2620:109:c006:104::215 permit
2620:109:c00d:104::/64 permit
2620:10d:c090:450::120 permit
2620:10d:c091:450::16 permit
2620:119:50c0:207::215 permit
2620:10d:c091:400::8:1 permit
2620:119:50c0:207::/64 permit
2620:119:50c0:207::215 permit
2800:3f0:4000::/36 permit
194.25.134.0/24 permit # t-online.de

View File

@ -27,4 +27,5 @@
#197518 2 #Rackmarkt SL, Spain
#197695 2 #Domain names registrar REG.RU Ltd, Russia
#198068 2 #P.A.G.M. OU, Estonia
#201942 5 #Soltia Consulting SL, Spain
#201942 5 #Soltia Consulting SL, Spain
#213373 4 #IP Connect Inc

View File

@ -3,7 +3,6 @@
/.*episerver.*/i
/.*supergewinne.*/i
/List-Unsubscribe.*nbps\.eu/i
/X-Mailer: AWeber.*/i
/.*regiofinder.*/i
/.*EmailSocket.*/i
/List-Unsubscribe:.*respread.*/i

View File

@ -8,7 +8,7 @@ VIRUS_FOUND {
}
# Bad policy from free mail providers
FREEMAIL_POLICY_FAILURE {
expression = "-g+:policies & !DMARC_POLICY_ALLOW & !MAILLIST & ( FREEMAIL_ENVFROM | FREEMAIL_FROM ) & !WHITELISTED_FWD_HOST";
expression = "FREEMAIL_FROM & !DMARC_POLICY_ALLOW & !MAILLIST& !WHITELISTED_FWD_HOST & -g+:policies";
score = 16.0;
}
# Applies to freemail with undisclosed recipients
@ -68,3 +68,39 @@ WL_FWD_HOST {
ENCRYPTED_CHAT {
expression = "CHAT_VERSION_HEADER & ENCRYPTED_PGP";
}
CLAMD_SPAM_FOUND {
expression = "CLAM_SECI_SPAM & !MAILCOW_WHITE";
description = "Probably Spam, Securite Spam Flag set through ClamAV";
score = 5;
}
CLAMD_BAD_PDF {
expression = "CLAM_SECI_PDF & !MAILCOW_WHITE";
description = "Bad PDF Found, Securite bad PDF Flag set through ClamAV";
score = 8;
}
CLAMD_BAD_JPG {
expression = "CLAM_SECI_JPG & !MAILCOW_WHITE";
description = "Bad JPG Found, Securite bad JPG Flag set through ClamAV";
score = 8;
}
CLAMD_ASCII_MALWARE {
expression = "CLAM_SECI_ASCII & !MAILCOW_WHITE";
description = "ASCII malware found, Securite ASCII malware Flag set through ClamAV";
score = 8;
}
CLAMD_HTML_MALWARE {
expression = "CLAM_SECI_HTML & !MAILCOW_WHITE";
description = "HTML malware found, Securite HTML malware Flag set through ClamAV";
score = 8;
}
CLAMD_JS_MALWARE {
expression = "CLAM_SECI_JS & !MAILCOW_WHITE";
description = "JS malware found, Securite JS malware Flag set through ClamAV";
score = 8;
}

View File

@ -159,8 +159,8 @@ BAZAAR_ABUSE_CH {
}
URLHAUS_ABUSE_CH {
type = "url";
filter = "full";
type = "selector";
selector = "urls";
map = "https://urlhaus.abuse.ch/downloads/text_online/";
score = 10.0;
}
@ -175,7 +175,7 @@ BAD_SUBJECT_00 {
type = "header";
header = "subject";
regexp = true;
map = "http://nullnull.org/bad-subject-regex.txt";
map = "http://fuzzy.mailcow.email/bad-subject-regex.txt";
score = 6.0;
symbols_set = ["BAD_SUBJECT_00"];
}

View File

@ -340,6 +340,10 @@ rspamd_config:register_symbol({
if not bcc_dest then
return -- stop
end
-- dot stuff content before sending
local email_content = tostring(task:get_content())
email_content = string.gsub(email_content, "\r\n%.", "\r\n..")
-- send mail
lua_smtp.sendmail({
task = task,
host = os.getenv("IPV4_NETWORK") .. '.253',
@ -347,8 +351,8 @@ rspamd_config:register_symbol({
from = task:get_from(stp)[1].addr,
recipients = bcc_dest,
helo = 'bcc',
timeout = 10,
}, task:get_content(), sendmail_cb)
timeout = 20,
}, email_content, sendmail_cb)
end
-- determine from

View File

@ -54,6 +54,7 @@ $rcpts = $headers['X-Rspamd-Rcpt'];
$sender = $headers['X-Rspamd-From'];
$ip = $headers['X-Rspamd-Ip'];
$subject = $headers['X-Rspamd-Subject'];
$messageid= $json_body->message_id;
$priority = 0;
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
@ -245,13 +246,13 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
"token" => $api_data['token'],
"user" => $api_data['key'],
"title" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address), $title)
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title)
),
"priority" => $priority,
"message" => sprintf("%s", str_replace(
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '\n'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, PHP_EOL), $text)
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'),
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text)
),
"sound" => $attributes['sound'] ?? "pushover"
);

View File

@ -62,7 +62,7 @@
SOGoFirstDayOfWeek = "1";
SOGoSieveFolderEncoding = "UTF-8";
SOGoPasswordChangeEnabled = YES;
SOGoPasswordChangeEnabled = NO;
SOGoSentFolderName = "Sent";
SOGoMailShowSubscribedFoldersOnly = NO;
NGImap4ConnectionStringSeparator = "/";

View File

@ -13,12 +13,12 @@
Please check the logs or contact support if the error persists.</p>
<h2>Quick debugging</h2>
<p>Check Nginx and PHP logs:</p>
<pre>docker-compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre>
<pre>docker compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre>
<p>Make sure your SQL credentials in mailcow.conf (a link to .env) do fit your initialized SQL volume. If you see an access denied, you might have the wrong mailcow.conf:</p>
<pre>source mailcow.conf ; docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre>
<pre>source mailcow.conf ; docker compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre>
<p>In case of a previous failed installation, create a backup of your existing data, followed by removing all volumes and starting over (<b>NEVER</b> do this with a production system, it will remove <b>ALL</b> data):</p>
<pre>BACKUP_LOCATION=/tmp/ ./helper-scripts/backup_and_restore.sh backup all</pre>
<pre>docker-compose down --volumes ; docker-compose up -d</pre>
<pre>docker compose down --volumes ; docker compose up -d</pre>
<p>Make sure your timezone is correct. Use "America/New_York" for example, do not use spaces. Check <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">here</a> for a list.</p>
<br>Click to learn more about <a style="color:red;text-decoration:none;" href="https://mailcow.github.io/mailcow-dockerized-docs/#get-support" target="_blank">getting support.</a>
</body>

View File

@ -10,9 +10,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$tfa_data = get_tfa();
$fido2_data = fido2(array("action" => "get_friendly_names"));
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/admin.js');
$js_minifier->add('/web/js/presets/rspamd.js');
@ -83,6 +80,10 @@ foreach ($RSPAMD_MAPS['regex'] as $rspamd_regex_desc => $rspamd_regex_map) {
];
}
// cors settings
$cors_settings = cors('get');
$cors_settings['allowed_origins'] = str_replace(", ", "\n", $cors_settings['allowed_origins']);
$cors_settings['allowed_methods'] = explode(", ", $cors_settings['allowed_methods']);
$template = 'admin.twig';
$template_data = [
@ -90,8 +91,6 @@ $template_data = [
'tfa_id' => @$_SESSION['tfa_id'],
'fido2_cid' => @$_SESSION['fido2_cid'],
'fido2_data' => $fido2_data,
'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'),
'api' => [
'ro' => admin_api('ro', 'get'),
'rw' => admin_api('rw', 'get'),
@ -109,9 +108,12 @@ $template_data = [
'rsettings' => $rsettings,
'rspamd_regex_maps' => $rspamd_regex_maps,
'logo_specs' => customize('get', 'main_logo_specs'),
'ip_check' => customize('get', 'ip_check'),
'password_complexity' => password_complexity('get'),
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
'cors_settings' => $cors_settings,
'lang_admin' => json_encode($lang['admin']),
'lang_datatables' => json_encode($lang['datatables'])
];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';

View File

@ -1,4 +1,4 @@
openapi: 3.0.0
openapi: 3.1.0
info:
description: >-
mailcow is complete e-mailing solution with advanced antispam, antivirus,
@ -699,6 +699,38 @@ paths:
type: string
type: object
summary: Create Domain Admin user
/api/v1/add/sso/domain-admin:
post:
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
token: "591F6D-5C3DD2-7455CD-DAF1C1-AA4FCC"
description: OK
headers: { }
tags:
- Single Sign-On
description: >-
Using this endpoint you can issue a token for Domain Admin user. This token can be used for
autologin Domain Admin user by using query_string var sso_token={token}. Token expiration time is 30s
operationId: Issue Domain Admin SSO token
requestBody:
content:
application/json:
schema:
example:
username: testadmin
properties:
username:
description: the username for the admin user
type: object
type: object
summary: Issue Domain Admin SSO token
/api/v1/edit/da-acl:
post:
responses:
@ -1999,7 +2031,7 @@ paths:
- domain.tld
- domain2.tld
properties:
items:
items:
type: array
items:
type: string
@ -2993,7 +3025,7 @@ paths:
application/json:
schema:
type: array
items:
items:
type: object
properties:
log:
@ -3144,8 +3176,10 @@ paths:
example:
attr:
ban_time: "86400"
ban_time_increment: "1"
blacklist: "10.100.6.5/32,10.100.8.4/32"
max_attempts: "5"
max_ban_time: "86400"
netban_ipv4: "24"
netban_ipv6: "64"
retry_window: "600"
@ -3159,11 +3193,17 @@ paths:
description: the backlisted ips or hostnames separated by comma
type: string
ban_time:
description: the time a ip should be banned
description: the time an ip should be banned
type: number
ban_time_increment:
description: if the time of the ban should increase each time
type: boolean
max_attempts:
description: the maximum numbe of wrong logins before a ip is banned
type: number
max_ban_time:
description: the maximum time an ip should be banned
type: number
netban_ipv4:
description: the networks mask to ban for ipv4
type: number
@ -4081,10 +4121,12 @@ paths:
response:
value:
ban_time: 604800
ban_time_increment: 1
blacklist: |-
45.82.153.37/32
92.118.38.52/32
max_attempts: 1
max_ban_time: 604800
netban_ipv4: 32
netban_ipv6: 128
perm_bans:
@ -5560,6 +5602,50 @@ paths:
description: You can list all mailboxes existing in system for a specific domain.
operationId: Get mailboxes of a domain
summary: Get mailboxes of a domain
/api/v1/edit/cors:
post:
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
- type: "success"
log: ["cors", "edit", {"allowed_origins": ["*", "mail.mailcow.tld"], "allowed_methods": ["POST", "GET", "DELETE", "PUT"]}]
msg: "cors_headers_edited"
description: OK
headers: { }
tags:
- Cross-Origin Resource Sharing (CORS)
description: >-
This endpoint allows you to manage Cross-Origin Resource Sharing (CORS) settings for the API.
CORS is a security feature implemented by web browsers to prevent unauthorized cross-origin requests.
By editing the CORS settings, you can specify which domains and which methods are permitted to access the API resources from outside the mailcow domain.
operationId: Edit Cross-Origin Resource Sharing (CORS) settings
requestBody:
content:
application/json:
schema:
example:
attr:
allowed_origins: ["*", "mail.mailcow.tld"]
allowed_methods: ["POST", "GET", "DELETE", "PUT"]
properties:
attr:
type: object
properties:
allowed_origins:
type: array
items:
type: string
allowed_methods:
type: array
items:
type: string
summary: Edit Cross-Origin Resource Sharing (CORS) settings
tags:
- name: Domains
@ -5586,6 +5672,8 @@ tags:
description: Manage DKIM keys
- name: Domain admin
description: Create or udpdate domain admin users
- name: Single Sign-On
description: Issue tokens for users
- name: Address Rewriting
description: Create BCC maps or recipient maps
- name: Outgoing TLS Policy Map Overrides
@ -5602,3 +5690,5 @@ tags:
description: Get the status of your cow
- name: Ratelimits
description: Edit domain ratelimits
- name: Cross-Origin Resource Sharing (CORS)
description: Manage Cross-Origin Resource Sharing (CORS) settings

View File

@ -1,6 +1,6 @@
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
window.ui = SwaggerUIBundle({
urls: [{url: "/api/openapi.yaml", name: "mailcow API"}],
dom_id: '#swagger-ui',
deepLinking: true,
@ -15,5 +15,4 @@ window.onload = function() {
});
// End Swagger UI call region
window.ui = ui;
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-collapse.collapse{display:none!important}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}

View File

@ -0,0 +1,487 @@
/*!
* Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
*
* Copyright 2012-2021 SnapAppointments, LLC
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
*/
@-webkit-keyframes bs-notify-fadeOut {
0% {
opacity: 0.9;
}
100% {
opacity: 0;
}
}
@-o-keyframes bs-notify-fadeOut {
0% {
opacity: 0.9;
}
100% {
opacity: 0;
}
}
@keyframes bs-notify-fadeOut {
0% {
opacity: 0.9;
}
100% {
opacity: 0;
}
}
select.bs-select-hidden,
.bootstrap-select > select.bs-select-hidden,
select.selectpicker {
display: none !important;
}
.bootstrap-select {
width: 220px \0;
/*IE9 and below*/
vertical-align: middle;
}
.bootstrap-select > .dropdown-toggle {
position: relative;
width: 100%;
text-align: right;
white-space: nowrap;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}
.bootstrap-select > .dropdown-toggle:after {
margin-top: -1px;
}
.bootstrap-select > .dropdown-toggle.bs-placeholder,
.bootstrap-select > .dropdown-toggle.bs-placeholder:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder:active {
color: #999;
}
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:hover,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:focus,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:active {
color: rgba(255, 255, 255, 0.5);
}
.bootstrap-select > select {
position: absolute !important;
bottom: 0;
left: 50%;
display: block !important;
width: 0.5px !important;
height: 100% !important;
padding: 0 !important;
opacity: 0 !important;
border: none;
z-index: 0 !important;
}
.bootstrap-select > select.mobile-device {
top: 0;
left: 0;
display: block !important;
width: 100% !important;
z-index: 2 !important;
}
.has-error .bootstrap-select .dropdown-toggle,
.error .bootstrap-select .dropdown-toggle,
.bootstrap-select.is-invalid .dropdown-toggle,
.was-validated .bootstrap-select select:invalid + .dropdown-toggle {
border-color: #b94a48;
}
.bootstrap-select.is-valid .dropdown-toggle,
.was-validated .bootstrap-select select:valid + .dropdown-toggle {
border-color: #28a745;
}
.bootstrap-select.fit-width {
width: auto !important;
}
.bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) {
width: 220px;
}
.bootstrap-select > select.mobile-device:focus + .dropdown-toggle,
.bootstrap-select .dropdown-toggle:focus {
outline: thin dotted #333333 !important;
outline: 5px auto -webkit-focus-ring-color !important;
outline-offset: -2px;
}
.bootstrap-select.form-control {
margin-bottom: 0;
padding: 0;
border: none;
height: auto;
}
:not(.input-group) > .bootstrap-select.form-control:not([class*="col-"]) {
width: 100%;
}
.bootstrap-select.form-control.input-group-btn {
float: none;
z-index: auto;
}
.form-inline .bootstrap-select,
.form-inline .bootstrap-select.form-control:not([class*="col-"]) {
width: auto;
}
.bootstrap-select:not(.input-group-btn),
.bootstrap-select[class*="col-"] {
float: none;
display: inline-block;
margin-left: 0;
}
.bootstrap-select.dropdown-menu-right,
.bootstrap-select[class*="col-"].dropdown-menu-right,
.row .bootstrap-select[class*="col-"].dropdown-menu-right {
float: right;
}
.form-inline .bootstrap-select,
.form-horizontal .bootstrap-select,
.form-group .bootstrap-select {
margin-bottom: 0;
}
.form-group-lg .bootstrap-select.form-control,
.form-group-sm .bootstrap-select.form-control {
padding: 0;
}
.form-group-lg .bootstrap-select.form-control .dropdown-toggle,
.form-group-sm .bootstrap-select.form-control .dropdown-toggle {
height: 100%;
font-size: inherit;
line-height: inherit;
border-radius: inherit;
}
.bootstrap-select.form-control-sm .dropdown-toggle,
.bootstrap-select.form-control-lg .dropdown-toggle {
font-size: inherit;
line-height: inherit;
border-radius: inherit;
}
.bootstrap-select.form-control-sm .dropdown-toggle {
padding: 0.25rem 0.5rem;
}
.bootstrap-select.form-control-lg .dropdown-toggle {
padding: 0.5rem 1rem;
}
.form-inline .bootstrap-select .form-control {
width: 100%;
}
.bootstrap-select.disabled,
.bootstrap-select > .disabled {
cursor: not-allowed;
}
.bootstrap-select.disabled:focus,
.bootstrap-select > .disabled:focus {
outline: none !important;
}
.bootstrap-select.bs-container {
position: absolute;
top: 0;
left: 0;
height: 0 !important;
padding: 0 !important;
}
.bootstrap-select.bs-container .dropdown-menu {
z-index: 1060;
}
.bootstrap-select .dropdown-toggle .filter-option {
position: static;
top: 0;
left: 0;
float: left;
height: 100%;
width: 100%;
text-align: left;
overflow: hidden;
-webkit-box-flex: 0;
-webkit-flex: 0 1 auto;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
}
.bs3.bootstrap-select .dropdown-toggle .filter-option {
padding-right: inherit;
}
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option {
position: absolute;
padding-top: inherit;
padding-bottom: inherit;
padding-left: inherit;
float: none;
}
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner {
padding-right: inherit;
}
.bootstrap-select .dropdown-toggle .filter-option-inner-inner {
overflow: hidden;
}
.bootstrap-select .dropdown-toggle .filter-expand {
width: 0 !important;
float: left;
opacity: 0 !important;
overflow: hidden;
}
.bootstrap-select .dropdown-toggle .caret {
position: absolute;
top: 50%;
right: 12px;
margin-top: -2px;
vertical-align: middle;
}
.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
position: relative;
display: block;
margin-right: 5px;
text-align: center;
}
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
padding-right: inherit;
}
.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
position: relative;
top: -webkit-calc(((-1em / 1.5) + 1ex) / 2);
top: calc(((-1em / 1.5) + 1ex) / 2);
pointer-events: none;
}
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
top: auto;
}
.bootstrap-select .dropdown-toggle.bs-placeholder .bs-select-clear-selected {
display: none;
}
.input-group .bootstrap-select.form-control .dropdown-toggle {
border-radius: inherit;
}
.bootstrap-select[class*="col-"] .dropdown-toggle {
width: 100%;
}
.bootstrap-select .dropdown-menu {
min-width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bootstrap-select .dropdown-menu > .inner:focus {
outline: none !important;
}
.bootstrap-select .dropdown-menu.inner {
position: static;
float: none;
border: 0;
padding: 0;
margin: 0;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
.bootstrap-select .dropdown-menu li {
position: relative;
}
.bootstrap-select .dropdown-menu li.active small {
color: rgba(255, 255, 255, 0.5) !important;
}
.bootstrap-select .dropdown-menu li.disabled a {
cursor: not-allowed;
}
.bootstrap-select .dropdown-menu li a {
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.bootstrap-select .dropdown-menu li a.opt {
position: relative;
padding-left: 2.25em;
}
.bootstrap-select .dropdown-menu li a span.check-mark {
display: none;
}
.bootstrap-select .dropdown-menu li a span.text {
display: inline-block;
}
.bootstrap-select .dropdown-menu li small {
padding-left: 0.5em;
}
.bootstrap-select .dropdown-menu .notify {
position: absolute;
bottom: 5px;
width: 96%;
margin: 0 2%;
min-height: 26px;
padding: 3px 5px;
background: #f5f5f5;
border: 1px solid #e3e3e3;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
pointer-events: none;
opacity: 0.9;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bootstrap-select .dropdown-menu .notify.fadeOut {
-webkit-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
-o-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
animation: 300ms linear 750ms forwards bs-notify-fadeOut;
}
.bootstrap-select .no-results {
padding: 3px;
background: #f5f5f5;
margin: 0 5px;
white-space: nowrap;
}
.bootstrap-select.fit-width .dropdown-toggle .filter-option {
position: static;
display: inline;
padding: 0;
}
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner,
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner {
display: inline;
}
.bootstrap-select.fit-width .dropdown-toggle .bs-caret:before {
content: '\00a0';
}
.bootstrap-select.fit-width .dropdown-toggle .caret {
position: static;
top: auto;
margin-top: -1px;
}
.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark {
position: absolute;
display: inline-block;
right: 15px;
top: 5px;
}
.bootstrap-select.show-tick .dropdown-menu li a span.text {
margin-right: 34px;
}
.bootstrap-select .bs-ok-default:after {
content: '';
display: block;
width: 0.5em;
height: 1em;
border-style: solid;
border-width: 0 0.26em 0.26em 0;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle,
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle {
z-index: 1061;
}
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before {
content: '';
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid rgba(204, 204, 204, 0.2);
position: absolute;
bottom: -4px;
left: 9px;
display: none;
}
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after {
content: '';
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid white;
position: absolute;
bottom: -4px;
left: 10px;
display: none;
}
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before {
bottom: auto;
top: -4px;
border-top: 7px solid rgba(204, 204, 204, 0.2);
border-bottom: 0;
}
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after {
bottom: auto;
top: -4px;
border-top: 6px solid white;
border-bottom: 0;
}
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before {
right: 12px;
left: auto;
}
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after {
right: 13px;
left: auto;
}
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:before,
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:before,
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:after,
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:after {
display: block;
}
.bs-searchbox,
.bs-actionsbox,
.bs-donebutton {
padding: 4px 8px;
}
.bs-actionsbox {
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bs-actionsbox .btn-group {
display: block;
}
.bs-actionsbox .btn-group button {
width: 50%;
}
.bs-donebutton {
float: left;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bs-donebutton .btn-group {
display: block;
}
.bs-donebutton .btn-group button {
width: 100%;
}
.bs-searchbox + .bs-actionsbox {
padding: 0 8px 4px;
}
.bs-searchbox .form-control {
margin-bottom: 0;
width: 100%;
float: none;
}
/*# sourceMappingURL=bootstrap-select.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1,323 +0,0 @@
table.footable-details,
table.footable > thead > tr.footable-filtering > th div.form-group {
margin-bottom: 0;
}
table.footable,
table.footable-details {
position: relative;
width: 100%;
border-spacing: 0;
border-collapse: collapse;
}
table.footable-hide-fouc {
display: none;
}
table > tbody > tr > td > span.footable-toggle {
margin-right: 8px;
opacity: 0.3;
}
table > tbody > tr > td > span.footable-toggle.last-column {
margin-left: 8px;
float: right;
}
table.table-condensed > tbody > tr > td > span.footable-toggle {
margin-right: 5px;
}
table.footable-details > tbody > tr > th:nth-child(1) {
min-width: 40px;
width: 120px;
}
table.footable-details > tbody > tr > td:nth-child(2) {
word-break: break-all;
}
table.footable-details > tbody > tr:first-child > td,
table.footable-details > tbody > tr:first-child > th,
table.footable-details > tfoot > tr:first-child > td,
table.footable-details > tfoot > tr:first-child > th,
table.footable-details > thead > tr:first-child > td,
table.footable-details > thead > tr:first-child > th {
border-top-width: 0;
}
table.footable-details.table-bordered > tbody > tr:first-child > td,
table.footable-details.table-bordered > tbody > tr:first-child > th,
table.footable-details.table-bordered > tfoot > tr:first-child > td,
table.footable-details.table-bordered > tfoot > tr:first-child > th,
table.footable-details.table-bordered > thead > tr:first-child > td,
table.footable-details.table-bordered > thead > tr:first-child > th {
border-top-width: 1px;
}
div.footable-loader {
vertical-align: middle;
text-align: center;
height: 300px;
position: relative;
}
div.footable-loader > span.fooicon {
display: inline-block;
opacity: 0.3;
font-size: 30px;
line-height: 32px;
width: 32px;
height: 32px;
margin-top: -16px;
margin-left: -16px;
position: absolute;
top: 50%;
left: 50%;
-webkit-animation: fooicon-spin-r 2s infinite linear;
animation: fooicon-spin-r 2s infinite linear;
}
table.footable > tbody > tr.footable-empty > td {
vertical-align: middle;
text-align: center;
font-size: 30px;
}
table.footable > tbody > tr > td,
table.footable > tbody > tr > th {
display: none;
}
table.footable > tbody > tr.footable-detail-row > td,
table.footable > tbody > tr.footable-detail-row > th,
table.footable > tbody > tr.footable-empty > td,
table.footable > tbody > tr.footable-empty > th {
display: table-cell;
}
@-webkit-keyframes fooicon-spin-r {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fooicon-spin-r {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
.fooicon {
position: relative;
top: 0px;
display: inline-block;
font-family: "bootstrap-icons" !important;
font-style: normal;
font-weight: 400;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@-moz-document url-prefix() {
.fooicon {
top: 2px;
}
}
.fooicon:after,
.fooicon:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.fooicon-loader:before {
content: "\f130";
}
.fooicon-plus:before {
content: "\f4fd";
}
.fooicon-minus:before {
content: "\f2e9";
}
.fooicon-search:before {
content: "\f52a";
}
.fooicon-remove:before {
content: "\f62a";
}
.fooicon-sort:before {
content: "\f3c6";
}
.fooicon-sort-asc:before {
content: "\f575";
}
.fooicon-sort-desc:before {
content: "\f57b";
}
.fooicon-pencil:before {
content: "\f4c9";
}
.fooicon-trash:before {
content: "\f62a";
}
.fooicon-eye-close:before {
content: "\f33f";
}
.fooicon-flash:before {
content: "\f46e";
}
.fooicon-cog:before {
content: "\f3e2";
}
.fooicon-stats:before {
content: "\f359";
}
table.footable > thead > tr.footable-filtering > th {
border-bottom-width: 1px;
font-weight: 400;
}
.footable-filtering-external.footable-filtering-right,
table.footable.footable-filtering-right > thead > tr.footable-filtering > th,
table.footable > thead > tr.footable-filtering > th {
text-align: right;
}
.footable-filtering-external.footable-filtering-left,
table.footable.footable-filtering-left > thead > tr.footable-filtering > th {
text-align: left;
}
.footable-filtering-external.footable-filtering-center,
.footable-paging-external.footable-paging-center,
table.footable-paging-center > tfoot > tr.footable-paging > td,
table.footable.footable-filtering-center > thead > tr.footable-filtering > th,
table.footable > tfoot > tr.footable-paging > td {
text-align: center;
}
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
margin-top: 5px;
}
table.footable > thead > tr.footable-filtering > th div.input-group {
width: 100%;
}
.footable-filtering-external ul.dropdown-menu > li > a.checkbox,
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox {
margin: 0;
display: block;
position: relative;
}
.footable-filtering-external ul.dropdown-menu > li > a.checkbox > label,
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox > label {
display: block;
padding-left: 20px;
}
.footable-filtering-external ul.dropdown-menu > li > a.checkbox input[type="checkbox"],
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox input[type="checkbox"] {
position: absolute;
margin-left: -20px;
}
@media (min-width: 768px) {
table.footable > thead > tr.footable-filtering > th div.input-group {
width: auto;
}
table.footable > thead > tr.footable-filtering > th div.form-group {
margin-left: 2px;
margin-right: 2px;
}
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
margin-top: 0;
}
}
table.footable > tbody > tr > td.footable-sortable,
table.footable > tbody > tr > th.footable-sortable,
table.footable > tfoot > tr > td.footable-sortable,
table.footable > tfoot > tr > th.footable-sortable,
table.footable > thead > tr > td.footable-sortable,
table.footable > thead > tr > th.footable-sortable {
position: relative;
padding-right: 30px;
cursor: pointer;
}
td.footable-sortable > span.fooicon,
th.footable-sortable > span.fooicon {
position: absolute;
right: 6px;
top: 50%;
margin-top: -7px;
opacity: 0;
transition: opacity 0.3s ease-in;
}
td.footable-sortable.footable-asc > span.fooicon,
td.footable-sortable.footable-desc > span.fooicon,
td.footable-sortable:hover > span.fooicon,
th.footable-sortable.footable-asc > span.fooicon,
th.footable-sortable.footable-desc > span.fooicon,
th.footable-sortable:hover > span.fooicon {
opacity: 1;
}
table.footable-sorting-disabled td.footable-sortable.footable-asc > span.fooicon,
table.footable-sorting-disabled td.footable-sortable.footable-desc > span.fooicon,
table.footable-sorting-disabled td.footable-sortable:hover > span.fooicon,
table.footable-sorting-disabled th.footable-sortable.footable-asc > span.fooicon,
table.footable-sorting-disabled th.footable-sortable.footable-desc > span.fooicon,
table.footable-sorting-disabled th.footable-sortable:hover > span.fooicon {
opacity: 0;
visibility: hidden;
}
.footable-paging-external ul.pagination,
table.footable > tfoot > tr.footable-paging > td > ul.pagination {
margin: 10px 0 0;
}
.footable-paging-external span.label,
table.footable > tfoot > tr.footable-paging > td > span.label {
display: inline-block;
margin: 0 0 10px;
padding: 4px 10px;
}
.footable-paging-external.footable-paging-left,
table.footable-paging-left > tfoot > tr.footable-paging > td {
text-align: left;
}
.footable-paging-external.footable-paging-right,
table.footable-editing-right td.footable-editing,
table.footable-editing-right tr.footable-editing,
table.footable-paging-right > tfoot > tr.footable-paging > td {
text-align: right;
}
ul.pagination > li.footable-page {
display: none;
}
ul.pagination > li.footable-page.visible {
display: inline;
}
td.footable-editing {
width: 90px;
max-width: 90px;
}
table.footable-editing-no-delete td.footable-editing,
table.footable-editing-no-edit td.footable-editing,
table.footable-editing-no-view td.footable-editing {
width: 70px;
max-width: 70px;
}
table.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
table.footable-editing-no-edit.footable-editing-no-delete td.footable-editing,
table.footable-editing-no-edit.footable-editing-no-view td.footable-editing {
width: 50px;
max-width: 50px;
}
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view th.footable-editing {
width: 0;
max-width: 0;
display: none !important;
}
table.footable-editing-left td.footable-editing,
table.footable-editing-left tr.footable-editing {
text-align: left;
}
table.footable-editing button.footable-add,
table.footable-editing button.footable-hide,
table.footable-editing-show button.footable-show,
table.footable-editing.footable-editing-always-show button.footable-hide,
table.footable-editing.footable-editing-always-show button.footable-show,
table.footable-editing.footable-editing-always-show.footable-editing-no-add tr.footable-editing {
display: none;
}
table.footable-editing.footable-editing-always-show button.footable-add,
table.footable-editing.footable-editing-show button.footable-add,
table.footable-editing.footable-editing-show button.footable-hide {
display: inline-block;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,691 @@
/*
* This combined file was created by the DataTables downloader builder:
* https://datatables.net/download
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#bs5/dt-1.13.1/r-2.4.0/sl-1.5.0
*
* Included libraries:
* DataTables 1.13.1, Responsive 2.4.0, Select 1.5.0
*/
@charset "UTF-8";
table.dataTable td.dt-control {
text-align: center;
cursor: pointer;
}
table.dataTable td.dt-control:before {
height: 1em;
width: 1em;
margin-top: -9px;
display: inline-block;
color: white;
border: 0.15em solid white;
border-radius: 1em;
box-shadow: 0 0 0.2em #444;
box-sizing: content-box;
text-align: center;
text-indent: 0 !important;
font-family: "Courier New", Courier, monospace;
line-height: 1em;
content: "+";
background-color: #31b131;
}
table.dataTable tr.dt-hasChild td.dt-control:before {
content: "-";
background-color: #d33333;
}
table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
table.dataTable thead > tr > td.sorting,
table.dataTable thead > tr > td.sorting_asc,
table.dataTable thead > tr > td.sorting_desc,
table.dataTable thead > tr > td.sorting_asc_disabled,
table.dataTable thead > tr > td.sorting_desc_disabled {
cursor: pointer;
position: relative;
padding-right: 26px;
}
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:after,
table.dataTable thead > tr > td.sorting:before,
table.dataTable thead > tr > td.sorting:after,
table.dataTable thead > tr > td.sorting_asc:before,
table.dataTable thead > tr > td.sorting_asc:after,
table.dataTable thead > tr > td.sorting_desc:before,
table.dataTable thead > tr > td.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc_disabled:before,
table.dataTable thead > tr > td.sorting_asc_disabled:after,
table.dataTable thead > tr > td.sorting_desc_disabled:before,
table.dataTable thead > tr > td.sorting_desc_disabled:after {
position: absolute;
display: block;
opacity: 0.125;
right: 10px;
line-height: 9px;
font-size: 0.8em;
}
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
table.dataTable thead > tr > td.sorting:before,
table.dataTable thead > tr > td.sorting_asc:before,
table.dataTable thead > tr > td.sorting_desc:before,
table.dataTable thead > tr > td.sorting_asc_disabled:before,
table.dataTable thead > tr > td.sorting_desc_disabled:before {
bottom: 50%;
content: "▲";
}
table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
table.dataTable thead > tr > td.sorting:after,
table.dataTable thead > tr > td.sorting_asc:after,
table.dataTable thead > tr > td.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc_disabled:after,
table.dataTable thead > tr > td.sorting_desc_disabled:after {
top: 50%;
content: "▼";
}
table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc:before,
table.dataTable thead > tr > td.sorting_desc:after {
opacity: 0.6;
}
table.dataTable thead > tr > th.sorting_desc_disabled:after, table.dataTable thead > tr > th.sorting_asc_disabled:before,
table.dataTable thead > tr > td.sorting_desc_disabled:after,
table.dataTable thead > tr > td.sorting_asc_disabled:before {
display: none;
}
table.dataTable thead > tr > th:active,
table.dataTable thead > tr > td:active {
outline: none;
}
div.dataTables_scrollBody table.dataTable thead > tr > th:before, div.dataTables_scrollBody table.dataTable thead > tr > th:after,
div.dataTables_scrollBody table.dataTable thead > tr > td:before,
div.dataTables_scrollBody table.dataTable thead > tr > td:after {
display: none;
}
div.dataTables_processing {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
margin-left: -100px;
margin-top: -26px;
text-align: center;
padding: 2px;
}
div.dataTables_processing > div:last-child {
position: relative;
width: 80px;
height: 15px;
margin: 1em auto;
}
div.dataTables_processing > div:last-child > div {
position: absolute;
top: 0;
width: 13px;
height: 13px;
border-radius: 50%;
background: rgba(13, 110, 253, 0.9);
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
div.dataTables_processing > div:last-child > div:nth-child(1) {
left: 8px;
animation: datatables-loader-1 0.6s infinite;
}
div.dataTables_processing > div:last-child > div:nth-child(2) {
left: 8px;
animation: datatables-loader-2 0.6s infinite;
}
div.dataTables_processing > div:last-child > div:nth-child(3) {
left: 32px;
animation: datatables-loader-2 0.6s infinite;
}
div.dataTables_processing > div:last-child > div:nth-child(4) {
left: 56px;
animation: datatables-loader-3 0.6s infinite;
}
@keyframes datatables-loader-1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes datatables-loader-3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes datatables-loader-2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(24px, 0);
}
}
table.dataTable.nowrap th, table.dataTable.nowrap td {
white-space: nowrap;
}
table.dataTable th.dt-left,
table.dataTable td.dt-left {
text-align: left;
}
table.dataTable th.dt-center,
table.dataTable td.dt-center,
table.dataTable td.dataTables_empty {
text-align: center;
}
table.dataTable th.dt-right,
table.dataTable td.dt-right {
text-align: right;
}
table.dataTable th.dt-justify,
table.dataTable td.dt-justify {
text-align: justify;
}
table.dataTable th.dt-nowrap,
table.dataTable td.dt-nowrap {
white-space: nowrap;
}
table.dataTable thead th,
table.dataTable thead td,
table.dataTable tfoot th,
table.dataTable tfoot td {
text-align: left;
}
table.dataTable thead th.dt-head-left,
table.dataTable thead td.dt-head-left,
table.dataTable tfoot th.dt-head-left,
table.dataTable tfoot td.dt-head-left {
text-align: left;
}
table.dataTable thead th.dt-head-center,
table.dataTable thead td.dt-head-center,
table.dataTable tfoot th.dt-head-center,
table.dataTable tfoot td.dt-head-center {
text-align: center;
}
table.dataTable thead th.dt-head-right,
table.dataTable thead td.dt-head-right,
table.dataTable tfoot th.dt-head-right,
table.dataTable tfoot td.dt-head-right {
text-align: right;
}
table.dataTable thead th.dt-head-justify,
table.dataTable thead td.dt-head-justify,
table.dataTable tfoot th.dt-head-justify,
table.dataTable tfoot td.dt-head-justify {
text-align: justify;
}
table.dataTable thead th.dt-head-nowrap,
table.dataTable thead td.dt-head-nowrap,
table.dataTable tfoot th.dt-head-nowrap,
table.dataTable tfoot td.dt-head-nowrap {
white-space: nowrap;
}
table.dataTable tbody th.dt-body-left,
table.dataTable tbody td.dt-body-left {
text-align: left;
}
table.dataTable tbody th.dt-body-center,
table.dataTable tbody td.dt-body-center {
text-align: center;
}
table.dataTable tbody th.dt-body-right,
table.dataTable tbody td.dt-body-right {
text-align: right;
}
table.dataTable tbody th.dt-body-justify,
table.dataTable tbody td.dt-body-justify {
text-align: justify;
}
table.dataTable tbody th.dt-body-nowrap,
table.dataTable tbody td.dt-body-nowrap {
white-space: nowrap;
}
/*! Bootstrap 5 integration for DataTables
*
* ©2020 SpryMedia Ltd, all rights reserved.
* License: MIT datatables.net/license/mit
*/
table.dataTable {
clear: both;
margin-top: 6px !important;
margin-bottom: 6px !important;
max-width: none !important;
border-collapse: separate !important;
border-spacing: 0;
}
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
table.dataTable td.dataTables_empty,
table.dataTable th.dataTables_empty {
text-align: center;
}
table.dataTable.nowrap th,
table.dataTable.nowrap td {
white-space: nowrap;
}
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
box-shadow: none;
}
table.dataTable > tbody > tr {
background-color: transparent;
}
table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
color: white;
}
table.dataTable > tbody > tr.selected a {
color: #090a0b;
}
table.dataTable.table-striped > tbody > tr.odd > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
}
table.dataTable.table-striped > tbody > tr.odd.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
}
table.dataTable.table-hover > tbody > tr:hover > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.075);
}
table.dataTable.table-hover > tbody > tr.selected:hover > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
}
div.dataTables_wrapper div.dataTables_length label {
font-weight: normal;
text-align: left;
white-space: nowrap;
}
div.dataTables_wrapper div.dataTables_length select {
width: auto;
display: inline-block;
}
div.dataTables_wrapper div.dataTables_filter {
text-align: right;
}
div.dataTables_wrapper div.dataTables_filter label {
font-weight: normal;
white-space: nowrap;
text-align: left;
}
div.dataTables_wrapper div.dataTables_filter input {
margin-left: 0.5em;
display: inline-block;
width: auto;
}
div.dataTables_wrapper div.dataTables_info {
padding-top: 0.85em;
}
div.dataTables_wrapper div.dataTables_paginate {
margin: 0;
white-space: nowrap;
text-align: right;
}
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
margin: 2px 0;
white-space: nowrap;
justify-content: flex-end;
}
div.dataTables_wrapper div.dt-row {
position: relative;
}
div.dataTables_wrapper span.sorting-value {
display: none;
}
div.dataTables_scrollHead table.dataTable {
margin-bottom: 0 !important;
}
div.dataTables_scrollBody > table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
div.dataTables_scrollBody > table > thead .sorting:before,
div.dataTables_scrollBody > table > thead .sorting_asc:before,
div.dataTables_scrollBody > table > thead .sorting_desc:before,
div.dataTables_scrollBody > table > thead .sorting:after,
div.dataTables_scrollBody > table > thead .sorting_asc:after,
div.dataTables_scrollBody > table > thead .sorting_desc:after {
display: none;
}
div.dataTables_scrollBody > table > tbody tr:first-child th,
div.dataTables_scrollBody > table > tbody tr:first-child td {
border-top: none;
}
div.dataTables_scrollFoot > .dataTables_scrollFootInner {
box-sizing: content-box;
}
div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
margin-top: 0 !important;
border-top: none;
}
@media screen and (max-width: 767px) {
div.dataTables_wrapper div.dataTables_length,
div.dataTables_wrapper div.dataTables_filter,
div.dataTables_wrapper div.dataTables_info,
div.dataTables_wrapper div.dataTables_paginate {
text-align: center;
}
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
justify-content: center !important;
}
}
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
padding-right: 20px;
}
table.table-bordered.dataTable {
border-right-width: 0;
}
table.table-bordered.dataTable thead tr:first-child th,
table.table-bordered.dataTable thead tr:first-child td {
border-top-width: 1px;
}
table.table-bordered.dataTable th,
table.table-bordered.dataTable td {
border-left-width: 0;
}
table.table-bordered.dataTable th:first-child, table.table-bordered.dataTable th:first-child,
table.table-bordered.dataTable td:first-child,
table.table-bordered.dataTable td:first-child {
border-left-width: 1px;
}
table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,
table.table-bordered.dataTable td:last-child,
table.table-bordered.dataTable td:last-child {
border-right-width: 1px;
}
table.table-bordered.dataTable th,
table.table-bordered.dataTable td {
border-bottom-width: 1px;
}
div.dataTables_scrollHead table.table-bordered {
border-bottom-width: 0;
}
div.table-responsive > div.dataTables_wrapper > div.row {
margin: 0;
}
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:first-child {
padding-left: 0;
}
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-child {
padding-right: 0;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
cursor: default !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
display: none !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control {
position: relative;
padding-left: 30px;
cursor: pointer;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before {
top: 50%;
left: 5px;
height: 1em;
width: 1em;
margin-top: -9px;
display: block;
position: absolute;
color: white;
border: 0.15em solid white;
border-radius: 1em;
box-shadow: 0 0 0.2em #444;
box-sizing: content-box;
text-align: center;
text-indent: 0 !important;
font-family: "Courier New", Courier, monospace;
line-height: 1em;
content: "+";
background-color: #0d6efd;
}
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th.dtr-control:before {
content: "-";
background-color: #d33333;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control {
padding-left: 27px;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control:before {
left: 4px;
height: 14px;
width: 14px;
border-radius: 14px;
line-height: 14px;
text-indent: 3px;
}
table.dataTable.dtr-column > tbody > tr > td.dtr-control,
table.dataTable.dtr-column > tbody > tr > th.dtr-control,
table.dataTable.dtr-column > tbody > tr > td.control,
table.dataTable.dtr-column > tbody > tr > th.control {
position: relative;
cursor: pointer;
}
table.dataTable.dtr-column > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-column > tbody > tr > th.dtr-control:before,
table.dataTable.dtr-column > tbody > tr > td.control:before,
table.dataTable.dtr-column > tbody > tr > th.control:before {
top: 50%;
left: 50%;
height: 0.8em;
width: 0.8em;
margin-top: -0.5em;
margin-left: -0.5em;
display: block;
position: absolute;
color: white;
border: 0.15em solid white;
border-radius: 1em;
box-shadow: 0 0 0.2em #444;
box-sizing: content-box;
text-align: center;
text-indent: 0 !important;
font-family: "Courier New", Courier, monospace;
line-height: 1em;
content: "+";
background-color: #0d6efd;
}
table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
content: "-";
background-color: #d33333;
}
table.dataTable > tbody > tr.child {
padding: 0.5em 1em;
}
table.dataTable > tbody > tr.child:hover {
background: transparent !important;
}
table.dataTable > tbody > tr.child ul.dtr-details {
display: inline-block;
list-style-type: none;
margin: 0;
padding: 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li {
border-bottom: 1px solid #efefef;
padding: 0.5em 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
padding-top: 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
border-bottom: none;
}
table.dataTable > tbody > tr.child span.dtr-title {
display: inline-block;
min-width: 75px;
font-weight: bold;
}
div.dtr-modal {
position: fixed;
box-sizing: border-box;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 100;
padding: 10em 1em;
}
div.dtr-modal div.dtr-modal-display {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 50%;
height: 50%;
overflow: auto;
margin: auto;
z-index: 102;
overflow: auto;
background-color: #f5f5f7;
border: 1px solid black;
border-radius: 0.5em;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
}
div.dtr-modal div.dtr-modal-content {
position: relative;
padding: 1em;
}
div.dtr-modal div.dtr-modal-close {
position: absolute;
top: 6px;
right: 6px;
width: 22px;
height: 22px;
border: 1px solid #eaeaea;
background-color: #f9f9f9;
text-align: center;
border-radius: 3px;
cursor: pointer;
z-index: 12;
}
div.dtr-modal div.dtr-modal-close:hover {
background-color: #eaeaea;
}
div.dtr-modal div.dtr-modal-background {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 101;
background: rgba(0, 0, 0, 0.6);
}
@media screen and (max-width: 767px) {
div.dtr-modal div.dtr-modal-display {
width: 95%;
}
}
div.dtr-bs-modal table.table tr:first-child td {
border-top: none;
}
table.dataTable.table-bordered th.dtr-control.dtr-hidden + *,
table.dataTable.table-bordered td.dtr-control.dtr-hidden + * {
border-left-width: 1px;
}
table.dataTable > tbody > tr > .selected {
background-color: rgba(13, 110, 253, 0.9);
color: white;
}
table.dataTable > tbody > tr > td.select-checkbox,
table.dataTable > tbody > tr > th.select-checkbox {
position: relative;
}
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after,
table.dataTable > tbody > tr > th.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:after {
display: block;
position: absolute;
top: 1.2em;
left: 50%;
width: 12px;
height: 12px;
box-sizing: border-box;
}
table.dataTable > tbody > tr > td.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:before {
content: " ";
margin-top: -5px;
margin-left: -6px;
border: 1px solid black;
border-radius: 3px;
}
table.dataTable > tbody > tr.selected > td.select-checkbox:before,
table.dataTable > tbody > tr.selected > th.select-checkbox:before {
border: 1px solid white;
}
table.dataTable > tbody > tr.selected > td.select-checkbox:after,
table.dataTable > tbody > tr.selected > th.select-checkbox:after {
content: "✓";
font-size: 20px;
margin-top: -19px;
margin-left: -6px;
text-align: center;
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
}
table.dataTable.compact > tbody > tr > td.select-checkbox:before,
table.dataTable.compact > tbody > tr > th.select-checkbox:before {
margin-top: -12px;
}
table.dataTable.compact > tbody > tr.selected > td.select-checkbox:after,
table.dataTable.compact > tbody > tr.selected > th.select-checkbox:after {
margin-top: -16px;
}
div.dataTables_wrapper span.select-info,
div.dataTables_wrapper span.select-item {
margin-left: 0.5em;
}
@media screen and (max-width: 640px) {
div.dataTables_wrapper span.select-info,
div.dataTables_wrapper span.select-item {
margin-left: 0;
display: block;
}
}
table.dataTable.table-sm tbody td.select-checkbox::before {
margin-top: -9px;
}

View File

@ -1 +0,0 @@
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}

View File

@ -1,7 +1,7 @@
@font-face {
font-family: "bootstrap-icons";
src: url("/fonts/bootstrap-icons.woff2?45695e8b569b2b0178db2713ca47065c") format("woff2"),
url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff");
src: url("/fonts/bootstrap-icons.woff2?524846017b983fc8ded9325d94ed40f3") format("woff2"),
url("/fonts/bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff");
}
.bi::before,
@ -19,6 +19,7 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
-moz-osx-font-smoothing: grayscale;
}
.bi-123::before { content: "\f67f"; }
.bi-alarm-fill::before { content: "\f101"; }
.bi-alarm::before { content: "\f102"; }
.bi-align-bottom::before { content: "\f103"; }
@ -1425,3 +1426,279 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
.bi-webcam-fill::before { content: "\f67c"; }
.bi-webcam::before { content: "\f67d"; }
.bi-yin-yang::before { content: "\f67e"; }
.bi-bandaid-fill::before { content: "\f680"; }
.bi-bandaid::before { content: "\f681"; }
.bi-bluetooth::before { content: "\f682"; }
.bi-body-text::before { content: "\f683"; }
.bi-boombox::before { content: "\f684"; }
.bi-boxes::before { content: "\f685"; }
.bi-dpad-fill::before { content: "\f686"; }
.bi-dpad::before { content: "\f687"; }
.bi-ear-fill::before { content: "\f688"; }
.bi-ear::before { content: "\f689"; }
.bi-envelope-check-1::before { content: "\f68a"; }
.bi-envelope-check-fill::before { content: "\f68b"; }
.bi-envelope-check::before { content: "\f68c"; }
.bi-envelope-dash-1::before { content: "\f68d"; }
.bi-envelope-dash-fill::before { content: "\f68e"; }
.bi-envelope-dash::before { content: "\f68f"; }
.bi-envelope-exclamation-1::before { content: "\f690"; }
.bi-envelope-exclamation-fill::before { content: "\f691"; }
.bi-envelope-exclamation::before { content: "\f692"; }
.bi-envelope-plus-fill::before { content: "\f693"; }
.bi-envelope-plus::before { content: "\f694"; }
.bi-envelope-slash-1::before { content: "\f695"; }
.bi-envelope-slash-fill::before { content: "\f696"; }
.bi-envelope-slash::before { content: "\f697"; }
.bi-envelope-x-1::before { content: "\f698"; }
.bi-envelope-x-fill::before { content: "\f699"; }
.bi-envelope-x::before { content: "\f69a"; }
.bi-explicit-fill::before { content: "\f69b"; }
.bi-explicit::before { content: "\f69c"; }
.bi-git::before { content: "\f69d"; }
.bi-infinity::before { content: "\f69e"; }
.bi-list-columns-reverse::before { content: "\f69f"; }
.bi-list-columns::before { content: "\f6a0"; }
.bi-meta::before { content: "\f6a1"; }
.bi-mortorboard-fill::before { content: "\f6a2"; }
.bi-mortorboard::before { content: "\f6a3"; }
.bi-nintendo-switch::before { content: "\f6a4"; }
.bi-pc-display-horizontal::before { content: "\f6a5"; }
.bi-pc-display::before { content: "\f6a6"; }
.bi-pc-horizontal::before { content: "\f6a7"; }
.bi-pc::before { content: "\f6a8"; }
.bi-playstation::before { content: "\f6a9"; }
.bi-plus-slash-minus::before { content: "\f6aa"; }
.bi-projector-fill::before { content: "\f6ab"; }
.bi-projector::before { content: "\f6ac"; }
.bi-qr-code-scan::before { content: "\f6ad"; }
.bi-qr-code::before { content: "\f6ae"; }
.bi-quora::before { content: "\f6af"; }
.bi-quote::before { content: "\f6b0"; }
.bi-robot::before { content: "\f6b1"; }
.bi-send-check-fill::before { content: "\f6b2"; }
.bi-send-check::before { content: "\f6b3"; }
.bi-send-dash-fill::before { content: "\f6b4"; }
.bi-send-dash::before { content: "\f6b5"; }
.bi-send-exclamation-1::before { content: "\f6b6"; }
.bi-send-exclamation-fill::before { content: "\f6b7"; }
.bi-send-exclamation::before { content: "\f6b8"; }
.bi-send-fill::before { content: "\f6b9"; }
.bi-send-plus-fill::before { content: "\f6ba"; }
.bi-send-plus::before { content: "\f6bb"; }
.bi-send-slash-fill::before { content: "\f6bc"; }
.bi-send-slash::before { content: "\f6bd"; }
.bi-send-x-fill::before { content: "\f6be"; }
.bi-send-x::before { content: "\f6bf"; }
.bi-send::before { content: "\f6c0"; }
.bi-steam::before { content: "\f6c1"; }
.bi-terminal-dash-1::before { content: "\f6c2"; }
.bi-terminal-dash::before { content: "\f6c3"; }
.bi-terminal-plus::before { content: "\f6c4"; }
.bi-terminal-split::before { content: "\f6c5"; }
.bi-ticket-detailed-fill::before { content: "\f6c6"; }
.bi-ticket-detailed::before { content: "\f6c7"; }
.bi-ticket-fill::before { content: "\f6c8"; }
.bi-ticket-perforated-fill::before { content: "\f6c9"; }
.bi-ticket-perforated::before { content: "\f6ca"; }
.bi-ticket::before { content: "\f6cb"; }
.bi-tiktok::before { content: "\f6cc"; }
.bi-window-dash::before { content: "\f6cd"; }
.bi-window-desktop::before { content: "\f6ce"; }
.bi-window-fullscreen::before { content: "\f6cf"; }
.bi-window-plus::before { content: "\f6d0"; }
.bi-window-split::before { content: "\f6d1"; }
.bi-window-stack::before { content: "\f6d2"; }
.bi-window-x::before { content: "\f6d3"; }
.bi-xbox::before { content: "\f6d4"; }
.bi-ethernet::before { content: "\f6d5"; }
.bi-hdmi-fill::before { content: "\f6d6"; }
.bi-hdmi::before { content: "\f6d7"; }
.bi-usb-c-fill::before { content: "\f6d8"; }
.bi-usb-c::before { content: "\f6d9"; }
.bi-usb-fill::before { content: "\f6da"; }
.bi-usb-plug-fill::before { content: "\f6db"; }
.bi-usb-plug::before { content: "\f6dc"; }
.bi-usb-symbol::before { content: "\f6dd"; }
.bi-usb::before { content: "\f6de"; }
.bi-boombox-fill::before { content: "\f6df"; }
.bi-displayport-1::before { content: "\f6e0"; }
.bi-displayport::before { content: "\f6e1"; }
.bi-gpu-card::before { content: "\f6e2"; }
.bi-memory::before { content: "\f6e3"; }
.bi-modem-fill::before { content: "\f6e4"; }
.bi-modem::before { content: "\f6e5"; }
.bi-motherboard-fill::before { content: "\f6e6"; }
.bi-motherboard::before { content: "\f6e7"; }
.bi-optical-audio-fill::before { content: "\f6e8"; }
.bi-optical-audio::before { content: "\f6e9"; }
.bi-pci-card::before { content: "\f6ea"; }
.bi-router-fill::before { content: "\f6eb"; }
.bi-router::before { content: "\f6ec"; }
.bi-ssd-fill::before { content: "\f6ed"; }
.bi-ssd::before { content: "\f6ee"; }
.bi-thunderbolt-fill::before { content: "\f6ef"; }
.bi-thunderbolt::before { content: "\f6f0"; }
.bi-usb-drive-fill::before { content: "\f6f1"; }
.bi-usb-drive::before { content: "\f6f2"; }
.bi-usb-micro-fill::before { content: "\f6f3"; }
.bi-usb-micro::before { content: "\f6f4"; }
.bi-usb-mini-fill::before { content: "\f6f5"; }
.bi-usb-mini::before { content: "\f6f6"; }
.bi-cloud-haze2::before { content: "\f6f7"; }
.bi-device-hdd-fill::before { content: "\f6f8"; }
.bi-device-hdd::before { content: "\f6f9"; }
.bi-device-ssd-fill::before { content: "\f6fa"; }
.bi-device-ssd::before { content: "\f6fb"; }
.bi-displayport-fill::before { content: "\f6fc"; }
.bi-mortarboard-fill::before { content: "\f6fd"; }
.bi-mortarboard::before { content: "\f6fe"; }
.bi-terminal-x::before { content: "\f6ff"; }
.bi-arrow-through-heart-fill::before { content: "\f700"; }
.bi-arrow-through-heart::before { content: "\f701"; }
.bi-badge-sd-fill::before { content: "\f702"; }
.bi-badge-sd::before { content: "\f703"; }
.bi-bag-heart-fill::before { content: "\f704"; }
.bi-bag-heart::before { content: "\f705"; }
.bi-balloon-fill::before { content: "\f706"; }
.bi-balloon-heart-fill::before { content: "\f707"; }
.bi-balloon-heart::before { content: "\f708"; }
.bi-balloon::before { content: "\f709"; }
.bi-box2-fill::before { content: "\f70a"; }
.bi-box2-heart-fill::before { content: "\f70b"; }
.bi-box2-heart::before { content: "\f70c"; }
.bi-box2::before { content: "\f70d"; }
.bi-braces-asterisk::before { content: "\f70e"; }
.bi-calendar-heart-fill::before { content: "\f70f"; }
.bi-calendar-heart::before { content: "\f710"; }
.bi-calendar2-heart-fill::before { content: "\f711"; }
.bi-calendar2-heart::before { content: "\f712"; }
.bi-chat-heart-fill::before { content: "\f713"; }
.bi-chat-heart::before { content: "\f714"; }
.bi-chat-left-heart-fill::before { content: "\f715"; }
.bi-chat-left-heart::before { content: "\f716"; }
.bi-chat-right-heart-fill::before { content: "\f717"; }
.bi-chat-right-heart::before { content: "\f718"; }
.bi-chat-square-heart-fill::before { content: "\f719"; }
.bi-chat-square-heart::before { content: "\f71a"; }
.bi-clipboard-check-fill::before { content: "\f71b"; }
.bi-clipboard-data-fill::before { content: "\f71c"; }
.bi-clipboard-fill::before { content: "\f71d"; }
.bi-clipboard-heart-fill::before { content: "\f71e"; }
.bi-clipboard-heart::before { content: "\f71f"; }
.bi-clipboard-minus-fill::before { content: "\f720"; }
.bi-clipboard-plus-fill::before { content: "\f721"; }
.bi-clipboard-pulse::before { content: "\f722"; }
.bi-clipboard-x-fill::before { content: "\f723"; }
.bi-clipboard2-check-fill::before { content: "\f724"; }
.bi-clipboard2-check::before { content: "\f725"; }
.bi-clipboard2-data-fill::before { content: "\f726"; }
.bi-clipboard2-data::before { content: "\f727"; }
.bi-clipboard2-fill::before { content: "\f728"; }
.bi-clipboard2-heart-fill::before { content: "\f729"; }
.bi-clipboard2-heart::before { content: "\f72a"; }
.bi-clipboard2-minus-fill::before { content: "\f72b"; }
.bi-clipboard2-minus::before { content: "\f72c"; }
.bi-clipboard2-plus-fill::before { content: "\f72d"; }
.bi-clipboard2-plus::before { content: "\f72e"; }
.bi-clipboard2-pulse-fill::before { content: "\f72f"; }
.bi-clipboard2-pulse::before { content: "\f730"; }
.bi-clipboard2-x-fill::before { content: "\f731"; }
.bi-clipboard2-x::before { content: "\f732"; }
.bi-clipboard2::before { content: "\f733"; }
.bi-emoji-kiss-fill::before { content: "\f734"; }
.bi-emoji-kiss::before { content: "\f735"; }
.bi-envelope-heart-fill::before { content: "\f736"; }
.bi-envelope-heart::before { content: "\f737"; }
.bi-envelope-open-heart-fill::before { content: "\f738"; }
.bi-envelope-open-heart::before { content: "\f739"; }
.bi-envelope-paper-fill::before { content: "\f73a"; }
.bi-envelope-paper-heart-fill::before { content: "\f73b"; }
.bi-envelope-paper-heart::before { content: "\f73c"; }
.bi-envelope-paper::before { content: "\f73d"; }
.bi-filetype-aac::before { content: "\f73e"; }
.bi-filetype-ai::before { content: "\f73f"; }
.bi-filetype-bmp::before { content: "\f740"; }
.bi-filetype-cs::before { content: "\f741"; }
.bi-filetype-css::before { content: "\f742"; }
.bi-filetype-csv::before { content: "\f743"; }
.bi-filetype-doc::before { content: "\f744"; }
.bi-filetype-docx::before { content: "\f745"; }
.bi-filetype-exe::before { content: "\f746"; }
.bi-filetype-gif::before { content: "\f747"; }
.bi-filetype-heic::before { content: "\f748"; }
.bi-filetype-html::before { content: "\f749"; }
.bi-filetype-java::before { content: "\f74a"; }
.bi-filetype-jpg::before { content: "\f74b"; }
.bi-filetype-js::before { content: "\f74c"; }
.bi-filetype-jsx::before { content: "\f74d"; }
.bi-filetype-key::before { content: "\f74e"; }
.bi-filetype-m4p::before { content: "\f74f"; }
.bi-filetype-md::before { content: "\f750"; }
.bi-filetype-mdx::before { content: "\f751"; }
.bi-filetype-mov::before { content: "\f752"; }
.bi-filetype-mp3::before { content: "\f753"; }
.bi-filetype-mp4::before { content: "\f754"; }
.bi-filetype-otf::before { content: "\f755"; }
.bi-filetype-pdf::before { content: "\f756"; }
.bi-filetype-php::before { content: "\f757"; }
.bi-filetype-png::before { content: "\f758"; }
.bi-filetype-ppt-1::before { content: "\f759"; }
.bi-filetype-ppt::before { content: "\f75a"; }
.bi-filetype-psd::before { content: "\f75b"; }
.bi-filetype-py::before { content: "\f75c"; }
.bi-filetype-raw::before { content: "\f75d"; }
.bi-filetype-rb::before { content: "\f75e"; }
.bi-filetype-sass::before { content: "\f75f"; }
.bi-filetype-scss::before { content: "\f760"; }
.bi-filetype-sh::before { content: "\f761"; }
.bi-filetype-svg::before { content: "\f762"; }
.bi-filetype-tiff::before { content: "\f763"; }
.bi-filetype-tsx::before { content: "\f764"; }
.bi-filetype-ttf::before { content: "\f765"; }
.bi-filetype-txt::before { content: "\f766"; }
.bi-filetype-wav::before { content: "\f767"; }
.bi-filetype-woff::before { content: "\f768"; }
.bi-filetype-xls-1::before { content: "\f769"; }
.bi-filetype-xls::before { content: "\f76a"; }
.bi-filetype-xml::before { content: "\f76b"; }
.bi-filetype-yml::before { content: "\f76c"; }
.bi-heart-arrow::before { content: "\f76d"; }
.bi-heart-pulse-fill::before { content: "\f76e"; }
.bi-heart-pulse::before { content: "\f76f"; }
.bi-heartbreak-fill::before { content: "\f770"; }
.bi-heartbreak::before { content: "\f771"; }
.bi-hearts::before { content: "\f772"; }
.bi-hospital-fill::before { content: "\f773"; }
.bi-hospital::before { content: "\f774"; }
.bi-house-heart-fill::before { content: "\f775"; }
.bi-house-heart::before { content: "\f776"; }
.bi-incognito::before { content: "\f777"; }
.bi-magnet-fill::before { content: "\f778"; }
.bi-magnet::before { content: "\f779"; }
.bi-person-heart::before { content: "\f77a"; }
.bi-person-hearts::before { content: "\f77b"; }
.bi-phone-flip::before { content: "\f77c"; }
.bi-plugin::before { content: "\f77d"; }
.bi-postage-fill::before { content: "\f77e"; }
.bi-postage-heart-fill::before { content: "\f77f"; }
.bi-postage-heart::before { content: "\f780"; }
.bi-postage::before { content: "\f781"; }
.bi-postcard-fill::before { content: "\f782"; }
.bi-postcard-heart-fill::before { content: "\f783"; }
.bi-postcard-heart::before { content: "\f784"; }
.bi-postcard::before { content: "\f785"; }
.bi-search-heart-fill::before { content: "\f786"; }
.bi-search-heart::before { content: "\f787"; }
.bi-sliders2-vertical::before { content: "\f788"; }
.bi-sliders2::before { content: "\f789"; }
.bi-trash3-fill::before { content: "\f78a"; }
.bi-trash3::before { content: "\f78b"; }
.bi-valentine::before { content: "\f78c"; }
.bi-valentine2::before { content: "\f78d"; }
.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; }
.bi-wrench-adjustable-circle::before { content: "\f78f"; }
.bi-wrench-adjustable::before { content: "\f790"; }
.bi-filetype-json::before { content: "\f791"; }
.bi-filetype-pptx::before { content: "\f792"; }
.bi-filetype-xlsx::before { content: "\f793"; }

View File

@ -0,0 +1,98 @@
.dataTables_info {
margin: 15px 0 !important;
padding: 0px !important;
}
.dataTables_paginate, .dataTables_length, .dataTables_filter {
margin: 15px 0 !important;
}
.dtr-details {
width: 100%;
}
.table-striped>tbody>tr:nth-of-type(odd) {
background-color: #F2F2F2;
}
td.child>ul>li {
display: flex;
}
table.dataTable>tbody>tr.child ul.dtr-details>li {
border-bottom: 1px solid rgba(0, 0, 0, 0.129);
padding: 0.5em 0;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
background-color: #5e5e5e;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
table.dataTable td.dt-control:before {
background-color: #979797 !important;
border: 1.5px solid #616161 !important;
border-radius: 2px !important;
color: #fff;
height: 1em;
width: 1em;
line-height: 1.25em;
border-radius: 0px;
box-shadow: none;
font-size: 14px;
transition: 0.5s all;
}
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
table.dataTable td.dt-control:before {
background-color: #979797 !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background-color: #fbfbfb;
}
table.dataTable.table-striped>tbody>tr>td {
vertical-align: middle;
}
table.dataTable.table-striped>tbody>tr>td>input[type="checkbox"] {
margin-top: 7px;
}
td.dtr-col-lg {
min-width: 350px;
word-break: break-word;
}
td.dtr-col-md {
min-width: 250px;
word-break: break-word;
}
td.dtr-col-sm {
min-width: 125px;
word-break: break-word;
}
.dt-data-w100 .dtr-data {
width: 100%;
}
li .dtr-data {
word-break: break-all;
flex: 1;
padding-left: 5px;
padding-right: 5px;
}
table.dataTable>tbody>tr.child span.dtr-title {
width: 30%;
max-width: 250px;
}
div.dataTables_wrapper div.dataTables_filter {
text-align: left;
}
div.dataTables_wrapper div.dataTables_length {
text-align: right;
}
.dataTables_paginate, .dataTables_length, .dataTables_filter {
margin: 10px 0!important;
}
td.dt-text-right {
text-align: end !important;
}
th.dt-text-right {
text-align: end !important;
}

View File

@ -63,6 +63,17 @@
.navbar-nav {
margin: 0;
}
.navbar-nav .nav-item {
flex-direction: column;
display: flex;
padding: 0 10px !important;
}
.navbar-nav .nav-link {
height: 44px;
display: flex;
align-items: center;
padding: 0 10px !important;
}
.navbar-fixed-bottom .navbar-collapse,
.navbar-fixed-top .navbar-collapse {
max-height: 1000px
@ -75,6 +86,12 @@
display: inline-block;
font-size: inherit;
}
.btn-group-xs > .btn, .btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: 1rem;
border-radius: .2rem;
}
.icon-spin {
animation-name: spin;
animation-duration: 2000ms;
@ -105,13 +122,22 @@
transform: rotate(359deg);
}
}
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
.footable-sortable {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
@keyframes blink {
50% {
color: transparent
}
}
.loader-dot {
animation: 1s blink infinite
}
.loader-dot:nth-child(2) {
animation-delay: 250ms
}
.loader-dot:nth-child(3) {
animation-delay: 500ms
}
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
/* Fix modal moving content left */
body.modal-open {
overflow: inherit;
@ -166,19 +192,11 @@ legend {
top: 0; right: 0; bottom: 0; left: 0;
opacity: 0.7;
}
#top {
padding-top: 70px;
}
.bootstrap-select.btn-group .no-results {
display: none;
}
.dropdown-desc {
display: block;
padding: 3px 10px;
clear: both;
font-weight: bold;
color: #5a5a5a;
white-space: nowrap;
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
color: rgb(197, 197, 197) !important;
}
.haveibeenpwned {
cursor: pointer;
@ -206,7 +224,7 @@ legend {
flex-direction: column;
}
.footer .version {
margin-left: auto;
margin-left: auto;
margin-top: 20px;
}
.slave-info {
@ -225,15 +243,8 @@ legend {
.btn-input-missing:active:hover,
.btn-input-missing:active:focus {
color: #000 !important;
background-color: #ff4136;
border-color: #ff291c;
}
table.footable>tbody>tr.footable-empty>td {
font-style:italic;
font-size: 1rem;
}
table>tbody>tr>td>span.footable-toggle {
opacity: 0.75;
background-color: #ff2f24 !important;
border-color: #e21207 !important;
}
.navbar-nav > li {
font-size: 1rem !important;
@ -260,18 +271,11 @@ code {
margin-right: 5px;
}
.list-group-item.webauthn-authenticator-selection,
.list-group-item.totp-authenticator-selection,
.list-group-item.yubi_otp-authenticator-selection {
border-radius: 0px !important;
}
.pending-tfa-collapse {
padding: 10px;
background: #fbfbfb;
border: 1px solid #ededed;
min-height: 110px;
.dropdown-header {
font-weight: 600;
}
.tag-box {
display: flex;
flex-wrap: wrap;
@ -295,7 +299,7 @@ code {
}
.tag-input {
margin-left: 10px;
border: 0;
border: 0 !important;
flex: 1;
height: 24px;
min-width: 150px;
@ -308,3 +312,61 @@ code {
align-items: center;
display: inline-flex;
}
#dnstable {
overflow-x: auto!important;
}
.well {
border: 1px solid #dfdfdf;
background-color: #f9f9f9;
padding: 10px;
}
.btn-check-label {
color: #555;
}
.caret {
transform: rotate(0deg);
}
a[aria-expanded='true'] > .caret,
button[aria-expanded='true'] > .caret {
transform: rotate(-180deg);
}
.list-group-details {
background: #fff;
}
.list-group-header {
background: #f7f7f7;
}
.bg-primary, .alert-primary, .btn-primary {
background-color: #0F688D !important;
border-color: #0d526d !important;
}
.bg-info, .alert-info, .btn-info {
background-color: #148DBC !important;
border-color: #127ea8 !important;
}
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
color: rgb(137 137 137)!important;
}
.progress {
background-color: #d5d5d5;
}
.btn-outline-secondary:hover {
background-color: #f0f0f0;
}
.btn.btn-outline-secondary {
border-color: #cfcfcf !important;
}
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #f0f0f0 !important;
}

View File

@ -1,308 +0,0 @@
.space20 {
margin-bottom: 20px;
}
.btn-xs-lg>.lang-sm:after {
margin-left: 4px;
}
.bootstrap-select {
max-width: 350px;
}
.panel-login .apps .btn {
width: auto;
float: left;
margin-right: 10px;
margin-top: auto;
}
.panel-login .apps .btn:hover {
margin-top: 1px !important;
border-bottom-width: 3px;
}
@media (max-width: 767px) {
.panel-login .apps .btn {
width: 100%;
float: none;
margin-bottom: 10px;
}
.panel-login .apps .btn {
border-bottom-width: 4px;
}
.media-clearfix::after {
clear: both;
box-sizing: border-box;
}
.media-clearfix::before {
display: table;
content: " ";
box-sizing: border-box;
}
.xs-show {
display: block !important;
}
.js-tabcollapse-panel-group .panel{
border: none;
box-shadow: none;
}
.js-tabcollapse-panel-group .panel-body {
padding: 10px 0;
}
.js-tabcollapse-panel-group .js-tabcollapse-panel-body .panel-body {
padding: 0;
}
.js-tabcollapse-panel-body .panel-heading {
display: none;
}
.js-tabcollapse-panel-body .well,
.panel-body .form-inline.well {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
background-color: #fff;
}
.js-tabcollapse-panel-heading {
display: block;
height: 37px;
line-height: 37px;
text-indent: 15px;
}
.js-tabcollapse-panel-heading:hover {
text-decoration: none;
}
.js-tabcollapse-panel-heading {
position: relative;
}
.js-tabcollapse-panel-heading:after {
content: '';
display: block;
position: absolute;
top: 17px;
right: 17px;
width: 0;
height: 0;
margin-left: 2px;
vertical-align: middle;
border-bottom: 4px dashed;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
}
.js-tabcollapse-panel-heading.collapsed:after {
border-bottom: none;
border-top: 4px dashed;
}
.recent-login-success {
font-size: 14px;
margin-top: 10px !important;
}
.pull-xs-right {
float: right !important;
}
.pull-xs-right .dropdown-menu {
right: 0;
left: auto;
}
.text-xs-left {
text-align: left;
}
.text-xs-bold {
font-weight: bold;
}
.text-xs-bold .small {
font-weight: normal;
text-align: justify;
}
.help-block {
text-align: justify;
}
.btn.visible-xs-block {
width: 100%;
float: none;
white-space: normal;
}
.btn-group.footable-actions .btn.btn-xs-half,
.btn.visible-xs-block.btn-xs-half {
width: 50%;
float: left;
}
.btn-group.footable-actions .btn.btn-xs-third,
.btn.visible-xs-block.btn-xs-third {
width: 33.33%;
float: left;
}
.btn-group.footable-actions .btn.btn-xs-quart,
.btn.visible-xs-block.btn-xs-quart {
width: 25%;
float: left;
}
.btn.visible-xs-block.btn-sm,
.btn-xs-lg {
padding: 15px 16px 13px;
line-height: 15px;
}
.input-xs-lg {
height: 47px;
padding: 13px 16px;
}
.btn-group:not(.input-group-btn) {
display: flex;
flex-wrap: wrap;
}
.btn-group.nowrap {
flex-wrap: nowrap;
}
.btn-group.nowrap .dropdown-menu {
width: 100%;
}
.panel-login .btn-group {
display: block;
}
.mass-actions-user .btn-group {
float: none;
}
div[class^='mass-actions'] .dropdown-menu,
.panel-xs-lg .dropdown-menu,
.dropdown-menu.login {
width: 100%;
}
div[class^='mass-actions'] .btn-group .dropdown-menu {
top: 50%;
}
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
div.mass-actions-quarantine .btn-group .dropdown-menu,
.panel-xs-lg .dropdown-menu {
top: 100%;
}
div[class^='mass-actions'] .dropdown-menu>li>a,
.panel-xs-lg .dropdown-menu>li>a,
.dropdown-menu.login>li>a {
padding: 8px 20px;
}
div[class^='mass-actions'] .dropdown-header {
font-size: 14px;
font-weight: bold;
}
.space20 {
margin-bottom: 10px;
}
.top100 {
top: 100% !important;
}
.top33 {
top: 33% !important;
}
.footable-filtering .form {
width: 65%;
}
.btn-xs-lg>.lang-sm:after {
top: 1px;
}
table.footable>tfoot>tr.footable-paging>td {
text-align: left;
}
.footable-first-visible {
min-width: 55px;
}
table>tbody>tr>td>span.footable-toggle {
font-size: 24px;
margin-right: 14px !important;
}
table>tbody>tr>td>span.footable-toggle + input {
position: absolute;
left: 38px;
}
.pagination {
margin-bottom: 5px;
}
tr.footable-filtering>th>form {
width: 270px;
}
.mass-actions-mailbox {
padding: 0;
}
.panel-xs-lg .panel-heading {
height: 66px;
line-height: 47px;
}
.panel-xs-lg .btn-group .btn {
padding-right: 5px;
padding-left: 5px;
}
.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 100%;
}
.btn-group:not(.bootstrap-select) {
width: auto !important;
}
.bootstrap-select {
max-width: 100%;
}
.img-responsive {
margin: 0 auto;
}
.btn-group.footable-actions {
position: absolute;
width: 90vw !important;
left: 0;
height: 36px;
margin-top: -8px;
}
.btn-group.footable-actions .btn {
padding: 10px 16px 7px;
line-height: 15px;
display: block;
width: 100%;
}
.btn-group.footable-actions:after {
content: "";
display: block;
clear: both;
}
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
margin-right: 14px;
white-space: normal;
}
.clearfix {
flex-basis: 100%;
height: 0;
}
.btn-group > .btn-group {
flex-basis: 100%;
}
.btn-group .btn {
display: flex !important;
align-items: center;
justify-content: center;
}
.btn-group .btn i {
margin-right: 5px;
}
.btn-group .btn .caret {
margin-left: 5px;
}
.panel-login .btn-group .btn {
display: block !important;
}
.panel-login .clearfix {
height: auto;
}
}
@media (max-width: 350px) {
.mailcow-logo img {
max-width: 250px;
}
}

View File

@ -0,0 +1,221 @@
.btn-xs-lg>.lang-sm:after {
margin-left: 4px;
}
.bootstrap-select {
max-width: 350px;
}
.card-login .apps .btn {
width: auto;
float: left;
margin-right: 10px;
margin-top: auto;
}
.card-login .apps .btn:hover {
margin-top: 1px !important;
border-bottom-width: 3px;
}
.responsive-tabs .nav-tabs {
display: none;
}
.dataTables_paginate.paging_simple_numbers .pagination {
display: flex;
flex-wrap: wrap;
}
@media (min-width: 768px) {
.responsive-tabs .nav-tabs {
display: flex;
}
.responsive-tabs .card .card-body.collapse {
display: block;
}
}
@media (max-width: 767px) {
.responsive-tabs .tab-pane {
display: block !important;
opacity: 1;
}
.card-login .apps .btn {
width: 100%;
float: none;
margin-bottom: 10px;
}
.card-login .apps .btn {
border-bottom-width: 4px;
}
.xs-show {
display: block !important;
}
.recent-login-success {
font-size: 14px;
margin-top: 10px !important;
}
.pull-xs-right {
float: right !important;
}
.pull-xs-right .dropdown-menu {
right: 0;
left: auto;
}
.text-xs-left {
text-align: left;
}
.text-xs-bold {
font-weight: bold;
}
.text-xs-bold .small {
font-weight: normal;
text-align: justify;
}
.btn.d-block {
width: 100%;
white-space: normal;
}
.btn.btn-xs-half,
.btn.d-block.btn-xs-half {
width: 50%;
}
.btn.btn-xs-third,
.btn.d-block.btn-xs-third {
width: 33.33%;
}
.btn.btn-xs-quart,
.btn.d-block.btn-xs-quart {
width: 25%;
}
.btn.d-block.btn-sm,
.btn-xs-lg {
padding: .5rem 1rem;
line-height: 20px;
}
.input-xs-lg {
height: 47px;
padding: 13px 16px;
}
.btn-group:not(.input-group-btn) {
display: flex;
flex-wrap: wrap;
}
.btn-group.nowrap {
flex-wrap: nowrap;
}
.btn-group.nowrap .dropdown-menu {
width: 100%;
}
.card-login .btn-group {
display: block;
}
.mass-actions-user .btn-group {
float: none;
}
div[class^='mass-actions'] .dropdown-menu,
.card-xs-lg .dropdown-menu,
.dropdown-menu.login {
width: 100%;
}
div[class^='mass-actions'] .btn-group .dropdown-menu {
top: 50%;
}
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
div.mass-actions-quarantine .btn-group .dropdown-menu,
.card-xs-lg .dropdown-menu {
top: 100%;
}
div[class^='mass-actions'] .dropdown-menu>li>a,
.card-xs-lg .dropdown-menu>li>a,
.dropdown-menu.login>li>a {
padding: 8px 20px;
}
div[class^='mass-actions'] .dropdown-header {
font-size: 14px;
font-weight: bold;
}
.top100 {
top: 100% !important;
}
.top33 {
top: 33% !important;
}
.footable-filtering .form {
width: 65%;
}
.btn-xs-lg>.lang-sm:after {
top: 1px;
}
.pagination {
margin-bottom: 5px;
}
.mass-actions-mailbox {
padding: 0;
}
.card-xs-lg .card-header {
height: 66px;
line-height: 47px;
}
.card-xs-lg .btn-group .btn {
padding-right: 5px;
padding-left: 5px;
}
.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 100%;
}
.btn-group:not(.bootstrap-select) {
width: auto !important;
}
.bootstrap-select {
max-width: 100%;
}
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
margin-right: 14px;
white-space: normal;
}
.btn-group > .btn-group {
flex-basis: 100%;
}
.btn-group .btn {
display: flex !important;
align-items: center;
justify-content: center;
}
.btn-group .btn i {
margin-right: 5px;
}
.card-login .btn-group .btn {
display: block !important;
}
.dt-sm-head-hidden .dtr-title {
display: none !important;
}
div.dataTables_wrapper div.dataTables_length {
text-align: left;
}
.senders-mw220 {
max-width: 100% !important;
}
}
@media (max-width: 350px) {
.mailcow-logo img {
max-width: 250px;
}
}
@media (min-width: 1400px) {
.container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
max-width: 1600px;
}
}

View File

@ -25,7 +25,6 @@ body.modal-open {
}
.mass-actions-admin {
user-select: none;
padding:10px 0 10px 0;
}
.inputMissingAttr {
border-color: #FF4136;

View File

@ -26,7 +26,6 @@
}
.mass-actions-debug {
user-select: none;
padding:10px 0 10px 10px;
}
.inputMissingAttr {
border-color: #FF4136;

View File

@ -21,7 +21,6 @@
}
.mass-actions-user {
user-select: none;
padding:10px 0 10px 0;
}
.inputMissingAttr {
border-color: #FF4136;

View File

@ -32,7 +32,6 @@
}
.mass-actions-mailbox {
user-select: none;
padding:10px 0 10px 10px;
}
.inputMissingAttr {
border-color: #FF4136;
@ -67,4 +66,6 @@ table tbody tr td input[type="checkbox"] {
padding: .2em .4em .3em !important;
background-color: #ececec!important;
}
.badge.bg-info .bi {
font-size: inherit;
}

View File

@ -1,103 +1,104 @@
.pagination a {
text-decoration: none !important;
}
.panel.panel-default {
overflow: visible !important;
}
.table-responsive {
overflow: visible !important;
}
.table-responsive {
overflow-x: scroll !important;
}
.footer-add-item {
display: block;
text-align: center;
font-style: italic;
padding: 10px;
background: #F5F5F5;
}
@media (min-width: 992px) {
.container {
width: 100%;
}
}
@media (min-width: 1920px) {
.container {
width: 80%;
}
}
.mass-actions-quarantine {
user-select: none;
padding: 10px;
}
.inputMissingAttr {
border-color: #FF4136;
}
.modal#qidDetailModal p {
word-break: break-all;
}
span#qid_detail_score {
font-weight: 700;
margin-left: 5px;
}
span.rspamd-symbol {
display: inline-block;
margin: 2px 6px 2px 0;
border-radius: 4px;
padding: 0 7px;
}
span.rspamd-symbol.positive {
background: #4CAF50;
border: 1px solid #4CAF50;
color: white;
}
span.rspamd-symbol.negative {
background: #ff4136;
border: 1px solid #ff4136;
color: white;
}
span.rspamd-symbol.neutral {
background: #f5f5f5;
color: #333;
border: 1px solid #ccc;
}
span.rspamd-symbol span.score {
font-weight: 700;
}
span.mail-address-item {
background-color: #f5f5f5;
border-radius: 4px;
border: 1px solid #ccc;
padding: 2px 7px;
display: inline-block;
margin: 2px 6px 2px 0;
}
table tbody tr {
cursor: pointer;
}
table tbody tr td input[type="checkbox"] {
cursor: pointer;
}
.label-rspamd-action {
font-size:110%;
margin:20px;
}
.pagination a {
text-decoration: none !important;
}
.panel.panel-default {
overflow: visible !important;
}
.table-responsive {
overflow: visible !important;
}
.table-responsive {
overflow-x: scroll !important;
}
.footer-add-item {
display: block;
text-align: center;
font-style: italic;
padding: 10px;
background: #F5F5F5;
}
@media (min-width: 992px) {
.container {
width: 100%;
}
}
@media (min-width: 1920px) {
.container {
width: 80%;
}
}
.mass-actions-quarantine {
user-select: none;
}
.inputMissingAttr {
border-color: #FF4136;
}
.modal#qidDetailModal p {
word-break: break-all;
}
span#qid_detail_score {
font-weight: 700;
margin-left: 5px;
}
span.rspamd-symbol {
display: inline-block;
margin: 2px 6px 2px 0;
border-radius: 4px;
padding: 0 7px;
}
span.rspamd-symbol.positive {
background: #4CAF50;
border: 1px solid #4CAF50;
color: white;
}
span.rspamd-symbol.negative {
background: #ff4136;
border: 1px solid #ff4136;
color: white;
}
span.rspamd-symbol.neutral {
background: #f5f5f5;
color: #333;
border: 1px solid #ccc;
}
span.rspamd-symbol span.score {
font-weight: 700;
}
span.mail-address-item {
background-color: #f5f5f5;
border-radius: 4px;
border: 1px solid #ccc;
padding: 2px 7px;
display: inline-block;
margin: 2px 6px 2px 0;
}
table tbody tr {
cursor: pointer;
}
table tbody tr td input[type="checkbox"] {
cursor: pointer;
}
.label-rspamd-action {
font-size:110%;
margin:20px;
}
.senders-mw220 {
max-width: 220px;
}

View File

@ -21,7 +21,6 @@
}
.mass-actions-user {
user-select: none;
padding:10px 0;
}
.inputMissingAttr {
border-color: #FF4136;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,373 @@
body {
background-color: #414141;
color: #e0e0e0;
}
.card {
border: 1px solid #1c1c1c;
background-color: #3a3a3a;
}
legend {
color: #f5f5f5;
}
.card-header {
color: #bbb;
background-color: #2c2c2c;
border-color: transparent;
}
.btn-secondary, .paginate_button, .page-link, .btn-light {
color: #fff !important;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
}
.btn-dark {
color: #000 !important;;
background-color: #f6f6f6 !important;;
border-color: #ddd !important;;
}
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
border-color: #7a7a7a !important;
}
.alert-secondary {
color: #fff !important;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
}
.bg-secondary {
color: #fff !important;
background-color: #7a7a7a !important;
}
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
color: #fff;
}
.page-item.active .page-link {
background-color: #158cba !important;
border-color: #127ba3 !important;
}
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
background-color: #7a7a7a;
border-color: #5c5c5c !important;
color: #fff;
}
.btn-secondary:disabled, .btn-secondary.disabled {
border-color: #7a7a7a !important;
}
.modal-content {
background-color: #414141;
}
.modal-header {
border-bottom: 1px solid #161616;
}
.modal-title {
color: white;
}
.modal .btn-close {
filter: invert(1) grayscale(100%) brightness(200%);
}
.navbar.bg-light {
background-color: #222222 !important;
border-color: #181818;
}
.nav-link {
color: #ccc !important;
}
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
background: none;
}
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
border-bottom-color: #414141;
}
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
color: #ccc !important;
}
.dropdown-menu {
background-color: #585858;
border: 1px solid #333;
}
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
color: #fafafa;
}
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder:active, .bootstrap-select>.dropdown-toggle.bs-placeholder:focus, .bootstrap-select>.dropdown-toggle.bs-placeholder:hover {
color: #fff;
}
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
color: #d4d4d4 !important;
}
tbody tr {
color: #555;
}
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
color: #ccc;
}
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
color: #ccc;
}
.list-group-item {
background-color: #333;
border: 1px solid #555;
}
.table-striped>tbody>tr:nth-of-type(odd) {
background-color: #333;
}
table.dataTable>tbody>tr.child ul.dtr-details>li {
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
}
tbody tr {
color: #ccc;
}
.label.label-last-login {
color: #ccc !important;
background-color: #555 !important;
}
.progress {
background-color: #555;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
color: #ccc;
}
div.numberedtextarea-number {
color: #999;
}
.well {
border: 1px solid #555;
background-color: #333;
}
pre {
color: #ccc;
background-color: #333;
border: 1px solid #555;
}
input.form-control, textarea.form-control {
color: #e2e2e2 !important;
background-color: #555 !important;
border: 1px solid #999;
}
input.form-control:focus, textarea.form-control {
background-color: #555 !important;
}
input.form-control:disabled, textarea.form-disabled {
color: #a8a8a8 !important;
background-color: #6e6e6e !important;
}
.input-group-addon {
color: #ccc;
background-color: #555 !important;
border: 1px solid #999;
}
.input-group-text {
color: #ccc;
background-color: #242424;
}
.list-group-item {
color: #ccc;
}
.dropdown-item {
color: #ccc;
}
.dropdown-item:hover {
color: #616161 !important;
}
.dropdown-item.active:hover {
color: #fff !important;
background-color: #31b1e4;
}
.form-select {
color: #e2e2e2!important;
background-color: #555!important;
border: 1px solid #999;
}
.responsive-tabs .card-header button[data-bs-toggle="collapse"] {
color: #c7c7c7;
}
.navbar-toggler {
color: #fff !important;
}
.table-secondary {
--bs-table-bg: #7a7a7a;
--bs-table-striped-bg: #e4e4e4;
--bs-table-striped-color: #000;
--bs-table-active-bg: #d8d8d8;
--bs-table-active-color: #000;
--bs-table-hover-bg: #dedede;
--bs-table-hover-color: #000;
color: #000;
border-color: #d8d8d8;
}
.table-light {
--bs-table-bg: #f6f6f6;
--bs-table-striped-bg: #eaeaea;
--bs-table-striped-color: #000;
--bs-table-active-bg: #dddddd;
--bs-table-active-color: #000;
--bs-table-hover-bg: #e4e4e4;
--bs-table-hover-color: #000;
color: #000;
border-color: #dddddd;
}
.form-control-plaintext {
color: #e0e0e0;
}
.breadcrumb {
color: #fff !important;
background-color: #7a7a7a !important;
border-color: #5c5c5c !important;
}
a {
color: #6fc7e9;
text-decoration: underline;
}
a:hover {
color: #3daedb;
}
.breadcrumb-item.active {
color: #ccc;
}
.list-group-item.disabled, .list-group-item:disabled {
color: #fff;
background-color: #a8a8a8 !important;
border-color: #a8a8a8;
}
.card.bg-light .card-title {
color: #000 !important;
}
.card.bg-light .card-text {
color: #000;
}
.accordion-item {
background-color: #3a3a3a;
}
.accordion-button {
color: #bbb;
background-color: #2c2c2c;
}
.accordion-button:not(.collapsed) {
color: #6fc7e9;
background-color: #2c2c2c;
}
.accordion-button::after {
background-image: none;
}
.accordion-button:not(.collapsed)::after {
background-image: none;
}
.toast-header {
background-color: #4c4c4c;
}
.toast-body {
background-color: #626262;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff !important;
}
.tag-box {
background-color: #555;
border: 1px solid #999;
}
.tag-input {
color: #fff;
background-color: #555;
}
.tag-add {
color: #ccc;
}
.tag-add:hover {
color: #d1d1d1;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
background-color: #7a7a7a !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
background-color: #7a7a7a !important;
border: 1.5px solid #5c5c5c !important;
color: #fff !important;
}
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
background-color: #949494;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background-color: #444444;
}
.btn-check-label {
color: #fff;
}
.btn-outline-secondary:hover {
background-color: #c3c3c3;
}
.btn.btn-outline-secondary {
color: #fff !important;
border-color: #7a7a7a !important;
}
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #9b9b9b !important;
}
.btn-input-missing,
.btn-input-missing:hover,
.btn-input-missing:active,
.btn-input-missing:focus,
.btn-input-missing:active:hover,
.btn-input-missing:active:focus {
color: #fff !important;
background-color: #ff2f24 !important;
border-color: #e21207 !important;
}
.inputMissingAttr {
border-color: #FF4136 !important;
}
.list-group-details {
background: #444444;
}
.list-group-header {
background: #333;
}
span.mail-address-item {
background-color: #333;
border-radius: 4px;
border: 1px solid #555;
padding: 2px 7px;
display: inline-block;
margin: 2px 6px 2px 0;
}

View File

@ -11,6 +11,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/debug.js');
// vmail df
@ -44,15 +49,26 @@ foreach ($containers as $container => $container_info) {
$containers[$container]['State']['StartedAtHR'] = $started;
}
// get mailcow data
$hostname = getenv('MAILCOW_HOSTNAME');
$timezone = getenv('TZ');
$template = 'debug.twig';
$template_data = [
'log_lines' => getenv('LOG_LINES'),
'vmail_df' => $vmail_df,
'hostname' => $hostname,
'timezone' => $timezone,
'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'),
'solr_status' => $solr_status,
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
'clamd_status' => $clamd_status,
'containers' => $containers,
'ip_check' => customize('get', 'ip_check'),
'lang_admin' => json_encode($lang['admin']),
'lang_debug' => json_encode($lang['debug']),
'lang_datatables' => json_encode($lang['datatables']),
];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';

View File

@ -38,24 +38,46 @@ if (isset($_SESSION['mailcow_cc_role'])) {
$template = 'edit/admin.twig';
$template_data = ['admin' => $admin];
}
elseif (isset($_GET['domain']) &&
is_valid_domain_name($_GET["domain"]) &&
!empty($_GET["domain"])) {
$domain = $_GET["domain"];
$result = mailbox('get', 'domain_details', $domain);
$quota_notification_bcc = quota_notification_bcc('get', $domain);
$rl = ratelimit('get', 'domain', $domain);
$rlyhosts = relayhost('get');
$template = 'edit/domain.twig';
elseif (isset($_GET['domain'])) {
if (is_valid_domain_name($_GET["domain"]) &&
!empty($_GET["domain"])) {
// edit domain
$domain = $_GET["domain"];
$result = mailbox('get', 'domain_details', $domain);
$quota_notification_bcc = quota_notification_bcc('get', $domain);
$rl = ratelimit('get', 'domain', $domain);
$rlyhosts = relayhost('get');
$template = 'edit/domain.twig';
$template_data = [
'acl' => $_SESSION['acl'],
'domain' => $domain,
'quota_notification_bcc' => $quota_notification_bcc,
'rl' => $rl,
'rlyhosts' => $rlyhosts,
'dkim' => dkim('details', $domain),
'domain_details' => $result,
];
}
}
elseif (isset($_GET["template"])){
$domain_template = mailbox('get', 'domain_templates', $_GET["template"]);
if ($domain_template){
$template_data = [
'acl' => $_SESSION['acl'],
'domain' => $domain,
'quota_notification_bcc' => $quota_notification_bcc,
'rl' => $rl,
'rlyhosts' => $rlyhosts,
'dkim' => dkim('details', $domain),
'domain_details' => $result,
'template' => $domain_template
];
$template = 'edit/domain-templates.twig';
$result = true;
}
else {
$mailbox_template = mailbox('get', 'mailbox_templates', $_GET["template"]);
if ($mailbox_template){
$template_data = [
'template' => $mailbox_template
];
$template = 'edit/mailbox-templates.twig';
$result = true;
}
}
}
elseif (isset($_GET['oauth2client']) &&
is_numeric($_GET["oauth2client"]) &&
@ -79,29 +101,32 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'dkim' => dkim('details', $alias_domain),
];
}
elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
$result = mailbox('get', 'mailbox_details', $mailbox);
$rl = ratelimit('get', 'mailbox', $mailbox);
$pushover_data = pushover('get', $mailbox);
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
$rlyhosts = relayhost('get');
$template = 'edit/mailbox.twig';
$template_data = [
'acl' => $_SESSION['acl'],
'mailbox' => $mailbox,
'rl' => $rl,
'pushover_data' => $pushover_data,
'quarantine_notification' => $quarantine_notification,
'quarantine_category' => $quarantine_category,
'get_tls_policy' => $get_tls_policy,
'rlyhosts' => $rlyhosts,
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
'user_acls' => acl('get', 'user', $mailbox),
'mailbox_details' => $result
];
elseif (isset($_GET['mailbox'])){
if(filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
// edit mailbox
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
$result = mailbox('get', 'mailbox_details', $mailbox);
$rl = ratelimit('get', 'mailbox', $mailbox);
$pushover_data = pushover('get', $mailbox);
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
$rlyhosts = relayhost('get');
$template = 'edit/mailbox.twig';
$template_data = [
'acl' => $_SESSION['acl'],
'mailbox' => $mailbox,
'rl' => $rl,
'pushover_data' => $pushover_data,
'quarantine_notification' => $quarantine_notification,
'quarantine_category' => $quarantine_category,
'get_tls_policy' => $get_tls_policy,
'rlyhosts' => $rlyhosts,
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
'user_acls' => acl('get', 'user', $mailbox),
'mailbox_details' => $result
];
}
}
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
$relayhost = intval($_GET["relayhost"]);
@ -189,5 +214,6 @@ $js_minifier->add('/web/js/site/pwgen.js');
$template_data['result'] = $result;
$template_data['return_to'] = $_SESSION['return_to'];
$template_data['lang_user'] = json_encode($lang['user']);
$template_data['lang_datatables'] = json_encode($lang['datatables']);
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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