Compare commits

...

333 Commits

Author SHA1 Message Date
Niklas Meyer
3028a18a37 Merge pull request #4819 from mailcow/staging
2022-10
2022-10-25 14:16:05 +02:00
Niklas Meyer
26a5fcf989 Merge pull request #4815 from ethrgeist:bump-redis-7
[redis] Bump Redis to version 7
2022-10-25 12:20:30 +02:00
Niklas Meyer
509086ef54 Merge pull request #4816 from mailcow/feature/rspamd-3.3
[RSPAMD] Update to 3.3
2022-10-25 11:42:34 +02:00
Niklas Meyer
963510ed22 Merge pull request #4806 from mailcow/feature/pigz-backup
[Backup] Swapped PIGZ instead of gzip (allow Threading)
2022-10-25 11:05:40 +02:00
DerLinkman
2c0f8cda50 [RSPAMD] Update to 3.3 2022-10-25 10:35:23 +02:00
DerLinkman
50d2671d75 Fixed leading / warning removal 2022-10-25 10:06:53 +02:00
DerLinkman
b73d879f3c Removed thread prompt again. Added notice message 2022-10-25 09:55:29 +02:00
Knuth
725a5fe5b9 Bump Redis to version 7 2022-10-25 09:47:03 +02:00
DerLinkman
65ca42ca42 Restored Thread Prompt due to implementation in restore 2022-10-24 15:10:15 +02:00
DerLinkman
b22ff59f7b Added PIGZ for Restoring as well. 2022-10-24 12:28:41 +02:00
DerLinkman
58527857d9 Removed debug message 2022-10-21 11:54:23 +02:00
DerLinkman
6306c4555c Removed Thread Prompt and set default value to 1 Thread 2022-10-21 11:48:29 +02:00
Peter
922603f906 Rename turkish language file for #4657 2022-10-20 17:57:13 +02:00
Niklas Meyer
f8d45de749 Merge pull request #4657 from tomy0000000:master
🌐 Add Traditional Chinese Translation
2022-10-20 11:27:58 +02:00
DerLinkman
cb1602c2de Fix English Flag rendering 2022-10-19 16:09:22 +02:00
DerLinkman
8026b6c874 Swapped PIGZ instead of gzip 2022-10-19 11:15:12 +02:00
Peter
042676fff7 [GH-Actions][actionpr] Update to v0.5.1 2022-10-12 18:27:30 +02:00
Peter
44d53146af [GH-Actions][stale] Update to v6.0.1 2022-10-12 18:26:39 +02:00
Niklas Meyer
ce4fb069d5 Merge pull request #4789 from mailcow/feat/prtonightlyaction
Update PR to nightly template
2022-10-09 17:26:17 +02:00
Peter
9444000d46 Use milkmaker as PR author
Use template to be able to use get_diff var
2022-10-09 17:02:28 +02:00
Peter
eacd9ac240 Add pr_to_nighty_template.yml 2022-10-09 17:01:21 +02:00
Tomy Hsieh
cf38d6ca69 🛠 fix: Improve language preference algo 2022-10-06 23:22:54 +08:00
Tomy Hsieh
905993d66e 🛠 fix: Language detection 2022-10-06 22:21:12 +08:00
DerLinkman
0d7fe2e347 Some corrections to pr action 2022-10-06 14:14:07 +02:00
DerLinkman
33bd871a63 Corrected some PR Action Code 2022-10-06 14:06:18 +02:00
DerLinkman
772122b255 Added auto PR for nightly builds 2022-10-06 14:04:27 +02:00
Niklas Meyer
9fb346751c Merge pull request #4724 from mnin/master
[Netfilter] Fix creating endless SNAT rules for ipv4
2022-10-06 12:18:23 +02:00
Niklas Meyer
cb058e91a3 Merge pull request #4772 from mailcow/staging
Update Twig to 3.4.3
2022-09-30 12:25:05 +02:00
FreddleSpl0it
27e7407407 Update Twig to 3.4.3 2022-09-30 11:03:05 +02:00
Tomy Hsieh
7d46de33d8 Merge from upstream branch 'staging'
# Conflicts:
#	data/web/inc/vars.inc.php
2022-09-30 16:03:49 +08:00
Niklas Meyer
5470b51cc7 Merge pull request #4766 from mailcow/staging
2022-09
2022-09-27 15:53:31 +02:00
Niklas Meyer
8e0b1d8aee Merge pull request #4703 from devops-ansible/master
Improve send-as behaviour
2022-09-27 15:39:53 +02:00
Niklas Meyer
2834459b22 Merge pull request #4763 from ntimo/task/update-swagger
[API] Update swagger version
2022-09-27 11:16:44 +02:00
ntimo
000894dabd [API] Update swagger version 2022-09-26 19:33:31 +00:00
milkmaker
494620cdea [Web] Updated lang.tr.json (#4765)
Co-authored-by: Burak Buylu <burak@burtinet.com>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Burak Buylu <burak@burtinet.com>
2022-09-26 19:05:54 +02:00
Niklas Meyer
a502eb239d Merge pull request #4758 from mailcow/feature/fix-4743 2022-09-26 18:41:40 +02:00
Niklas Meyer
caf775093e Merge pull request #4762 from mindsolve/patch-1 2022-09-26 18:40:19 +02:00
Alex
f28e18e676 GitHub Workflows security hardening (#4761)
* build: harden integration_tests.yml permissions

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

* build: harden image_builds.yml permissions

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* [Web] Turkish translation

* [Web] Turkish translation

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

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

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

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

* add tags to request body of add domain

* add gal to request body of add domain

* add relay_unknown_only to request body of add domain

* add relay_unknown_only to request body of edit domain

* add rl_frame, rl_value to request body of edit domain

* fix indentation

* add tags to request body of edit domain

* change response of edit domain to array

* Revert "change response of edit domain to array"

This reverts commit 692384e21b.

* change response type of edit domain to application/json

* change response type of edit domain

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

* change response of edit domain to array

* fix indentation

* revert changing response type of edit domain-admin

* change response type of edit domain to array

* fix response type of edit domains

* change msg in response of edit domains to array

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

* change request body of delete domain to array of strings

* fix

* remove properties

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

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

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

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

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

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

Co-authored-by: Daniel Castellanos <decacis@gmail.com>
2022-06-19 22:23:35 +02:00
DerLinkman
dd6b8c44a4 Added automatic docker-compose standalone installation 2022-06-16 14:13:08 +02:00
DerLinkman
499273dbb7 Readded docker-compose check 2022-06-16 13:50:44 +02:00
DerLinkman
6612b892b7 Removed extra checkout line 2022-06-16 12:56:54 +02:00
DerLinkman
89cea31475 Revert "Before update on 2022-06-16_12_41_05"
This reverts commit 36e4ee7738.
2022-06-16 12:51:51 +02:00
DerLinkman
872fa07213 Restore docker-compose check in scripts 2022-06-16 12:49:17 +02:00
DerLinkman
36e4ee7738 Before update on 2022-06-16_12_41_05 2022-06-16 12:41:49 +02:00
DerLinkman
a139eb9bce Readded Dual Stack availability of WebUI (default) 2022-06-16 12:38:06 +02:00
DerLinkman
7166696aa2 Readded Compose Standalone Download 2022-06-16 12:28:04 +02:00
Markus Ritzmann
537a7908f1 Clamd: Fix Docker Healthcheck 2022-06-16 09:50:33 +02:00
Peter
3fe776ee69 Update SOGo to 5.7.0 2022-06-14 18:55:26 +02:00
DerLinkman
581be02e53 [Dovecot] Update to 2.3.19.1 2022-06-14 15:02:40 +02:00
FreddleSpl0it
71db83efce hotfix imapsync 2022-06-13 12:46:39 +02:00
andryyy
7ae7f25580 [Web] Re-use DKIM key if available 2022-06-11 11:42:36 +02:00
DerLinkman
5d14baa43a Fixed typo for previous commit 2022-06-07 18:38:43 +02:00
DerLinkman
141b397c82 Fix Docker Compose recognition for docker-compose syntax 2022-06-07 18:34:41 +02:00
Niklas Meyer
fd853cfc6f [Compose] Rollback watchdog to 1.96
Due to https://github.com/nagios-plugins/nagios-plugins/pull/649 which cause the Certificate Check to fail.
2022-06-07 17:50:42 +02:00
Niklas Meyer
63f718178e 🌕🐄 Moone Update 2022 - The Docker Compose v2 Update (Part I)
The next major mailcow release.
2022-06-07 15:37:41 +02:00
DerLinkman
74baf20feb Optimized if-else arguments and outputs 2022-06-07 14:45:19 +02:00
FreddleSpl0it
958112af6b [Compose] Remove >&2 in if block 2022-06-07 14:07:35 +02:00
FreddleSpl0it
08d0f9448e [Compose] move then in if statement 2022-06-07 13:59:59 +02:00
Niklas Meyer
7bcc8bd3a2 [Compose] Removed volume Bind from rspamd-vol 2022-06-07 10:34:59 +02:00
FreddleSpl0it
0eb2545773 [WebAuthn] send empty transports array to fix android bug 2022-06-07 09:01:04 +02:00
Niklas Meyer
714511b0a8 [Compose] Update to Docker Compose v2 (#4605)
* Change default HTTP_BIND, HTTPS_BIND

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

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

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

(cherry picked from commit 4d53216c05)

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

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

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

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

* [ClamAV] Fixed ClamAV start before unbound

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

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

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

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

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

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

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

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

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

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

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

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

* Add Ukrainian language code in vars.inc.php

Co-authored-by: DRago_Angel <alekseev.dmitriy.92@gmail.com>
Co-authored-by: OGudzik <olegrpg@gmail.com>
Co-authored-by: Oleksii Kruhlenko <a.kruglenko@gmail.com>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: Stefano <stefano.vassena@gmail.com>
2022-05-18 18:20:03 +02:00
FreddleSpl0it
7d5990bf0f restrict webauthn-tfa-get-args sql query 2022-05-18 10:03:10 +02:00
FreddleSpl0it
4ec982163e restrict webauthn-tfa-get-args sql query 2022-05-18 09:39:50 +02:00
FreddleSpl0it
3c9502f241 add webauthn console log 2022-05-17 19:02:52 +02:00
Niklas Meyer
63cecb2fd8 Merge pull request #4484 from FreddleSpl0it/selection-tfa
[Web] change tfa flow
2022-05-17 15:26:43 +02:00
Niklas Meyer
3029a2d33d Change DB Date to newer Date than staging 2022-05-17 15:26:01 +02:00
Niklas Meyer
fa0d2a959d Merge branch 'feature/tfa-flow' into selection-tfa 2022-05-17 15:23:10 +02:00
Niklas Meyer
f79cac3292 Merge pull request #4590 from FreddleSpl0it/swagger-appPasswd 2022-05-17 08:53:57 +02:00
FreddleSpl0it
7a20a9941e Update swagger docs - add/app-passwd 2022-05-17 07:03:33 +02:00
Niklas Meyer
24cc960379 [Clamd] Update to ClamAV 0.105
Merge pull request #4589 from mailcow/feature/clamd-0.105
2022-05-16 19:51:18 +02:00
Niklas Meyer
353df6413f [UI] Increase Mailadmin loading performance
Merge pull request #4562 from marcojarjour/unblock_mailadmin_upstream
2022-05-16 19:30:50 +02:00
Andri Steiner
b68eae16e5 [Web] Swagger UI: explicitly define used OpenAPI specifications (#4587) 2022-05-13 10:40:22 +02:00
Niklas Meyer
9a812edee4 Mooay 2022 Update – The Tag Update | Revision B (2022-05b)
This PR adds some API Fixes and one UI Fix (improvement)
2022-05-12 11:52:06 +02:00
Peter
43d2a6e135 Update issue template 2022-05-10 21:16:08 +02:00
Peter
5839e22796 Update issue template 2022-05-10 21:14:51 +02:00
DerLinkman
ee844c81d2 Changed Base Docker Image to 0.105.0_base 2022-05-08 18:33:29 +02:00
Niklas Meyer
b6cb3b026c [ClamAV] Update to 0.105 2022-05-06 15:44:58 +02:00
Niklas Meyer
df33ebb2a0 Merge pull request #4575 from FreddleSpl0it/footable-override-css
[Web] change opacity of footable collapse toggle
2022-05-06 08:59:53 +02:00
Niklas Meyer
d2a6838958 Merge pull request #4574 from FreddleSpl0it/tag-fix
[Web] domain/mailbox tagging check for empty tags
2022-05-06 08:59:21 +02:00
FreddleSpl0it
96b8054e6b [Web] change opacity of footable collapse toggle 2022-05-06 08:52:44 +02:00
FreddleSpl0it
dfdd2dadb4 [Web] domain/mailbox tagging check for empty tags 2022-05-06 08:30:15 +02:00
Niklas Meyer
d0528b7883 Merge pull request #4573 from jkellerer/patch-1
Fix for /api/v1/get/mailbox/{email}
2022-05-06 08:24:41 +02:00
FreddleSpl0it
f40e682800 [Web] domain/mailbox tagging check for empty tags 2022-05-06 07:42:45 +02:00
jkellerer
f4dc01d1ec Ensure return type is consistent (list vs object) 2022-05-05 20:00:40 +02:00
jkellerer
187ddedf96 Fix for /api/v1/get/mailbox/{email} 2022-05-05 19:43:33 +02:00
Niklas Meyer
5613134fed Merge pull request #4572 from mailcow/staging
Readded .gitkeep in data/web/templates/cache
2022-05-05 17:30:21 +02:00
Niklas Meyer
e454ed4e39 Readded .gitkeep in data/web/templates/cache 2022-05-05 17:25:04 +02:00
Niklas Meyer
1e2125653e [Update.sh] Added skip-ping-check Variable
This PR adds the skip-ping-check Variable which allows the update.sh Script to continue even without a ping check of the public DNS resolvers.
2022-05-05 10:52:39 +02:00
Niklas Meyer
835a726d2a [SOGo] Update to 5.6.0
This PR includes the Update from SOGo to 5.6.0.

The new Docker Tag is mailcow/sogo:1.108 and was already pushed to the Dockerhub.
2022-05-05 09:47:58 +02:00
Niklas Meyer
0539cc6d8c [SOGo] Update to 5.6.0 2022-05-05 08:28:57 +02:00
FreddleSpl0it
549ff7d100 Add Domain and Mailbox tagging (#4569)
* [Web] define tag tables

* [Web] add mailbox tag functions

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* Include new tags lang in language.en.json

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

* [Web] add domain/mailbox tagging

Co-authored-by: Niklas Meyer <62480600+DerLinkman@users.noreply.github.com>
2022-05-05 08:25:01 +02:00
Niklas Meyer
456b528785 [API] Add version endpoint
Resolves: https://github.com/mailcow/mailcow-dockerized/issues/4553
2022-05-04 14:33:39 +02:00
Marco Jarjour
003a6342a5 Match also mobile id's 2022-04-27 17:43:40 +02:00
Marco Jarjour
fb10764167 Execute API calls only when needed 2022-04-27 15:57:53 +02:00
Lars Lehmann
9e1554f5c7 Add missing break 2022-04-26 13:12:31 +02:00
Niklas Meyer
42c82be8f5 Added skip-ping-check Variable to skip DNS ICMP if deactivated. 2022-04-26 10:17:47 +02:00
Lars Lehmann
76ec0e888b Add version endpoint 2022-04-25 22:44:41 +02:00
Niklas Meyer
892c99fa23 Merge pull request #4556 from mailcow/accessibility
[Web] Make TLS policy toggles accessible
2022-04-25 09:48:15 +02:00
Michael Kuron
28da482ef2 [Web] Make TLS policy toggles accessible
Fixes #4554
2022-04-24 12:25:49 +02:00
Niklas Meyer
936f07336c [Netfilter] Exclude banning IPs when dovecot server not reacheble
The new docker tag for mailcow/netfilter is 1.47

Thanks to @dragoangel
2022-04-22 16:20:35 +02:00
DerLinkman
224a59ab4b [Compose] Update netfilter-mailcow to 1.47 2022-04-22 16:19:06 +02:00
Dmitriy Alekseev
6c5ab7800e [Netfilter] Exclude banning IPs when dovecot server not reacheble 2022-04-13 13:01:58 +03:00
andryyy
7e26a2ab98 [Rspamd] Remove neural config due to massive fp 2022-04-13 10:42:11 +02:00
Kristian Feldsam
4e6c398c8c [Clamd] fix whitelist (#4541)
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2022-04-08 21:39:35 +02:00
Kristian Feldsam
d4e829465b [Dovecot] Disable imapsync job, when auth details are wrong. Fixes #4276 (#4540)
Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
2022-04-08 21:36:21 +02:00
andryyy
1ade37312e Merge remote-tracking branch 'origin/staging' into staging 2022-04-08 09:39:50 +02:00
andryyy
372e381a85 [Web] Fix wrong lang string for filter deletion confirmation 2022-04-08 09:39:32 +02:00
DerLinkman
374cc64601 Merge branch 'staging' 2022-04-05 22:56:11 +02:00
Niklas Meyer
1cf25572a3 [NGINX] Added new Proxy Buffers to the /SOGo Section 2022-04-05 22:54:38 +02:00
DerLinkman
ba45f70a30 [NGINX] Added new Proxy Buffers to the /SOGo Section 2022-04-05 22:49:41 +02:00
andryyy
5e56566de6 [Nginx] Fix Nginx buffer sizes by moving parameters to correct location 2022-04-05 22:35:02 +02:00
andryyy
a2ccf7ef03 [Nginx] Fix Nginx buffer sizes by moving parameters to correct location 2022-04-05 22:34:26 +02:00
Niklas Meyer
654dbf8198 🐄🐰 Moopril 2022 - ClamAV, Rspamd, SOGo Update
Additions:

Update SOGo to 5.5.1
Update Rspamd to 3.2.1
Update ClamAV Containers to use the official ones
Added a specific ClamAV Volume for Docker

Fixes:

Autodiscover is now compatible with App Passwords.
The Postmap Access List has been updated to a newer state.
New French translations.
2022-04-05 11:38:01 +02:00
Niklas Meyer
53a5254897 [SOGo] Update SOGo to 5.5.1
**Includes Database Changes!**

As a preparation for 5.5.2 the database as well as some NGINX Settings have been changed.
2022-04-01 15:20:09 +02:00
milkmaker
c433daf024 [Web] Updated lang.fr.json [CI SKIP] (#4529)
Co-authored-by: crep7424 <guillaume@crepieux.eu>

Co-authored-by: crep7424 <guillaume@crepieux.eu>
2022-03-31 21:05:40 +02:00
Peter
fd7269d455 [ClamAV] Move to official ClamAV Docker container (#4525)
Since ClamAV starts to offer Docker containers this PR introduces said containers so we don't need to build the container on our own anymore. This was an easy task until v0.104, but then ClamAV changed its buildprocess to use cmake and with v0.105 it also needs the Rust toolchain -> https://docs.clamav.net/manual/Installing/Installing-from-source-Unix.html#ubuntu--debian

Here are the main changes for the new container

Creates clamd-db-vol-1 volume
Still uses the same config files
Downloads ClamAV databases in said volume
Smaller container footprint 13MB vs 150MB

---

* [ClamAV] Move to official ClamAV Docker container

* [ClamAV] Remove vim + nano

* [ClamAV] Use normal version in docker-compose
2022-03-28 11:07:47 +02:00
Niklas Meyer
b375e6a250 [Rspamd] Update Rspamd to 3.2.1 (#4526)
This PR Updates Rspamd to 3.2.1

(See Changelog here: https://rspamd.com/announce/2022/03/26/rspamd-3.2.html)

The new Tag is mailcow/rspamd:1.90
2022-03-28 11:05:44 +02:00
milkmaker
48589d20e2 [Web] Updated lang.fr.json [CI SKIP] (#4523)
Co-authored-by: crep7424 <guillaume@crepieux.eu>

Co-authored-by: crep7424 <guillaume@crepieux.eu>
2022-03-25 18:00:50 +01:00
Aiko Appeldorn
be9cbcf5ac [Postfix] update postscreen access list (#4515) 2022-03-23 11:49:46 +01:00
Niklas Meyer
b04faddac4 Modified Buffer Size in site-defaults.conf 2022-03-23 11:14:07 +01:00
DerLinkman
e925187dda Revert "[Web] add github version tag - adjust css"
This reverts commit a0c09af67e.
2022-03-22 19:53:21 +01:00
Niklas Meyer
06f380a17a [DB] Removed empty space behind c_value 2022-03-22 19:47:53 +01:00
Niklas Meyer
67882414e1 [DB] Update DB Version to 22032022_1330
For SOGo 5.5.1 and newer
2022-03-22 19:47:53 +01:00
Niklas Meyer
2b149fb8ea [DB] Update schema for longer passwords in sogo 2022-03-22 19:47:53 +01:00
Niklas Meyer
3166bd5df5 [Compose] Update SOGo to 5.5.1 2022-03-22 19:47:53 +01:00
Michael Kuron
e911452d0c Enable autodiscover to work with app passwords (#4516)
Fixes #4513
2022-03-22 19:41:34 +01:00
Vincent Simon
deac5ad2fe [Web] Fix resource.php and /cache/ warning message
If http://mail.example.tld/cache/ or http://mail.example.tld/resource.php are called without the required parameters it returns one or two warnings
2022-03-20 22:05:28 +01:00
Niklas Meyer
f097267bcd Merge branch 'mailcow:staging' into staging 2022-03-20 22:04:46 +01:00
FreddleSpl0it
161130c116 [Web] Fix missing rspamd description (#4512)
* [Web] fix missing rspamd description

* [Web] fix missing rspamd description
2022-03-19 23:21:00 +01:00
Perry Toone
a03b8f28ae Update lang.en.json (#4511)
* Update lang.en.json

Minor grammar correction in whitelist area.

* Update lang.en.json

Co-authored-by: Peter <magic@kthx.at>
2022-03-19 23:12:21 +01:00
FreddleSpl0it
6d3798ad08 [Web] fix yubi otp 2022-03-19 20:18:31 +01:00
FreddleSpl0it
70921b8d15 [Web] tfa extra debugging 2022-03-18 08:45:02 +01:00
FreddleSpl0it
b185f83fc3 [Web] tfa extra debugging 2022-03-18 08:37:22 +01:00
Niklas Meyer
bb9ae02ccc Merge branch 'mailcow:staging' into staging 2022-03-17 22:56:23 +01:00
FreddleSpl0it
60af295c0a Merge branch 'selection-tfa' of https://github.com/FreddleSpl0it/mailcow-dockerized into selection-tfa 2022-03-14 10:32:55 +01:00
FreddleSpl0it
e7fe52a625 [Web] increase mysql publicKey field length 2022-03-14 10:31:59 +01:00
FreddleSpl0it
49c506eed9 [Web] multiple tfa - user support 2022-03-14 10:31:59 +01:00
FreddleSpl0it
21fadf6df2 [Web] multiple tfa - domainadmin support 2022-03-14 10:31:58 +01:00
FreddleSpl0it
5fcccbc97d [Web] add verify selected tfa 2022-03-14 10:31:56 +01:00
FreddleSpl0it
3ef2b6cfa2 [Web] add verify selected tfa 2022-03-14 10:31:51 +01:00
FreddleSpl0it
84b4269c75 [Web] increase mysql publicKey field length 2022-03-14 09:29:07 +01:00
FreddleSpl0it
a0c09af67e [Web] add github version tag - adjust css 2022-03-12 22:39:56 +01:00
FreddleSpl0it
a2d57d43d1 [Web] multiple tfa - user support 2022-03-07 11:41:13 +01:00
FreddleSpl0it
df33f1a130 [Web] multiple tfa - domainadmin support 2022-02-22 09:38:06 +01:00
FreddleSpl0it
4c6a2055c2 [Web] add verify selected tfa 2022-02-21 14:10:12 +01:00
FreddleSpl0it
f09a3df870 [Web] add verify selected tfa 2022-02-21 10:46:24 +01:00
El-Virus
ea1a412749 Fix missing "lbuchs", after resolving last conflict
It seems that when solving the conflict in my pr when the latest staging branch was merged to master, I accidentally deleted "lbuchs", I added it back
2022-01-21 15:46:44 +01:00
El-Virus
db82327d9a Merge branch 'staging' into master 2022-01-21 15:40:37 +01:00
El-Virus
ea1a02bd7d Fix "The operation is insecure." when trying to register fido2 device.
navigator.credentials.create(); Doesn't accept a port in the "id" parameter. So, when trying to register a fido2 device via WebAuthn throws: "The operation is insecure." on firefox and "The relying party ID is not a registrable domain suffix of, nor equal to the current domain." on Chrome or Edge.
This commit replaces `$_SERVER['HTTP_HOST']` with `$_SERVER['SERVER_NAME']` when initializing `$WebAuthn` which excludes the port to formulate correct requests.
Now Mailcow allows the registration of fido2 devices when running in a non-standard port(eg. 443).
2021-12-26 17:11:06 +01:00
144 changed files with 5893 additions and 1644 deletions

View File

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

View File

@@ -54,10 +54,11 @@ body:
| --- | --- |
| My operating system | I_DO_REPLY_HERE |
| Is Apparmor, SELinux or similar active? | I_DO_REPLY_HERE |
| Virtualization technlogy (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE |
| Virtualization technology (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE |
| Server/VM specifications (Memory, CPU Cores) | I_DO_REPLY_HERE |
| Docker Version (`docker version`) | I_DO_REPLY_HERE |
| Docker-Compose Version (`docker-compose version`) | I_DO_REPLY_HERE |
| Docker version (`docker version`) | I_DO_REPLY_HERE |
| docker-compose version (`docker-compose version`) | I_DO_REPLY_HERE |
| mailcow version (```git describe --tags `git rev-list --tags --max-count=1` ```) | I_DO_REPLY_HERE |
| Reverse proxy (custom solution) | I_DO_REPLY_HERE |
Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:

View File

@@ -0,0 +1,13 @@
## :memo: Brief description
<!-- Diff summary - START -->
<!-- Diff summary - END -->
## :computer: Commits
<!-- Diff commits - START -->
<!-- Diff commits - END -->
## :file_folder: Modified files
<!-- Diff files - START -->
<!-- Diff files - END -->

View File

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

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

@@ -0,0 +1,45 @@
name: Build mailcow Docker Images
on:
push:
branches: [ "master", "staging" ]
workflow_dispatch:
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
docker_image_builds:
strategy:
matrix:
images:
- "acme-mailcow"
- "clamd-mailcow"
- "dockerapi-mailcow"
- "dovecot-mailcow"
- "netfilter-mailcow"
- "olefy-mailcow"
- "php-fpm-mailcow"
- "postfix-mailcow"
- "rspamd-mailcow"
- "sogo-mailcow"
- "solr-mailcow"
- "unbound-mailcow"
- "watchdog-mailcow"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Docker
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}
env:
image: ${{ matrix.images }}

63
.github/workflows/integration_tests.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
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'

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

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

View File

@@ -0,0 +1,17 @@
name: "Tweet trigger release"
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- 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-dockerized Release has been Released on GitHub! Checkout our GitHub Page for the latest Release: github.com/mailcow/mailcow-dockerized/releases/latest'

View File

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

View File

@@ -2,7 +2,8 @@
## We stand with 🇺🇦
[![master build status](https://img.shields.io/drone/build/mailcow/mailcow-dockerized/master?label=master%20build&server=https%3A%2F%2Fdrone.mailcow.email)](https://drone.mailcow.email/mailcow/mailcow-dockerized) [![staging build status](https://img.shields.io/drone/build/mailcow/mailcow-dockerized/staging?label=staging%20build&server=https%3A%2F%2Fdrone.mailcow.email)](https://drone.mailcow.email/mailcow/mailcow-dockerized) [![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/)
[![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)
## Want to support mailcow?

42
SECURITY.md Normal file
View File

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

0
create_cold_standby.sh Normal file → Executable file
View File

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"

View File

@@ -0,0 +1,3 @@
FROM debian:bullseye-slim
RUN apt update && apt install pigz

View File

@@ -1,76 +1,21 @@
FROM debian:bullseye-slim
FROM clamav/clamav:0.105.1_base
LABEL maintainer "André Peters <andre.peters@servercow.de>"
ARG CLAMAV=0.104.2
ARG TINI_VERSION=v0.19.0
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
build-essential \
pkg-config \
python3 \
python3-pip \
valgrind \
check \
libbz2-dev \
libcurl4-openssl-dev \
libjson-c-dev \
libmilter-dev \
libncurses5-dev \
libpcre2-dev \
libssl-dev \
libxml2-dev \
zlib1g-dev \
curl \
bash \
wget \
tzdata \
dnsutils \
RUN apk upgrade --no-cache \
&& apk add --update --no-cache \
rsync \
dos2unix \
netcat \
&& python3 -m pip install cmake \
&& rm -rf /var/lib/apt/lists/* \
&& wget -O - https://www.clamav.net/downloads/production/clamav-${CLAMAV}.tar.gz | tar xfvz - \
&& cd clamav-${CLAMAV} \
&& cmake . \
-D CMAKE_INSTALL_PREFIX=/usr \
-D CMAKE_INSTALL_LIBDIR=/usr/lib \
-D APP_CONFIG_DIRECTORY=/etc/clamav \
-D CMAKE_INSTALL_MANDIR=/usr/share/man \
-D CMAKE_INSTALL_INFODIR=/usr/share/info \
-D CLAMAV_USER=clamav \
-D CLAMAV_GROUP=clamav \
-D DATABASE_DIRECTORY=/var/lib/clamav \
-D ENABLE_APP=ON \
-D ENABLE_JSON_SHARED=OFF \
-D CMAKE_BUILD_TYPE=MinSizeRel \
&& cmake --build . -j4 \
&& cmake --build . --target install \
&& cd .. && rm -rf clamav-${CLAMAV} \
&& apt-get -y --auto-remove purge build-essential \
&& apt-get -y purge pkg-config \
python3 \
python3-pip \
valgrind \
check \
libbz2-dev \
libcurl4-openssl-dev \
libjson-c-dev \
libmilter-dev \
libncurses5-dev \
libpcre2-dev \
libssl-dev \
libxml2-dev \
zlib1g-dev \
bind-tools \
bash
&& addgroup --system --gid 700 clamav \
&& adduser --system --no-create-home --home /var/lib/clamav --uid 700 --gid 700 --disabled-login clamav \
&& rm -rf /tmp/* /var/tmp/*
COPY clamd.sh ./
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
# init
COPY clamd.sh /clamd.sh
RUN chmod +x /sbin/tini
CMD ["/sbin/tini", "-g", "--", "/clamd.sh"]
# healthcheck
COPY healthcheck.sh /healthcheck.sh
RUN chmod +x /healthcheck.sh
HEALTHCHECK --start-period=6m CMD "/healthcheck.sh"
ENTRYPOINT []
CMD ["/sbin/tini", "-g", "--", "/clamd.sh"]

View File

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

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"

View File

@@ -2,7 +2,7 @@ FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG DOVECOT=2.3.18
ARG DOVECOT=2.3.19.1
ENV LC_ALL C
ENV GOSU_VERSION 1.14

View File

@@ -307,6 +307,7 @@ namespace {
}
EOF
cat <<EOF > /etc/dovecot/sogo_trusted_ip.conf
# Autogenerated by mailcow
remote ${IPV4_NETWORK}.248 {
@@ -349,6 +350,14 @@ sievec /var/vmail/sieve/global_sieve_after.sieve
sievec /usr/lib/dovecot/sieve/report-spam.sieve
sievec /usr/lib/dovecot/sieve/report-ham.sieve
for file in /var/vmail/*/*/sieve/*.sieve ; do
if [[ "$file" == "/var/vmail/*/*/sieve/*.sieve" ]]; then
continue
fi
sievec "$file" "$(dirname "$file")/../.dovecot.svbin"
chown vmail:vmail "$(dirname "$file")/../.dovecot.svbin"
done
# Fix permissions
chown root:root /etc/dovecot/sql/*.conf
chown root:dovecot /etc/dovecot/sql/dovecot-dict-sql-sieve* /etc/dovecot/sql/dovecot-dict-sql-quota* /etc/dovecot/lua/passwd-verify.lua

View File

@@ -51,8 +51,8 @@ sub sig_handler {
die "sig_handler received signal, preparing to exit...\n";
};
open my $file, '<', "/etc/sogo/sieve.creds";
my $creds = <$file>;
open my $file, '<', "/etc/sogo/sieve.creds";
my $creds = <$file>;
close $file;
my ($master_user, $master_pass) = split /:/, $creds;
my $sth = $dbh->prepare("SELECT id,
@@ -166,11 +166,17 @@ while ($row = $sth->fetchrow_arrayref()) {
$success = 1;
}
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
$keep_job_active = 1;
if (defined $exit_status && $exit_status eq "EXIT_AUTHENTICATION_FAILURE_USER1") {
$keep_job_active = 0;
}
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ?, active = ? WHERE id = ?");
$update->bind_param( 1, ${stdout} );
$update->bind_param( 2, ${success} );
$update->bind_param( 3, ${exit_status} );
$update->bind_param( 4, ${id} );
$update->bind_param( 4, ${keep_job_active} );
$update->bind_param( 5, ${id} );
$update->execute();
} catch {
$update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");

View File

@@ -50,7 +50,7 @@ try:
def query_mysql(query, headers = True, update = False):
while True:
try:
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8")
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8mb4", collation="utf8mb4_general_ci")
except Exception as ex:
print('%s - trying again...' % (ex))
time.sleep(3)
@@ -166,4 +166,4 @@ try:
notify_rcpt(record['rcpt'], record['counter'], record['quarantine_acl'], attrs['quarantine_category'])
finally:
os.unlink(pidfile)
os.unlink(pidfile)

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ENV XTABLES_LIBDIR /usr/lib/xtables

View File

@@ -94,7 +94,7 @@ def refreshF2bregex():
f2bregex = {}
f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
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\.:]+),'
@@ -252,7 +252,7 @@ def permBan(net, unban=False):
if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule)
@@ -267,7 +267,7 @@ def permBan(net, unban=False):
if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule)
@@ -346,6 +346,8 @@ def snat4(snat_target):
rule.dst = '!' + rule.src
target = rule.create_target("SNAT")
target.to_source = snat_target
match = rule.create_match("comment")
match.comment = f'{int(round(time.time()))}'
return rule
while not quit_now:
@@ -356,19 +358,26 @@ def snat4(snat_target):
table.refresh()
chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False
if get_snat4_rule() not in chain.rules:
logCrit('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat4_rule().src, snat_target))
chain.insert_rule(get_snat4_rule())
table.commit()
else:
for position, item in enumerate(chain.rules):
if item == get_snat4_rule():
if position != 0:
chain.delete_rule(get_snat4_rule())
table.commit()
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)
table.commit()
table.autocommit = True
except:
print('Error running SNAT4, retrying...')
print('Error running SNAT4, retrying...')
def snat6(snat_target):
global lock
@@ -402,7 +411,7 @@ def snat6(snat_target):
table.commit()
table.autocommit = True
except:
print('Error running SNAT6, retrying...')
print('Error running SNAT6, retrying...')
def autopurge():
while not quit_now:
@@ -468,7 +477,7 @@ def whitelistUpdate():
if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate():
global quit_now
@@ -479,7 +488,7 @@ def blacklistUpdate():
new_blacklist = []
if list:
new_blacklist = genNetworkList(list)
if Counter(new_blacklist) != Counter(BLACKLIST):
if Counter(new_blacklist) != Counter(BLACKLIST):
addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist
@@ -490,7 +499,7 @@ def blacklistUpdate():
if delban:
for net in delban:
permBan(net=net, unban=True)
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def initChain():
# Is called before threads start, no locking

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
WORKDIR /app

View File

@@ -1,12 +1,12 @@
FROM php:8.0-fpm-alpine3.14
FROM php:8.0-fpm-alpine3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ENV APCU_PECL 5.1.20
ENV IMAGICK_PECL 3.5.1
ENV APCU_PECL 5.1.21
ENV IMAGICK_PECL 3.7.0
# Mailparse is pulled from master branch
#ENV MAILPARSE_PECL 3.0.2
ENV MEMCACHED_PECL 3.1.5
ENV REDIS_PECL 5.3.4
ENV MEMCACHED_PECL 3.2.0
ENV REDIS_PECL 5.3.7
RUN apk add -U --no-cache autoconf \
aspell-dev \

View File

@@ -1,4 +1,4 @@
FROM debian:buster-slim
FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive

View File

@@ -323,7 +323,19 @@ hosts = unix:/var/run/mysqld/mysqld.sock
dbname = ${DBNAME}
# First select queries domain and alias_domain to determine if domains are active.
query = SELECT goto FROM alias
WHERE address='%s'
WHERE id IN (
SELECT COALESCE (
(
SELECT id FROM alias
WHERE address='%s'
AND (active='1' OR active='2')
), (
SELECT id FROM alias
WHERE address='@%d'
AND (active='1' OR active='2')
)
)
)
AND active='1'
AND (domain IN
(SELECT domain FROM domain
@@ -354,7 +366,7 @@ query = SELECT goto FROM alias
WHERE alias_domain.alias_domain = '%d'
AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
AND (mailbox.active = '1' OR mailbox.active ='2')
AND alias_domain.active='1'
AND alias_domain.active='1';
EOF
# MX based routing

View File

@@ -1,4 +1,4 @@
@version: 3.19
@version: 3.28
@include "scl.conf"
options {
chain_hostnames(off);

View File

@@ -1,4 +1,4 @@
@version: 3.19
@version: 3.28
@include "scl.conf"
options {
chain_hostnames(off);

View File

@@ -2,7 +2,7 @@ FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
ENV LC_ALL C
ENV GOSU_VERSION 1.14
@@ -30,7 +30,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
&& gosu nobody true \
&& mkdir /usr/share/doc/sogo \
&& touch /usr/share/doc/sogo/empty.sh \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-key 0x810273C4 \
&& apt-key adv --keyserver keys.openpgp.org --recv-key 74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 \
&& echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \
&& apt-get update && apt-get install -y --no-install-recommends \
sogo \
@@ -52,4 +52,4 @@ RUN chmod +x /bootstrap-sogo.sh \
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf

View File

@@ -142,6 +142,10 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_acl</string>
<key>SOGoIMAPServer</key>
<string>imap://${IPV4_NETWORK}.250:143/?TLS=YES&amp;tlsVerifyMode=none</string>
<key>SOGoSieveServer</key>
<string>sieve://${IPV4_NETWORK}.250:4190/?TLS=YES&amp;tlsVerifyMode=none</string>
<key>SOGoSMTPServer</key>
<string>smtp://${IPV4_NETWORK}.253:588/?TLS=YES&amp;tlsVerifyMode=none</string>
<key>SOGoTrustProxyAuthentication</key>
<string>YES</string>
<key>SOGoEncryptionKey</key>

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.16
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"

View File

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

View File

@@ -65,7 +65,7 @@
}
location ~ ^/api/v1/(.*)$ {
try_files $uri $uri/ /json_api.php?query=$1;
try_files $uri $uri/ /json_api.php?query=$1&$args;
}
location ^~ /.well-known/acme-challenge/ {
@@ -163,7 +163,9 @@
proxy_connect_timeout 75;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_buffers 64 256k;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
@@ -197,6 +199,9 @@
proxy_set_header x-webobjects-server-name $server_name;
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
proxy_set_header x-webobjects-server-port $server_port;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
client_body_buffer_size 128k;

View File

@@ -1,53 +1,63 @@
# Whitelist generated by Postwhite v3.4 on Sun Dec 15 21:16:19 CET 2019
# Whitelist generated by Postwhite v3.4 on Mon 21 Mar 2022 06:50:26 PM CET
# https://github.com/stevejenkins/postwhite/
# 1928 total rules
# 1898 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
2a02:a60:0:5::/64 permit
2c0f:fb50:4000::/36 permit
3.93.157.0/24 permit
8.20.114.31 permit
8.25.194.0/23 permit
8.25.196.0/23 permit
8.39.54.0/23 permit
8.40.222.0/23 permit
8.45.169.0/24 permit
12.130.86.238 permit
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.216.0/22 permit
13.110.224.0/20 permit
13.111.0.0/16 permit
13.111.0.0/22 permit
13.111.52.0/22 permit
13.111.63.0/24 permit
13.111.68.0/24 permit
13.111.72.0/22 permit
13.111.92.0/24 permit
13.111.111.0/24 permit
17.36.0.0/16 permit
17.41.0.0/16 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.111.110.0/23 permit
17.120.0.0/16 permit
17.133.0.0/16 permit
17.139.0.0/16 permit
17.142.0.0/15 permit
17.151.1.0/24 permit
17.158.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.194.95.56 permit
18.208.124.128/25 permit
18.198.96.88 permit
20.47.149.138 permit
20.48.0.0/12 permit
20.52.52.2 permit
20.52.128.133 permit
20.63.210.192/28 permit
20.64.0.0/10 permit
20.94.180.64/28 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
23.23.237.213 permit
23.103.131.7 permit
20.192.0.0/10 permit
23.100.85.1 permit
23.103.224.0/19 permit
23.249.208.0/20 permit
23.251.224.0/19 permit
23.253.141.0/24 permit
23.253.182.0/23 permit
23.253.182.103 permit
23.253.183.145 permit
@@ -68,11 +78,11 @@
27.123.206.56/29 permit
27.123.206.76/30 permit
27.123.206.80/28 permit
27.126.146.0/24 permit
34.200.123.20 permit
34.194.25.167 permit
34.194.144.120 permit
34.212.163.75 permit
34.213.104.127 permit
34.225.212.172 permit
34.247.168.44 permit
35.176.132.251 permit
35.190.247.0/24 permit
35.191.0.0/16 permit
@@ -80,7 +90,10 @@
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
@@ -91,18 +104,20 @@
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.201.0/24 permit
41.74.204.0/23 permit
41.74.205.0/24 permit
41.74.206.0/24 permit
42.159.163.81 permit
42.159.163.82 permit
42.159.163.83 permit
46.19.168.0/23 permit
43.228.184.0/22 permit
46.226.48.0/21 permit
46.228.36.37 permit
46.228.36.38/31 permit
@@ -160,26 +175,19 @@
50.18.125.97 permit
50.18.125.237 permit
50.18.126.162 permit
50.23.218.192/27 permit
50.31.32.0/19 permit
50.31.36.197 permit
50.31.36.199 permit
50.31.36.205 permit
50.31.36.208 permit
50.31.36.213 permit
50.31.44.111 permit
50.31.57.54/31 permit
50.31.57.60 permit
50.31.57.61 permit
50.31.57.62 permit
50.31.60.1 permit
50.31.156.96/27 permit
50.31.205.0/24 permit
50.207.218.237 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
51.163.158.0/24 permit
51.163.159.0/24 permit
52.0.20.102 permit
51.163.159.21 permit
52.5.230.59 permit
52.27.5.72 permit
52.27.28.47 permit
@@ -190,10 +198,15 @@
52.41.64.145 permit
52.60.41.5 permit
52.60.115.116 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.100.0.0/14 permit
52.128.40.0/21 permit
52.119.213.144/28 permit
52.160.39.140 permit
52.165.175.144 permit
52.185.106.240/28 permit
52.200.59.0/24 permit
52.205.61.79 permit
52.207.191.216 permit
@@ -201,26 +214,30 @@
52.222.73.83 permit
52.222.73.120 permit
52.222.75.85 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.173.229.38 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.194.61.95 permit
54.195.113.45 permit
54.214.39.184 permit
54.216.77.168 permit
54.240.0.0/18 permit
54.240.40.0/25 permit
54.240.56.128/26 permit
54.240.63.0/25 permit
54.240.64.0/19 permit
54.240.96.0/19 permit
54.241.16.209 permit
54.243.205.80 permit
54.244.54.130 permit
54.244.242.0/24 permit
54.246.232.180 permit
62.13.128.0/24 permit
62.13.129.128/25 permit
62.13.136.0/22 permit
@@ -231,9 +248,9 @@
62.13.152.0/23 permit
62.17.146.128/26 permit
62.140.7.0/24 permit
62.140.10.0/24 permit
62.140.10.21 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
@@ -241,9 +258,11 @@
64.20.241.45 permit
64.34.47.128/27 permit
64.34.57.192/26 permit
64.71.149.160/28 permit
64.79.155.0/24 permit
64.79.155.192 permit
64.89.45.192/30 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
@@ -265,21 +284,21 @@
64.207.219.7 permit
64.207.219.8 permit
64.207.219.9 permit
64.207.219.10 permit
64.207.219.11 permit
64.207.219.12 permit
64.207.219.13 permit
64.207.219.14 permit
64.207.219.15 permit
64.207.219.71 permit
64.207.219.72 permit
64.207.219.73 permit
64.207.219.74 permit
64.207.219.75 permit
64.207.219.76 permit
64.207.219.77 permit
64.207.219.78 permit
64.207.219.79 permit
64.207.219.135 permit
64.207.219.136 permit
64.207.219.137 permit
64.207.219.138 permit
64.207.219.139 permit
64.207.219.140 permit
64.207.219.141 permit
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
@@ -288,7 +307,6 @@
65.54.51.64/26 permit
65.54.61.64/26 permit
65.54.121.120/29 permit
65.54.121.124/31 permit
65.54.190.0/24 permit
65.54.241.0/24 permit
65.55.29.77 permit
@@ -298,7 +316,6 @@
65.55.52.224/27 permit
65.55.78.128/25 permit
65.55.81.48/28 permit
65.55.81.54/31 permit
65.55.90.0/24 permit
65.55.94.0/25 permit
65.55.111.0/24 permit
@@ -325,9 +342,6 @@
66.111.4.225 permit
66.111.4.229 permit
66.111.4.230 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
@@ -358,7 +372,8 @@
66.196.81.232/31 permit
66.196.81.234 permit
66.211.168.230/31 permit
66.211.184.0/23 permit
66.211.170.86/31 permit
66.211.170.88/30 permit
66.218.74.64/30 permit
66.218.74.68/31 permit
66.218.75.112/30 permit
@@ -420,9 +435,7 @@
67.221.168.65 permit
67.228.2.24/30 permit
67.228.21.184/29 permit
67.228.34.32/27 permit
67.228.37.4/30 permit
67.228.50.54/31 permit
67.231.145.42 permit
67.231.153.30 permit
68.142.230.0/24 permit
@@ -432,17 +445,6 @@
68.142.230.72/30 permit
68.142.230.76/31 permit
68.142.230.78 permit
68.232.131.164 permit
68.232.131.172 permit
68.232.131.183 permit
68.232.131.185 permit
68.232.143.44 permit
68.232.145.216 permit
68.232.148.56 permit
68.232.148.128 permit
68.232.148.138 permit
68.232.157.60 permit
68.232.157.143 permit
68.232.192.0/20 permit
69.63.178.128/25 permit
69.63.181.0/24 permit
@@ -456,9 +458,9 @@
69.171.232.0/24 permit
69.171.244.0/23 permit
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
@@ -523,8 +525,10 @@
72.32.154.0/24 permit
72.32.217.0/24 permit
72.32.243.0/24 permit
72.34.168.75 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
@@ -536,9 +540,6 @@
74.6.133.0/24 permit
74.6.134.0/24 permit
74.6.135.0/24 permit
74.63.63.115 permit
74.63.63.121 permit
74.63.194.126 permit
74.63.212.0/24 permit
74.63.234.75 permit
74.63.236.0/24 permit
@@ -557,17 +558,9 @@
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
75.126.253.48 permit
76.223.176.0/24 permit
76.223.180.0/23 permit
76.223.188.0/24 permit
76.223.189.0/24 permit
76.223.190.0/24 permit
76.223.176.0/20 permit
77.238.176.0/22 permit
77.238.176.0/24 permit
77.238.177.0/24 permit
@@ -590,13 +583,11 @@
77.238.189.146/31 permit
77.238.189.148/30 permit
81.223.46.0/27 permit
82.165.159.0/24 permit
82.165.159.0/26 permit
82.165.229.130 permit
82.165.230.22 permit
84.16.77.1 permit
85.158.136.0/21 permit
86.61.88.25 permit
87.198.219.130 permit
87.198.219.153 permit
87.238.80.0/21 permit
87.248.103.12 permit
87.248.103.21 permit
@@ -633,11 +624,9 @@
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.211.243.0/24 permit
91.220.42.0/24 permit
94.236.119.0/26 permit
94.245.112.0/27 permit
@@ -649,7 +638,6 @@
96.43.148.64/28 permit
96.43.148.64/31 permit
96.43.151.64/28 permit
96.46.150.192/27 permit
98.136.44.181 permit
98.136.44.182/31 permit
98.136.44.184 permit
@@ -1152,20 +1140,25 @@
98.139.245.180/31 permit
98.139.245.208/30 permit
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.96.20.0/24 permit
103.96.22.0/24 permit
103.47.204.0/22 permit
103.96.21.0/24 permit
103.96.23.0/24 permit
103.151.192.0/23 permit
103.237.104.0/22 permit
104.43.243.237 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
@@ -1291,6 +1284,7 @@
106.10.242.0/24 permit
106.10.243.0/24 permit
106.10.244.0/24 permit
106.39.212.64/29 permit
106.50.16.0/28 permit
108.174.0.0/24 permit
108.174.0.215 permit
@@ -1302,13 +1296,14 @@
108.175.30.45 permit
108.177.8.0/21 permit
108.177.96.0/19 permit
108.178.6.0/24 permit
109.237.142.0/24 permit
111.221.23.128/25 permit
111.221.26.0/27 permit
111.221.66.0/25 permit
111.221.69.128/25 permit
111.221.112.0/21 permit
112.19.199.64/29 permit
112.19.242.64/29 permit
116.214.12.0/24 permit
116.214.12.47 permit
116.214.12.48/31 permit
@@ -1325,6 +1320,7 @@
117.120.16.0/21 permit
119.42.242.52/31 permit
119.42.242.156 permit
123.126.78.64/29 permit
124.47.150.0/24 permit
124.47.189.0/24 permit
124.108.96.0/24 permit
@@ -1332,11 +1328,19 @@
124.108.96.28/31 permit
124.108.96.70/31 permit
124.108.96.72/31 permit
128.17.0.0/20 permit
128.17.64.0/20 permit
128.17.128.0/20 permit
128.17.192.0/20 permit
128.127.70.0/26 permit
128.245.0.0/20 permit
128.245.64.0/20 permit
129.41.77.70 permit
129.41.169.249 permit
129.146.236.58 permit
129.153.194.228 permit
129.159.87.137 permit
130.61.9.72 permit
130.61.68.235 permit
130.211.0.0/22 permit
130.248.172.0/24 permit
130.248.173.0/24 permit
@@ -1345,8 +1349,10 @@
131.253.121.0/26 permit
131.253.121.20 permit
131.253.121.52 permit
132.145.11.129 permit
132.145.13.209 permit
132.226.26.225 permit
132.226.49.32 permit
132.226.56.24 permit
134.170.27.8 permit
134.170.113.0/26 permit
134.170.141.64/26 permit
@@ -1356,21 +1362,27 @@
135.84.82.0/24 permit
135.84.216.0/22 permit
136.143.182.0/23 permit
136.143.188.0/23 permit
136.143.184.0/24 permit
136.143.188.0/24 permit
136.147.128.0/20 permit
136.147.135.0/24 permit
136.147.176.0/20 permit
136.147.176.0/24 permit
136.147.182.0/24 permit
138.91.172.26 permit
139.60.152.0/22 permit
139.178.64.159 permit
139.178.64.195 permit
139.180.17.0/24 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
144.178.36.0/24 permit
144.178.38.0/24 permit
146.20.112.0/26 permit
146.20.113.0/24 permit
146.20.191.0/24 permit
146.88.28.0/24 permit
146.20.215.0/24 permit
146.101.78.0/24 permit
147.75.65.173 permit
147.75.65.174 permit
@@ -1384,10 +1396,7 @@
148.105.0.14 permit
148.105.8.0/21 permit
149.72.0.0/16 permit
151.101.1.140 permit
151.101.65.140 permit
151.101.129.140 permit
151.101.193.140 permit
152.67.105.195 permit
157.55.0.192/26 permit
157.55.1.128/26 permit
157.55.2.0/25 permit
@@ -1397,6 +1406,7 @@
157.55.61.0/24 permit
157.55.157.128/25 permit
157.55.225.0/25 permit
157.55.254.216 permit
157.56.24.0/25 permit
157.56.120.128/26 permit
157.56.232.0/21 permit
@@ -1405,21 +1415,26 @@
157.58.196.96/29 permit
157.58.249.3 permit
157.151.208.65 permit
158.247.16.0/20 permit
157.255.1.64/29 permit
159.92.157.0/24 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.135.132.128/25 permit
159.135.140.80/29 permit
159.135.224.0/20 permit
161.38.192.0/22 permit
161.38.196.0/22 permit
161.71.32.0/21 permit
159.183.0.0/16 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
162.248.184.121 permit
162.248.184.122 permit
162.248.185.121 permit
162.248.185.122 permit
162.248.186.121 permit
162.248.186.122 permit
163.47.180.0/22 permit
163.47.180.0/23 permit
163.114.130.16 permit
163.114.132.120 permit
166.78.68.0/22 permit
166.78.68.221 permit
166.78.69.146 permit
@@ -1427,16 +1442,7 @@
166.78.69.170 permit
166.78.71.131 permit
167.89.0.0/17 permit
167.89.2.4 permit
167.89.22.44 permit
167.89.25.84 permit
167.89.31.192/29 permit
167.89.32.5 permit
167.89.32.50 permit
167.89.46.159 permit
167.89.46.185 permit
167.89.60.95 permit
167.89.62.118 permit
167.89.64.9 permit
167.89.65.0 permit
167.89.65.53 permit
@@ -1448,22 +1454,15 @@
167.89.75.164 permit
167.89.101.2 permit
167.89.101.192/28 permit
167.89.107.125 permit
167.89.107.127 permit
167.89.107.129 permit
167.89.107.136 permit
167.216.129.170 permit
167.216.129.182/31 permit
167.216.129.184/29 permit
167.216.129.192/29 permit
167.216.129.200 permit
167.216.129.205 permit
167.216.129.206/31 permit
167.216.129.208/31 permit
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.245.0.0/17 permit
170.10.68.0/22 permit
170.10.129.0/24 permit
170.10.133.0/24 permit
172.217.0.0/19 permit
172.217.32.0/20 permit
172.217.128.0/19 permit
@@ -1473,8 +1472,6 @@
172.253.112.0/20 permit
173.0.84.224/27 permit
173.0.94.244/30 permit
173.193.132.134/31 permit
173.193.210.32/27 permit
173.194.0.0/16 permit
173.203.79.182 permit
173.203.81.39 permit
@@ -1482,7 +1479,6 @@
173.224.160.188 permit
173.224.161.128/25 permit
173.228.155.0/24 permit
173.236.20.0/24 permit
174.36.84.8/29 permit
174.36.84.16/29 permit
174.36.84.32/29 permit
@@ -1494,30 +1490,25 @@
174.36.114.148/30 permit
174.36.114.152/29 permit
174.37.67.28/30 permit
174.37.226.64/27 permit
174.129.194.241 permit
174.129.203.189 permit
174.137.46.0/24 permit
176.32.105.0/24 permit
176.32.127.0/24 permit
178.236.10.128/26 permit
180.189.28.0/24 permit
182.50.76.0/22 permit
182.50.78.64/28 permit
184.173.105.0/24 permit
184.173.153.0/24 permit
185.4.120.0/24 permit
185.4.122.0/24 permit
183.240.219.64/29 permit
185.12.80.0/22 permit
185.28.196.0/22 permit
185.58.84.0/24 permit
185.58.87.0/24 permit
185.58.84.93 permit
185.58.85.0/24 permit
185.58.86.0/24 permit
185.72.128.75 permit
185.72.128.76 permit
185.72.128.80 permit
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
@@ -1577,7 +1568,6 @@
192.64.236.0/24 permit
192.64.237.0/24 permit
192.64.238.0/24 permit
192.92.97.0/24 permit
192.161.144.0/20 permit
192.162.87.0/24 permit
192.237.158.0/23 permit
@@ -1589,37 +1579,34 @@
192.254.113.10 permit
192.254.113.101 permit
192.254.114.176 permit
192.254.115.72 permit
192.254.118.63 permit
192.254.127.96/27 permit
193.7.206.0/25 permit
193.7.207.0/25 permit
193.109.254.0/23 permit
194.64.234.128/27 permit
193.122.128.100 permit
194.64.234.129 permit
194.104.109.0/24 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.54.172.0/23 permit
195.130.217.0/24 permit
195.234.109.226 permit
195.245.230.0/23 permit
198.2.128.0/18 permit
198.2.128.0/24 permit
198.2.132.0/22 permit
198.2.136.0/23 permit
198.2.145.0/24 permit
198.2.177.0/24 permit
198.2.178.0/24 permit
198.2.179.0/24 permit
198.2.178.0/23 permit
198.2.180.0/24 permit
198.2.186.0/23 permit
198.21.0.0/21 permit
198.21.3.166 permit
198.21.4.224 permit
198.37.144.0/20 permit
198.37.145.250 permit
198.37.146.118/31 permit
198.37.149.128 permit
198.37.151.26 permit
198.37.152.186 permit
198.61.254.0/23 permit
198.61.254.231 permit
198.74.56.28 permit
198.178.234.57 permit
198.245.80.0/20 permit
198.245.81.0/24 permit
@@ -1636,18 +1623,15 @@
199.122.120.0/21 permit
199.122.123.0/24 permit
199.127.232.0/22 permit
199.201.64.23 permit
199.201.65.23 permit
199.255.192.0/22 permit
202.129.242.0/23 permit
202.165.102.47 permit
202.177.148.100 permit
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
@@ -1680,32 +1664,30 @@
203.188.201.12/30 permit
203.209.230.75 permit
203.209.230.76/31 permit
204.2.193.0/29 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.120.0/23 permit
204.153.121.0/24 permit
204.232.168.0/24 permit
205.139.110.0/24 permit
205.139.111.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.179.17 permit
205.251.233.32 permit
205.251.233.36 permit
206.25.247.143 permit
@@ -1727,6 +1709,8 @@
207.46.132.128/27 permit
207.46.198.0/25 permit
207.46.200.0/27 permit
207.46.225.107 permit
207.58.147.64/28 permit
207.67.38.0/24 permit
207.67.98.192/27 permit
207.68.176.0/26 permit
@@ -1734,7 +1718,8 @@
207.82.80.0/24 permit
207.126.144.0/20 permit
207.171.160.0/19 permit
207.211.30.0/24 permit
207.211.30.64/26 permit
207.211.30.128/25 permit
207.211.31.0/25 permit
207.211.41.113 permit
207.218.90.0/24 permit
@@ -1743,7 +1728,7 @@
208.43.21.28/30 permit
208.43.21.64/29 permit
208.43.21.72/30 permit
208.43.239.136/30 permit
208.46.212.80 permit
208.46.212.208/31 permit
208.46.212.210 permit
208.64.132.0/22 permit
@@ -1773,13 +1758,13 @@
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.122.246 permit
208.82.236.96/28 permit
208.82.237.96/28 permit
208.82.238.96/28 permit
208.82.237.96/29 permit
208.82.237.104/31 permit
208.82.238.96/29 permit
208.82.238.104/31 permit
208.85.50.137 permit
208.117.48.0/20 permit
208.185.229.45 permit
@@ -1792,10 +1777,10 @@
209.67.98.59 permit
209.85.128.0/17 permit
212.4.136.0/26 permit
212.25.240.75 permit
212.25.240.76 permit
212.25.240.80 permit
212.25.240.83 permit
212.25.240.84 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
@@ -1836,13 +1821,8 @@
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.165.64.0/23 permit
213.167.75.0/24 permit
213.167.81.0/24 permit
213.167.75.0/25 permit
213.167.81.0/25 permit
213.199.128.139 permit
213.199.128.145 permit
213.199.138.181 permit
@@ -1851,6 +1831,7 @@
213.199.177.0/26 permit
216.17.150.242 permit
216.17.150.251 permit
216.22.15.224/27 permit
216.24.224.0/20 permit
216.39.60.0/23 permit
216.39.60.154/31 permit
@@ -1877,17 +1858,9 @@
216.39.62.60/31 permit
216.39.62.136/29 permit
216.39.62.144/31 permit
216.46.168.197 permit
216.46.168.222 permit
216.52.185.88/29 permit
216.46.168.0/24 permit
216.58.192.0/19 permit
216.66.217.240/29 permit
216.71.96.0/22 permit
216.71.152.175 permit
216.71.152.207 permit
216.71.154.29 permit
216.71.155.88 permit
216.71.155.89 permit
216.74.162.13 permit
216.74.162.14 permit
216.82.240.0/20 permit
@@ -1897,9 +1870,6 @@
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
@@ -1909,14 +1879,13 @@
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.193.0/24 permit
217.175.194.0/23 permit
217.175.196.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:4860:4000::/36 permit
2404:6800:4000::/36 permit
2607:f8b0:4000::/36 permit
@@ -1925,6 +1894,7 @@
2620:109:c006:104::215 permit
2620:109:c006:104::/64 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:119:50c0:207::/64 permit

View File

@@ -18,6 +18,9 @@ symbols {
"ENCRYPTED_CHAT" {
score = -20.0;
}
"SOGO_CONTACT" {
score = -99.0;
}
}
group "MX" {

View File

@@ -1,24 +0,0 @@
rules {
"LONG" {
train {
max_trains = 200;
max_usages = 20;
max_iterations = 25;
learning_rate = 0.01,
}
symbol_spam = "NEURAL_SPAM_LONG";
symbol_ham = "NEURAL_HAM_LONG";
ann_expire = 45d;
}
"SHORT" {
train {
max_trains = 100;
max_usages = 10;
max_iterations = 15;
learning_rate = 0.01,
}
symbol_spam = "NEURAL_SPAM_SHORT";
symbol_ham = "NEURAL_HAM_SHORT";
ann_expire = 7d;
}
}

View File

@@ -1,18 +0,0 @@
symbols = {
"NEURAL_SPAM_LONG" {
weight = 3.7; # sample weight
description = "Neural network spam (long)";
}
"NEURAL_HAM_LONG" {
weight = -4.0; # sample weight
description = "Neural network ham (long)";
}
"NEURAL_SPAM_SHORT" {
weight = 2.5; # sample weight
description = "Neural network spam (short)";
}
"NEURAL_HAM_SHORT" {
weight = -2.0; # sample weight
description = "Neural network ham (short)";
}
}

View File

@@ -32,8 +32,6 @@
// );
// self-signed is not trusted anymore
SOGoSieveServer = "sieve://dovecot:4190/?TLS=YES&tlsVerifyMode=none";
SOGoSMTPServer = "smtp://postfix:588/?TLS=YES&tlsVerifyMode=none";
WOPort = "0.0.0.0:20000";
SOGoMemcachedHost = "memcached";

16
data/web/api/index.css Normal file
View File

@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

View File

@@ -5,56 +5,15 @@
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/api/openapi.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
// End Swagger UI call region
window.ui = ui;
};
</script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@@ -13,7 +13,7 @@
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
@@ -38,7 +38,7 @@
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
@@ -58,7 +58,7 @@
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
@@ -67,9 +67,13 @@
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

View File

@@ -209,10 +209,17 @@ paths:
- app_passwd
- add
- active: "1"
app_name: emclient
username: info@domain.tld
app_name: wordpress
app_passwd: keyleudecticidechothistishownsan31
app_passwd2: keyleudecticidechothistishownsan31
username: hello@mailcow.email
protocols:
- imap_access
- dav_access
- smtp_access
- eas_access
- pop3_access
- sieve_access
msg: app_passwd_added
type: success
schema:
@@ -249,6 +256,13 @@ paths:
app_name: wordpress
app_passwd: keyleudecticidechothistishownsan31
app_passwd2: keyleudecticidechothistishownsan31
protocols:
- imap_access
- dav_access
- smtp_access
- eas_access
- pop3_access
- sieve_access
properties:
active:
description: is alias active or not
@@ -497,27 +511,30 @@ paths:
relay_all_recipients: "0"
rl_frame: s
rl_value: "10"
tags: ["tag1", "tag2"]
- null
msg:
- domain_added
- domain.tld
type: success
schema:
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
type: object
type: array
items:
type: object
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
description: OK
headers: {}
tags:
@@ -544,6 +561,7 @@ paths:
rl_frame: s
rl_value: "10"
restart_sogo: "10"
tags: ["tag1", "tag2"]
properties:
active:
description: is domain active or not
@@ -563,6 +581,11 @@ paths:
domain:
description: Fully qualified domain name
type: string
gal:
description: >-
is domain global address list active or not, it enables
shared contacts accross domain in SOGo webmail
type: boolean
mailboxes:
description: limit count of mailboxes associated with this domain
type: number
@@ -580,6 +603,9 @@ paths:
if not, them you have to create "dummy" mailbox for each
address to relay
type: boolean
relay_unknown_only:
description: Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.
type: boolean
rl_frame:
enum:
- s
@@ -590,6 +616,11 @@ paths:
rl_value:
description: rate limit value
type: number
tags:
description: tags for this Domain
type: array
items:
type: string
type: object
summary: Create domain
/api/v1/add/domain-admin:
@@ -1010,6 +1041,7 @@ paths:
force_pw_update: "1"
tls_enforce_in: "1"
tls_enforce_out: "1"
tags: ["tag1", "tag2"]
- null
msg:
- mailbox_added
@@ -1054,6 +1086,7 @@ paths:
force_pw_update: "1"
tls_enforce_in: "1"
tls_enforce_out: "1"
tags: ["tag1", "tag2"]
properties:
active:
description: is mailbox active or not
@@ -1934,21 +1967,23 @@ paths:
- domain2.tld
type: success
schema:
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
type: object
type: array
items:
type: object
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
description: OK
headers: {}
tags:
@@ -1959,14 +1994,15 @@ paths:
content:
application/json:
schema:
type: object
example:
- domain.tld
- domain2.tld
properties:
items:
description: contains list of domains you want to delete
type: object
type: object
items:
type: array
items:
type: string
summary: Delete domain
/api/v1/delete/domain-admin:
post:
@@ -2716,6 +2752,140 @@ paths:
type: object
type: object
summary: Delete Transport Maps
"/api/v1/delete/mailbox/tag/{mailbox}":
post:
parameters:
- description: name of mailbox
in: path
name: mailbox
example: info@domain.tld
required: true
schema:
type: string
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
- log:
- mailbox
- delete
- tags_mailbox
- tags:
- tag1
- tag2
mailbox: info@domain.tld
- null
msg:
- mailbox_modified
- info@domain.tld
type: success
schema:
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
type: object
description: OK
headers: {}
tags:
- Mailboxes
description: You can delete one or more mailbox tags.
operationId: Delete mailbox tags
requestBody:
content:
application/json:
schema:
example:
- tag1
- tag2
properties:
items:
description: contains list of mailboxes you want to delete
type: object
type: object
summary: Delete mailbox tags
"/api/v1/delete/domain/tag/{domain}":
post:
parameters:
- description: name of domain
in: path
name: domain
example: domain.tld
required: true
schema:
type: string
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
- log:
- mailbox
- delete
- tags_domain
- tags:
- tag1
- tag2
domain: domain.tld
- null
msg:
- domain_modified
- domain.tld
type: success
schema:
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
type: object
description: OK
headers: {}
tags:
- Domains
description: You can delete one or more domain tags.
operationId: Delete domain tags
requestBody:
content:
application/json:
schema:
example:
- tag1
- tag2
properties:
items:
description: contains list of domains you want to delete
type: object
type: object
summary: Delete domain tags
/api/v1/edit/alias:
post:
responses:
@@ -2820,23 +2990,25 @@ paths:
$ref: "#/components/responses/Unauthorized"
"200":
content:
"*/*":
application/json:
schema:
properties:
log:
description: contains request object
items: {}
type: array
msg:
items: {}
type: array
type:
enum:
- success
- danger
- error
type: string
type: object
type: array
items:
type: object
properties:
log:
type: array
description: contains request object
items: {}
msg:
type: array
items: {}
type:
enum:
- success
- danger
- error
type: string
description: OK
headers: {}
tags:
@@ -2865,6 +3037,7 @@ paths:
quota: "10240"
relay_all_recipients: "0"
relayhost: "2"
tags: ["tag3", "tag4"]
items: domain.tld
properties:
attr:
@@ -2903,13 +3076,33 @@ paths:
if not, them you have to create "dummy" mailbox for each
address to relay
type: boolean
relay_unknown_only:
description: Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.
type: boolean
relayhost:
description: id of relayhost
type: number
rl_frame:
enum:
- s
- m
- h
- d
type: string
rl_value:
description: rate limit value
type: number
tags:
description: tags for this Domain
type: array
items:
type: string
type: object
items:
description: contains list of domain names you want update
type: object
type: array
items:
type: string
type: object
summary: Update domain
/api/v1/edit/fail2ban:
@@ -3019,6 +3212,7 @@ paths:
sogo_access: "1"
username:
- info@domain.tld
tags: ["tag3", "tag4"]
- null
msg:
- mailbox_modified
@@ -3066,6 +3260,7 @@ paths:
- domain3.tld
- "*"
sogo_access: "1"
tags: ["tag3", "tag4"]
items:
- info@domain.tld
properties:
@@ -3793,6 +3988,13 @@ paths:
- all
- mailcow.tld
type: string
- description: comma seperated list of tags to filter by
example: "tag1,tag2"
in: query
name: tags
required: false
schema:
type: string
- description: e.g. api-key-string
example: api-key-string
in: header
@@ -3831,6 +4033,7 @@ paths:
relay_all_recipients: "0"
relayhost: "0"
rl: false
tags: ["tag1", "tag2"]
- active: "1"
aliases_in_domain: 0
aliases_left: 400
@@ -3853,6 +4056,7 @@ paths:
relay_all_recipients: "0"
relayhost: "0"
rl: false
tags: ["tag3", "tag4"]
description: OK
headers: {}
tags:
@@ -4345,6 +4549,13 @@ paths:
- all
- user@domain.tld
type: string
- description: comma seperated list of tags to filter by
example: "tag1,tag2"
in: query
name: tags
required: false
schema:
type: string
- description: e.g. api-key-string
example: api-key-string
in: header
@@ -4382,6 +4593,7 @@ paths:
rl: false
spam_aliases: 0
username: info@doman3.tld
tags: ["tag1", "tag2"]
description: OK
headers: {}
tags:
@@ -5072,6 +5284,27 @@ paths:
of used storage.
operationId: Get vmail status
summary: Get vmail status
/api/v1/get/status/version:
get:
responses:
"401":
$ref: "#/components/responses/Unauthorized"
"200":
content:
application/json:
examples:
response:
value:
version: "2022-04"
description: OK
headers: {}
tags:
- Status
description: >-
Using this endpoint you can get the current running release of this
instance.
operationId: Get version status
summary: Get version status
/api/v1/get/syncjobs/all/no_log:
get:
responses:

View File

@@ -0,0 +1,19 @@
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
urls: [{url: "/api/openapi.yaml", name: "mailcow API"}],
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
// 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

View File

@@ -68,7 +68,7 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) {
exit(0);
}
$login_role = check_login($login_user, $login_pass, true);
$login_role = check_login($login_user, $login_pass, array('eas' => TRUE));
if ($login_role === "user") {
header("Content-Type: application/xml");

View File

@@ -128,10 +128,10 @@ table.footable > tbody > tr.footable-empty > th {
content: "\f130";
}
.fooicon-plus:before {
content: "\f4fc";
content: "\f4fd";
}
.fooicon-minus:before {
content: "\f2e8";
content: "\f2e9";
}
.fooicon-search:before {
content: "\f52a";

File diff suppressed because one or more lines are too long

View File

@@ -232,6 +232,9 @@ table.footable>tbody>tr.footable-empty>td {
font-style:italic;
font-size: 1rem;
}
table>tbody>tr>td>span.footable-toggle {
opacity: 0.75;
}
.navbar-nav > li {
font-size: 1rem !important;
}
@@ -256,3 +259,52 @@ code {
.flag-icon {
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;
}
.tag-box {
display: flex;
flex-wrap: wrap;
height: auto;
}
.tag-badge {
transition: 200ms linear;
margin-top: 5px;
margin-bottom: 5px;
margin-left: 2px;
margin-right: 2px;
}
.tag-badge.btn-badge {
cursor: pointer;
}
.tag-badge .bi {
font-size: 12px;
}
.tag-badge.btn-badge:hover {
filter: brightness(0.9);
}
.tag-input {
margin-left: 10px;
border: 0;
flex: 1;
height: 24px;
min-width: 150px;
}
.tag-input:focus {
outline: none;
}
.tag-add {
padding: 0 5px 0 5px;
align-items: center;
display: inline-flex;
}

View File

@@ -54,6 +54,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'rl' => $rl,
'rlyhosts' => $rlyhosts,
'dkim' => dkim('details', $domain),
'domain_details' => $result,
];
}
elseif (isset($_GET['oauth2client']) &&
@@ -99,6 +100,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'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"])) {

View File

@@ -2,5 +2,5 @@
session_start();
unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_method']);
unset($_SESSION['pending_tfa_methods']);
?>

View File

@@ -23,14 +23,43 @@ if (is_array($alertbox_log_parser)) {
unset($_SESSION['return']);
}
// map tfa details for twig
$pending_tfa_authmechs = [];
foreach($_SESSION['pending_tfa_methods'] as $authdata){
$pending_tfa_authmechs[$authdata['authmech']] = false;
}
if (isset($pending_tfa_authmechs['webauthn'])) {
$pending_tfa_authmechs['webauthn'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& isset($pending_tfa_authmechs['yubi_otp'])) {
$pending_tfa_authmechs['yubi_otp'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& !isset($pending_tfa_authmechs['yubi_otp'])
&& isset($pending_tfa_authmechs['totp'])) {
$pending_tfa_authmechs['totp'] = true;
}
if (isset($pending_tfa_authmechs['u2f'])) {
$pending_tfa_authmechs['u2f'] = true;
}
// globals
$globalVariables = [
'mailcow_info' => array(
'version_tag' => $GLOBALS['MAILCOW_GIT_VERSION'],
'git_project_url' => $GLOBALS['MAILCOW_GIT_URL']
'last_version_tag' => $GLOBALS['MAILCOW_LAST_GIT_VERSION'],
'git_owner' => $GLOBALS['MAILCOW_GIT_OWNER'],
'git_repo' => $GLOBALS['MAILCOW_GIT_REPO'],
'git_project_url' => $GLOBALS['MAILCOW_GIT_URL'],
'git_commit' => $GLOBALS['MAILCOW_GIT_COMMIT'],
'git_commit_date' => $GLOBALS['MAILCOW_GIT_COMMIT_DATE'],
'mailcow_branch' => $GLOBALS['MAILCOW_BRANCH'],
'updated_at' => $GLOBALS['MAILCOW_UPDATEDAT']
),
'js_path' => '/cache/'.basename($JSPath),
'pending_tfa_method' => @$_SESSION['pending_tfa_method'],
'pending_tfa_methods' => @$_SESSION['pending_tfa_methods'],
'pending_tfa_authmechs' => $pending_tfa_authmechs,
'pending_mailcow_cc_username' => @$_SESSION['pending_mailcow_cc_username'],
'lang_footer' => json_encode($lang['footer']),
'lang_acl' => json_encode($lang['acl']),

View File

@@ -197,7 +197,7 @@ function dkim($_action, $_data = null, $privkey = false) {
return false;
}
try {
dkim('delete', (array)$domain);
dkim('delete', array('domains' => $domain));
$redis->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);

View File

@@ -830,11 +830,15 @@ function check_login($user, $pass, $app_passwd_data = false) {
$stmt->execute(array(':user' => $user));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
// verify password
if (verify_hash($row['password'], $pass)) {
if (get_tfa($user)['name'] != "none") {
// check for tfa authenticators
$authenticators = get_tfa($user);
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
// active tfa authenticators found, set pending user login
$_SESSION['pending_mailcow_cc_username'] = $user;
$_SESSION['pending_mailcow_cc_role'] = "admin";
$_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
unset($_SESSION['ldelay']);
$_SESSION['return'][] = array(
'type' => 'info',
@@ -842,8 +846,7 @@ function check_login($user, $pass, $app_passwd_data = false) {
'msg' => 'awaiting_tfa_confirmation'
);
return "pending";
}
else {
} else {
unset($_SESSION['ldelay']);
// Reactivate TFA if it was set to "deactivate TFA for next login"
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
@@ -866,11 +869,14 @@ function check_login($user, $pass, $app_passwd_data = false) {
$stmt->execute(array(':user' => $user));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
// verify password
if (verify_hash($row['password'], $pass) !== false) {
if (get_tfa($user)['name'] != "none") {
// check for tfa authenticators
$authenticators = get_tfa($user);
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
$_SESSION['pending_mailcow_cc_username'] = $user;
$_SESSION['pending_mailcow_cc_role'] = "domainadmin";
$_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
unset($_SESSION['ldelay']);
$_SESSION['return'][] = array(
'type' => 'info',
@@ -929,15 +935,37 @@ function check_login($user, $pass, $app_passwd_data = false) {
$stmt->execute(array(':user' => $user));
$rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC));
}
foreach ($rows as $row) {
foreach ($rows as $row) {
// verify password
if (verify_hash($row['password'], $pass) !== false) {
unset($_SESSION['ldelay']);
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $user, '*'),
'msg' => array('logged_in_as', $user)
);
if ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) {
if (!array_key_exists("app_passwd_id", $row)){
// password is not a app password
// check for tfa authenticators
$authenticators = get_tfa($user);
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 &&
$app_passwd_data['eas'] !== true && $app_passwd_data['dav'] !== true) {
// authenticators found, init TFA flow
$_SESSION['pending_mailcow_cc_username'] = $user;
$_SESSION['pending_mailcow_cc_role'] = "user";
$_SESSION['pending_tfa_methods'] = $authenticators['additional'];
unset($_SESSION['ldelay']);
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $user, '*'),
'msg' => array('logged_in_as', $user)
);
return "pending";
} else if (!isset($authenticators['additional']) || !is_array($authenticators['additional']) || count($authenticators['additional']) == 0) {
// no authenticators found, login successfull
// Reactivate TFA if it was set to "deactivate TFA for next login"
$stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
$stmt->execute(array(':user' => $user));
unset($_SESSION['ldelay']);
return "user";
}
} elseif ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) {
// password is a app password
$service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV';
$stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)");
$stmt->execute(array(
@@ -946,8 +974,10 @@ function check_login($user, $pass, $app_passwd_data = false) {
':username' => $user,
':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
));
unset($_SESSION['ldelay']);
return "user";
}
return "user";
}
}
@@ -1142,47 +1172,46 @@ function set_tfa($_data) {
global $yubi;
global $tfa;
$_data_log = $_data;
$access_denied = null;
!isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*';
$username = $_SESSION['mailcow_cc_username'];
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
}
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if (!empty($num_results)) {
if (!verify_hash($row['password'], $_data["confirm_password"])) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
}
}
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if (!empty($num_results)) {
if (!verify_hash($row['password'], $_data["confirm_password"])) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
// check for empty user and role
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
// check admin confirm password
if ($access_denied === null) {
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
else $access_denied = false;
}
}
// check mailbox confirm password
if ($access_denied === null) {
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
else $access_denied = false;
}
}
// set access_denied error
if ($access_denied){
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
}
switch ($_data["tfa_method"]) {
case "yubi_otp":
@@ -1220,8 +1249,7 @@ function set_tfa($_data) {
$yubico_modhex_id = substr($_data["otp_token"], 0, 12);
$stmt = $pdo->prepare("DELETE FROM `tfa`
WHERE `username` = :username
AND (`authmech` != 'yubi_otp')
OR (`authmech` = 'yubi_otp' AND `secret` LIKE :modhex)");
AND (`authmech` = 'yubi_otp' AND `secret` LIKE :modhex)");
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
$stmt = $pdo->prepare("INSERT INTO `tfa` (`key_id`, `username`, `authmech`, `active`, `secret`) VALUES
(:key_id, :username, 'yubi_otp', '1', :secret)");
@@ -1265,9 +1293,6 @@ function set_tfa($_data) {
case "webauthn":
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'webauthn'");
$stmt->execute(array(':username' => $username));
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`)
VALUES (?, ?, 'webauthn', ?, ?, ?, ?, '1')");
$stmt->execute(array(
@@ -1439,25 +1464,27 @@ function unset_tfa_key($_data) {
global $pdo;
global $lang;
$_data_log = $_data;
$access_denied = null;
$id = intval($_data['unset_tfa_key']);
$username = $_SESSION['mailcow_cc_username'];
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
}
// check for empty user and role
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
try {
if (!is_numeric($id)) {
$_SESSION['return'][] = array(
if (!is_numeric($id)) $access_denied = true;
// set access_denied error
if ($access_denied){
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_data_log),
'msg' => 'access_denied'
);
return false;
}
}
// check if it's last key
$stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array(':username' => $username));
@@ -1470,6 +1497,8 @@ function unset_tfa_key($_data) {
);
return false;
}
// delete key
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
$stmt->execute(array(':username' => $username, ':id' => $id));
$_SESSION['return'][] = array(
@@ -1487,7 +1516,7 @@ function unset_tfa_key($_data) {
return false;
}
}
function get_tfa($username = null) {
function get_tfa($username = null, $id = null) {
global $pdo;
if (isset($_SESSION['mailcow_cc_username'])) {
$username = $_SESSION['mailcow_cc_username'];
@@ -1495,95 +1524,119 @@ function get_tfa($username = null) {
elseif (empty($username)) {
return false;
}
$stmt = $pdo->prepare("SELECT * FROM `tfa`
WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (isset($row["authmech"])) {
switch ($row["authmech"]) {
case "yubi_otp":
$data['name'] = "yubi_otp";
$data['pretty'] = "Yubico OTP";
$stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
$stmt->execute(array(
':username' => $username,
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
if (!isset($id)){
// fetch all tfa methods - just get information about possible authenticators
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `authmech` FROM `tfa`
WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array(':username' => $username));
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// no tfa methods found
if (count($results) == 0) {
$data['name'] = 'none';
$data['pretty'] = "-";
$data['additional'] = array();
return $data;
}
$data['additional'] = $results;
return $data;
} else {
// fetch specific authenticator details by id
$stmt = $pdo->prepare("SELECT * FROM `tfa`
WHERE `username` = :username AND `id` = :id AND `active` = '1'");
$stmt->execute(array(':username' => $username, ':id' => $id));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (isset($row["authmech"])) {
switch ($row["authmech"]) {
case "yubi_otp":
$data['name'] = "yubi_otp";
$data['pretty'] = "Yubico OTP";
$stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username AND `id` = :id");
$stmt->execute(array(
':username' => $username,
':id' => $id
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
// u2f - deprecated, should be removed
case "u2f":
$data['name'] = "u2f";
$data['pretty'] = "Fido U2F";
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username AND `id` = :id");
$stmt->execute(array(
':username' => $username,
':id' => $id
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
case "hotp":
$data['name'] = "hotp";
$data['pretty'] = "HMAC-based OTP";
return $data;
break;
case "totp":
$data['name'] = "totp";
$data['pretty'] = "Time-based OTP";
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username AND `id` = :id");
$stmt->execute(array(
':username' => $username,
':id' => $id
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
case "webauthn":
$data['name'] = "webauthn";
$data['pretty'] = "WebAuthn";
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username AND `id` = :id");
$stmt->execute(array(
':username' => $username,
':id' => $id
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
default:
$data['name'] = 'none';
$data['pretty'] = "-";
return $data;
break;
}
return $data;
break;
// u2f - deprecated, should be removed
case "u2f":
$data['name'] = "u2f";
$data['pretty'] = "Fido U2F";
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
$stmt->execute(array(
':username' => $username,
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
case "hotp":
$data['name'] = "hotp";
$data['pretty'] = "HMAC-based OTP";
return $data;
break;
case "totp":
$data['name'] = "totp";
$data['pretty'] = "Time-based OTP";
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
$stmt->execute(array(
':username' => $username,
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
case "webauthn":
$data['name'] = "webauthn";
$data['pretty'] = "WebAuthn";
$stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
$stmt->execute(array(
':username' => $username,
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$data['additional'][] = $row;
}
return $data;
break;
default:
}
else {
$data['name'] = 'none';
$data['pretty'] = "-";
return $data;
break;
}
}
}
else {
$data['name'] = 'none';
$data['pretty'] = "-";
return $data;
}
}
function verify_tfa_login($username, $_data, $WebAuthn) {
global $pdo;
global $yubi;
global $u2f;
global $tfa;
$stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
WHERE `username` = :username AND `active` = '1'");
$stmt->execute(array(':username' => $username));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
function verify_tfa_login($username, $_data) {
global $pdo;
global $yubi;
global $u2f;
global $tfa;
global $WebAuthn;
switch ($row["authmech"]) {
if ($_data['tfa_method'] != 'u2f'){
switch ($_data["tfa_method"]) {
case "yubi_otp":
if (!ctype_alnum($_data['token']) || strlen($_data['token']) != 44) {
$_SESSION['return'][] = array(
@@ -1597,7 +1650,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
$stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
WHERE `username` = :username
AND `authmech` = 'yubi_otp'
AND `active`='1'
AND `active` = '1'
AND `secret` LIKE :modhex");
$stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -1632,15 +1685,16 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
return false;
break;
case "totp":
try {
try {
$stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
WHERE `username` = :username
AND `authmech` = 'totp'
AND `id` = :id
AND `active`='1'");
$stmt->execute(array(':username' => $username));
$stmt->execute(array(':username' => $username, ':id' => $_data['id']));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
$_SESSION['tfa_id'] = $row['id'];
$_SESSION['return'][] = array(
'type' => 'success',
@@ -1648,7 +1702,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
'msg' => 'verified_totp_login'
);
return true;
}
}
}
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -1656,23 +1710,16 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
'msg' => 'totp_verification_failed'
);
return false;
}
catch (PDOException $e) {
}
catch (PDOException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $username, '*'),
'msg' => array('mysql_error', $e)
);
return false;
}
}
break;
// u2f - deprecated, should be removed
case "u2f":
// delete old keys that used u2f
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = :authmech AND `username` = :username");
$stmt->execute(array(':authmech' => 'u2f', ':username' => $username));
return true;
case "webauthn":
$tokenData = json_decode($_data['token']);
$clientDataJSON = base64_decode($tokenData->clientDataJSON);
@@ -1681,13 +1728,20 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
$id = base64_decode($tokenData->id);
$challenge = $_SESSION['challenge'];
$stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
$stmt->execute(array(':tokenId' => $tokenData->id));
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `id` = :id AND `active`='1'");
$stmt->execute(array(':id' => $_data['id']));
$process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($process_webauthn) || empty($process_webauthn['publicKey']) || empty($process_webauthn['username'])) return false;
if (empty($process_webauthn)){
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $username, '*'),
'msg' => array('webauthn_verification_failed', 'authenticator not found')
);
return false;
}
if ($process_webauthn['publicKey'] === false) {
if (empty($process_webauthn['publicKey']) || $process_webauthn['publicKey'] === false) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $username, '*'),
@@ -1695,6 +1749,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
);
return false;
}
try {
$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $process_webauthn['publicKey'], $challenge, null, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN'], $GLOBALS['WEBAUTHN_USER_PRESENT_FLAG']);
}
@@ -1707,26 +1762,31 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
return false;
}
$stmt = $pdo->prepare("SELECT `superadmin` FROM `admin` WHERE `username` = :username");
$stmt->execute(array(':username' => $process_webauthn['username']));
$obj_props = $stmt->fetch(PDO::FETCH_ASSOC);
if ($obj_props['superadmin'] === 1) {
$_SESSION["mailcow_cc_role"] = "admin";
$_SESSION["mailcow_cc_role"] = "admin";
}
elseif ($obj_props['superadmin'] === 0) {
$_SESSION["mailcow_cc_role"] = "domainadmin";
$_SESSION["mailcow_cc_role"] = "domainadmin";
}
else {
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
$stmt->execute(array(':username' => $process_webauthn['username']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row['username'] == $process_webauthn['username']) {
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
$stmt->execute(array(':username' => $process_webauthn['username']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($row['username'])) {
$_SESSION["mailcow_cc_role"] = "user";
}
} else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $username, '*'),
'msg' => array('webauthn_verification_failed', 'could not determine user role')
);
return false;
}
}
if ($process_webauthn['username'] != $_SESSION['pending_mailcow_cc_username']){
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -1736,9 +1796,8 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
return false;
}
$_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
$_SESSION['tfa_id'] = $process_webauthn['key_id'];
$_SESSION['tfa_id'] = $process_webauthn['id'];
$_SESSION['authReq'] = null;
unset($_SESSION["challenge"]);
$_SESSION['return'][] = array(
@@ -1759,6 +1818,17 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
}
return false;
} else {
// delete old keys that used u2f
$stmt = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
$stmt->execute(array(':username' => $username));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($rows) == 0) return false;
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
$stmt->execute(array(':username' => $username));
return true;
}
}
function admin_api($access, $action, $data = null) {
global $pdo;

View File

@@ -336,9 +336,37 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$mins_interval = $_data['mins_interval'];
$enc1 = $_data['enc1'];
$custom_params = (empty(trim($_data['custom_params']))) ? '' : trim($_data['custom_params']);
// Workaround, fixme
if (strpos($custom_params, 'pipemess')) {
$custom_params = '';
// validate custom params
foreach (explode('-', $custom_params) as $param){
if(empty($param)) continue;
// extract option
if (str_contains($param, '=')) $param = explode('=', $param)[0];
else $param = rtrim($param, ' ');
// remove first char if first char is -
if ($param[0] == '-') $param = ltrim($param, $param[0]);
if (str_contains($param, ' ')) {
// bad char
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'bad character SPACE'
);
return false;
}
// check if param is whitelisted
if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
// bad option
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'bad option '. $param
);
return false;
}
}
if (empty($subfolder2)) {
$subfolder2 = "";
@@ -443,16 +471,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
'msg' => 'access_denied'
);
return false;
}
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$description = $_data['description'];
if (empty($description)) {
$description = $domain;
}
if (empty($description)) $description = $domain;
$tags = (array)$_data['tags'];
$aliases = (int)$_data['aliases'];
$mailboxes = (int)$_data['mailboxes'];
$defquota = (int)$_data['defquota'];
@@ -545,10 +572,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
return false;
}
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
$stmt->execute(array(
':domain' => '%@' . $domain
));
// save domain
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
$stmt->execute(array(
@@ -565,6 +594,24 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':relay_unknown_only' => $relay_unknown_only,
':relay_all_recipients' => $relay_all_recipients
));
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
if ($index > $GLOBALS['TAGGING_LIMIT']) {
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
);
break;
}
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
$stmt->execute(array(
':domain' => $domain,
':tag_name' => $tag,
));
}
try {
$redis->hSet('DOMAIN_MAP', $domain, 1);
}
@@ -580,7 +627,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
}
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'domain_add_dkim_available'
);
}
else {
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
}
}
if (!empty($restart_sogo)) {
$restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
@@ -910,7 +966,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
}
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'domain_add_dkim_available'
);
}
else {
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
}
}
$_SESSION['return'][] = array(
'type' => 'success',
@@ -942,6 +1007,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$password = $_data['password'];
$password2 = $_data['password2'];
$name = ltrim(rtrim($_data['name'], '>'), '<');
$tags = $_data['tags'];
$quota_m = intval($_data['quota']);
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
$_SESSION['return'][] = array(
@@ -1103,6 +1169,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':username' => $username
));
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
if ($index > $GLOBALS['TAGGING_LIMIT']) {
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
);
break;
}
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
$stmt->execute(array(
':username' => $username,
':tag_name' => $tag,
));
}
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
$stmt->execute(array(':username' => $username));
@@ -1709,8 +1792,37 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
continue;
}
if (strpos($custom_params, 'pipemess')) {
$custom_params = '';
// validate custom params
foreach (explode('-', $custom_params) as $param){
if(empty($param)) continue;
// extract option
if (str_contains($param, '=')) $param = explode('=', $param)[0];
else $param = rtrim($param, ' ');
// remove first char if first char is -
if ($param[0] == '-') $param = ltrim($param, $param[0]);
if (str_contains($param, ' ')) {
// bad char
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'bad character SPACE'
);
return false;
}
// check if param is whitelisted
if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
// bad option
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'bad option '. $param
);
return false;
}
}
if (empty($subfolder2)) {
$subfolder2 = "";
@@ -2146,6 +2258,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
$description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
}
else {
$_SESSION['return'][] = array(
@@ -2155,6 +2268,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
continue;
}
$stmt = $pdo->prepare("UPDATE `domain` SET
`description` = :description,
`gal` = :gal
@@ -2164,6 +2278,24 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':gal' => $gal,
':domain' => $domain
));
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
if ($index > $GLOBALS['TAGGING_LIMIT']) {
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
);
break;
}
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
$stmt->execute(array(
':domain' => $domain,
':tag_name' => $tag,
));
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
@@ -2185,6 +2317,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
$quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
if ($relay_all_recipients == '1') {
$backupmx = '1';
}
@@ -2283,6 +2416,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
continue;
}
$stmt = $pdo->prepare("UPDATE `domain` SET
`relay_all_recipients` = :relay_all_recipients,
`relay_unknown_only` = :relay_unknown_only,
@@ -2312,6 +2446,24 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':description' => $description,
':domain' => $domain
));
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
if ($index > $GLOBALS['TAGGING_LIMIT']) {
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
);
break;
}
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
$stmt->execute(array(
':domain' => $domain,
':tag_name' => $tag,
));
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
@@ -2360,6 +2512,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$quota_b = $quota_m * 1048576;
$password = (!empty($_data['password'])) ? $_data['password'] : null;
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
}
else {
$_SESSION['return'][] = array(
@@ -2636,6 +2789,24 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':relayhost' => $relayhost,
':username' => $username
));
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
if ($index > $GLOBALS['TAGGING_LIMIT']) {
$_SESSION['return'][] = array(
'type' => 'warning',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
);
break;
}
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
$stmt->execute(array(
':username' => $username,
':tag_name' => $tag,
));
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
@@ -2851,10 +3022,34 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
break;
case 'mailboxes':
$mailboxes = array();
if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false;
if (isset($_extra) && is_array($_extra) && isset($_data)) {
// get by domain and tags
$tags = is_array($_extra) ? $_extra : array();
$sql = "";
foreach ($tags as $key => $tag) {
$sql = $sql."SELECT DISTINCT `username` FROM `tags_mailbox` WHERE `username` LIKE ? AND `tag_name` LIKE ?"; // distinct, avoid duplicates
if ($key === array_key_last($tags)) break;
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
}
// prepend domain to array
$params = array();
foreach ($tags as $key => $val){
array_push($params, '%'.$_data.'%');
array_push($params, '%'.$val.'%');
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], explode('@', $row['username'])[1]))
$mailboxes[] = $row['username'];
}
}
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
// get by domain
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
$stmt->execute(array(
':domain' => $_data,
@@ -3348,20 +3543,46 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
return false;
}
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
WHERE (`domain` IN (
SELECT `domain` from `domain_admins`
WHERE (`active`='1' AND `username` = :username))
)
OR 'admin'= :role");
$stmt->execute(array(
':username' => $_SESSION['mailcow_cc_username'],
':role' => $_SESSION['mailcow_cc_role'],
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$domains[] = $row['domain'];
if (isset($_extra) && is_array($_extra)){
// get by tags
$tags = is_array($_extra) ? $_extra : array();
// add % as prefix and suffix to every element for relative searching
$tags = array_map(function($x){ return '%'.$x.'%'; }, $tags);
$sql = "";
foreach ($tags as $key => $tag) {
$sql = $sql."SELECT DISTINCT `domain` FROM `tags_domain` WHERE `tag_name` LIKE ?"; // distinct, avoid duplicates
if ($key === array_key_last($tags)) break;
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
}
$stmt = $pdo->prepare($sql);
$stmt->execute($tags);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
if ($_SESSION['mailcow_cc_role'] == "admin")
$domains[] = $row['domain'];
elseif (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain']))
$domains[] = $row['domain'];
}
} else {
// get all
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
WHERE (`domain` IN (
SELECT `domain` from `domain_admins`
WHERE (`active`='1' AND `username` = :username))
)
OR 'admin'= :role");
$stmt->execute(array(
':username' => $_SESSION['mailcow_cc_username'],
':role' => $_SESSION['mailcow_cc_role'],
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$domains[] = $row['domain'];
}
}
return $domains;
break;
case 'domain_details':
@@ -3478,6 +3699,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
(isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
}
$stmt = $pdo->prepare("SELECT `tag_name`
FROM `tags_domain` WHERE `domain`= :domain");
$stmt->execute(array(
':domain' => $_data
));
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($tag = array_shift($tags)) {
$domaindata['tags'][] = $tag['tag_name'];
}
return $domaindata;
break;
case 'mailbox_details':
@@ -3613,6 +3844,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
$mailboxdata['is_relayed'] = $row['backupmx'];
}
$stmt = $pdo->prepare("SELECT `tag_name`
FROM `tags_mailbox` WHERE `username`= :username");
$stmt->execute(array(
':username' => $_data
));
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($tag = array_shift($tags)) {
$mailboxdata['tags'][] = $tag['tag_name'];
}
return $mailboxdata;
break;
@@ -4342,6 +4582,108 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
}
break;
case 'tags_domain':
if (!is_array($_data['domain'])) {
$domains = array();
$domains[] = $_data['domain'];
}
else {
$domains = $_data['domain'];
}
$tags = $_data['tags'];
if (!is_array($tags)) $tags = array();
if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied'
);
return false;
}
$wasModified = false;
foreach ($domains as $domain) {
if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'domain_invalid'
);
continue;
}
foreach($tags as $tag){
// delete tag
$wasModified = true;
$stmt = $pdo->prepare("DELETE FROM `tags_domain` WHERE `domain` = :domain AND `tag_name` = :tag_name");
$stmt->execute(array(
':domain' => $domain,
':tag_name' => $tag,
));
}
}
if (!$wasModified) return false;
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('domain_modified', $domain)
);
break;
case 'tags_mailbox':
if (!is_array($_data['username'])) {
$usernames = array();
$usernames[] = $_data['username'];
}
else {
$usernames = $_data['username'];
}
$tags = $_data['tags'];
if (!is_array($tags)) $tags = array();
$wasModified = false;
foreach ($usernames as $username) {
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'email invalid'
);
continue;
}
$is_now = mailbox('get', 'mailbox_details', $username);
$domain = $is_now['domain'];
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied'
);
continue;
}
// delete tags
foreach($tags as $tag){
$wasModified = true;
$stmt = $pdo->prepare("DELETE FROM `tags_mailbox` WHERE `username` = :username AND `tag_name` = :tag_name");
$stmt->execute(array(
':username' => $username,
':tag_name' => $tag,
));
}
}
if (!$wasModified) return false;
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('mailbox_modified', $username)
);
break;
}
break;
}

View File

@@ -3,7 +3,7 @@ function init_db_schema() {
try {
global $pdo;
$db_version = "18012022_1020";
$db_version = "25072022_2300";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -23,35 +23,35 @@ function init_db_schema() {
}
$views = array(
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
SELECT goto, IFNULL(GROUP_CONCAT(address ORDER BY address SEPARATOR ' '), '') AS address FROM alias
WHERE address!=goto
AND active = '1'
AND sogo_visible = '1'
AND address NOT LIKE '@%'
GROUP BY goto;",
// START
// Unused at the moment - we cannot allow to show a foreign mailbox as sender address in SOGo, as SOGo does not like this
// We need to create delegation in SOGo AND set a sender_acl in mailcow to allow to send as user X
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
WHERE send_as NOT LIKE '@%'
GROUP BY logged_in_as;",
// END
"grouped_sender_acl_external" => "CREATE VIEW grouped_sender_acl_external (username, send_as_acl) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
WHERE send_as NOT LIKE '@%' AND external = '1'
GROUP BY logged_in_as;",
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
LEFT OUTER JOIN alias_domain ON target_domain=domain
GROUP BY username;",
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'prefilter';",
"sieve_after" => "CREATE VIEW sieve_after (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'postfilter';"
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
SELECT goto, IFNULL(GROUP_CONCAT(address ORDER BY address SEPARATOR ' '), '') AS address FROM alias
WHERE address!=goto
AND active = '1'
AND sogo_visible = '1'
AND address NOT LIKE '@%'
GROUP BY goto;",
// START
// Unused at the moment - we cannot allow to show a foreign mailbox as sender address in SOGo, as SOGo does not like this
// We need to create delegation in SOGo AND set a sender_acl in mailcow to allow to send as user X
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
WHERE send_as NOT LIKE '@%'
GROUP BY logged_in_as;",
// END
"grouped_sender_acl_external" => "CREATE VIEW grouped_sender_acl_external (username, send_as_acl) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
WHERE send_as NOT LIKE '@%' AND external = '1'
GROUP BY logged_in_as;",
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
LEFT OUTER JOIN alias_domain ON target_domain=domain
GROUP BY username;",
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'prefilter';",
"sieve_after" => "CREATE VIEW sieve_after (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'postfilter';"
);
$tables = array(
@@ -251,6 +251,26 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"tags_domain" => array(
"cols" => array(
"tag_name" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"fkey" => array(
"fk_tags_domain" => array(
"col" => "domain",
"ref" => "domain.domain",
"delete" => "CASCADE",
"update" => "NO ACTION"
)
),
"unique" => array(
"tag_name" => array("tag_name", "domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"tls_policy_override" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
@@ -325,6 +345,26 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"tags_mailbox" => array(
"cols" => array(
"tag_name" => "VARCHAR(255) NOT NULL",
"username" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"fkey" => array(
"fk_tags_mailbox" => array(
"col" => "username",
"ref" => "mailbox.username",
"delete" => "CASCADE",
"update" => "NO ACTION"
)
),
"unique" => array(
"tag_name" => array("tag_name", "username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sieve_filters" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
@@ -400,7 +440,7 @@ function init_db_schema() {
"spam_score" => "TINYINT(1) NOT NULL DEFAULT '1'",
"spam_policy" => "TINYINT(1) NOT NULL DEFAULT '1'",
"delimiter_action" => "TINYINT(1) NOT NULL DEFAULT '1'",
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '0'",
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
"sogo_profile_reset" => "TINYINT(1) NOT NULL DEFAULT '0'",
"pushover" => "TINYINT(1) NOT NULL DEFAULT '1'",
@@ -698,8 +738,8 @@ function init_db_schema() {
"username" => "VARCHAR(255) NOT NULL",
"authmech" => "ENUM('yubi_otp', 'u2f', 'hotp', 'totp', 'webauthn')",
"secret" => "VARCHAR(255) DEFAULT NULL",
"keyHandle" => "VARCHAR(255) DEFAULT NULL",
"publicKey" => "VARCHAR(255) DEFAULT NULL",
"keyHandle" => "VARCHAR(1023) DEFAULT NULL",
"publicKey" => "VARCHAR(4096) DEFAULT NULL",
"counter" => "INT NOT NULL DEFAULT '0'",
"certificate" => "TEXT",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
@@ -864,7 +904,7 @@ function init_db_schema() {
"sogo_sessions_folder" => array(
"cols" => array(
"c_id" => "VARCHAR(255) NOT NULL",
"c_value" => "VARCHAR(255) NOT NULL",
"c_value" => "VARCHAR(4096) NOT NULL",
"c_creationdate" => "INT(11) NOT NULL",
"c_lastseen" => "INT(11) NOT NULL"
),
@@ -1187,8 +1227,16 @@ function init_db_schema() {
$pdo->query($create);
}
// Mitigate imapsync pipemess issue
$pdo->query("UPDATE `imapsync` SET `custom_params` = '' WHERE `custom_params` LIKE '%pipemess%';");
// Mitigate imapsync argument injection issue
$pdo->query("UPDATE `imapsync` SET `custom_params` = ''
WHERE `custom_params` LIKE '%pipemess%'
OR custom_params LIKE '%skipmess%'
OR custom_params LIKE '%delete2foldersonly%'
OR custom_params LIKE '%delete2foldersbutnot%'
OR custom_params LIKE '%regexflag%'
OR custom_params LIKE '%pipemess%'
OR custom_params LIKE '%regextrans2%'
OR custom_params LIKE '%maxlinelengthcmd%';");
// Migrate webauthn tfa
$stmt = $pdo->query("ALTER TABLE `tfa` MODIFY COLUMN `authmech` ENUM('yubi_otp', 'u2f', 'hotp', 'totp', 'webauthn')");

View File

@@ -1604,16 +1604,16 @@
},
{
"name": "twig/twig",
"version": "v3.3.8",
"version": "v3.4.3",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
"shasum": ""
},
"require": {
@@ -1628,7 +1628,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3-dev"
"dev-master": "3.4-dev"
}
},
"autoload": {
@@ -1664,7 +1664,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
"source": "https://github.com/twigphp/Twig/tree/v3.4.3"
},
"funding": [
{
@@ -1676,7 +1676,7 @@
"type": "tidelift"
}
],
"time": "2022-02-04T06:59:48+00:00"
"time": "2022-09-28T08:42:51+00:00"
},
{
"name": "yubico/u2flib-server",
@@ -1728,5 +1728,5 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.3.0"
}

View File

@@ -2,6 +2,11 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b::getLoader();

View File

@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
@@ -37,7 +39,7 @@ class InstalledVersions
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
@@ -241,7 +243,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
@@ -255,7 +257,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@@ -278,7 +280,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
@@ -301,7 +303,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
@@ -311,7 +313,7 @@ class InstalledVersions
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,15 +2,15 @@
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
'04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php',

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View File

@@ -25,38 +25,15 @@ class ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::getInitializer($loader));
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
$includeFiles = \Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire873464e4bd965a3168f133248b1b218b($fileIdentifier, $file);
}

View File

@@ -8,10 +8,10 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
'04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php',

View File

@@ -1654,17 +1654,17 @@
},
{
"name": "twig/twig",
"version": "v3.3.8",
"version_normalized": "3.3.8.0",
"version": "v3.4.3",
"version_normalized": "3.4.3.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
"shasum": ""
},
"require": {
@@ -1676,11 +1676,11 @@
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"time": "2022-02-04T06:59:48+00:00",
"time": "2022-09-28T08:42:51+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3-dev"
"dev-master": "3.4-dev"
}
},
"installation-source": "dist",
@@ -1717,7 +1717,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
"source": "https://github.com/twigphp/Twig/tree/v3.4.3"
},
"funding": [
{

View File

@@ -1,49 +1,49 @@
<?php return array(
'root' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => NULL,
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => NULL,
'dev_requirement' => false,
),
'bshaffer/oauth2-server-php' => array(
'pretty_version' => 'v1.11.1',
'version' => '1.11.1.0',
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
'type' => 'library',
'install_path' => __DIR__ . '/../bshaffer/oauth2-server-php',
'aliases' => array(),
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
'dev_requirement' => false,
),
'ddeboer/imap' => array(
'pretty_version' => '1.13.1',
'version' => '1.13.1.0',
'reference' => '8b772d04b1deadb5df13782fb78c4b648f77496e',
'type' => 'library',
'install_path' => __DIR__ . '/../ddeboer/imap',
'aliases' => array(),
'reference' => '8b772d04b1deadb5df13782fb78c4b648f77496e',
'dev_requirement' => false,
),
'directorytree/ldaprecord' => array(
'pretty_version' => 'v2.10.1',
'version' => '2.10.1.0',
'reference' => 'bf512d9af7a7b0e2ed7a666ab29cefdd027bee88',
'type' => 'library',
'install_path' => __DIR__ . '/../directorytree/ldaprecord',
'aliases' => array(),
'reference' => 'bf512d9af7a7b0e2ed7a666ab29cefdd027bee88',
'dev_requirement' => false,
),
'exorus/php-mime-mail-parser' => array(
@@ -55,28 +55,28 @@
'illuminate/contracts' => array(
'pretty_version' => 'v9.3.0',
'version' => '9.3.0.0',
'reference' => 'bf4b3c254c49d28157645d01e4883b5951b1e1d0',
'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(),
'reference' => 'bf4b3c254c49d28157645d01e4883b5951b1e1d0',
'dev_requirement' => false,
),
'matthiasmullie/minify' => array(
'pretty_version' => '1.3.66',
'version' => '1.3.66.0',
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/minify',
'aliases' => array(),
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
'dev_requirement' => false,
),
'matthiasmullie/path-converter' => array(
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
'type' => 'library',
'install_path' => __DIR__ . '/../matthiasmullie/path-converter',
'aliases' => array(),
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
'dev_requirement' => false,
),
'messaged/php-mime-mail-parser' => array(
@@ -88,136 +88,136 @@
'mustangostang/spyc' => array(
'pretty_version' => '0.6.3',
'version' => '0.6.3.0',
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
'type' => 'library',
'install_path' => __DIR__ . '/../mustangostang/spyc',
'aliases' => array(),
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
'dev_requirement' => false,
),
'nesbot/carbon' => array(
'pretty_version' => '2.57.0',
'version' => '2.57.0.0',
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(),
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
'dev_requirement' => false,
),
'php-mime-mail-parser/php-mime-mail-parser' => array(
'pretty_version' => '7.0.0',
'version' => '7.0.0.0',
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
'type' => 'library',
'install_path' => __DIR__ . '/../php-mime-mail-parser/php-mime-mail-parser',
'aliases' => array(),
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.6.0',
'version' => '6.6.0.0',
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(),
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
'dev_requirement' => false,
),
'psr/container' => array(
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
'dev_requirement' => false,
),
'psr/log' => array(
'pretty_version' => '3.0.0',
'version' => '3.0.0.0',
'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001',
'dev_requirement' => false,
),
'psr/simple-cache' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
'reference' => '8707bf3cea6f710bf6ef05491234e3ab06f6432a',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
'reference' => '8707bf3cea6f710bf6ef05491234e3ab06f6432a',
'dev_requirement' => false,
),
'robthree/twofactorauth' => array(
'pretty_version' => '1.8.1',
'version' => '1.8.1.0',
'reference' => '5afcb45282f1c75562a48d479ecd1732c9bdb11b',
'type' => 'library',
'install_path' => __DIR__ . '/../robthree/twofactorauth',
'aliases' => array(),
'reference' => '5afcb45282f1c75562a48d479ecd1732c9bdb11b',
'dev_requirement' => false,
),
'soundasleep/html2text' => array(
'pretty_version' => '0.5.0',
'version' => '0.5.0.0',
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
'type' => 'library',
'install_path' => __DIR__ . '/../soundasleep/html2text',
'aliases' => array(),
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.24.0',
'version' => '1.24.0.0',
'reference' => '57b712b08eddb97c762a8caa32c84e037892d2e9',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'reference' => '57b712b08eddb97c762a8caa32c84e037892d2e9',
'dev_requirement' => false,
),
'symfony/translation' => array(
'pretty_version' => 'v6.0.5',
'version' => '6.0.5.0',
'reference' => 'e69501c71107cc3146b32aaa45f4edd0c3427875',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(),
'reference' => 'e69501c71107cc3146b32aaa45f4edd0c3427875',
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v3.0.0',
'version' => '3.0.0.0',
'reference' => '1b6ea5a7442af5a12dba3dbd6d71034b5b234e77',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
'reference' => '1b6ea5a7442af5a12dba3dbd6d71034b5b234e77',
'dev_requirement' => false,
),
'symfony/translation-implementation' => array(
@@ -229,37 +229,37 @@
'symfony/var-dumper' => array(
'pretty_version' => 'v6.0.5',
'version' => '6.0.5.0',
'reference' => '60d6a756d5f485df5e6e40b337334848f79f61ce',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'reference' => '60d6a756d5f485df5e6e40b337334848f79f61ce',
'dev_requirement' => false,
),
'tightenco/collect' => array(
'pretty_version' => 'v8.83.2',
'version' => '8.83.2.0',
'reference' => 'd9c66d586ec2d216d8a31283d73f8df1400cc722',
'type' => 'library',
'install_path' => __DIR__ . '/../tightenco/collect',
'aliases' => array(),
'reference' => 'd9c66d586ec2d216d8a31283d73f8df1400cc722',
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v3.3.8',
'version' => '3.3.8.0',
'pretty_version' => 'v3.4.3',
'version' => '3.4.3.0',
'reference' => 'c38fd6b0b7f370c198db91ffd02e23b517426b58',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),
'reference' => '972d8604a92b7054828b539f2febb0211dd5945c',
'dev_requirement' => false,
),
'yubico/u2flib-server' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
'type' => 'library',
'install_path' => __DIR__ . '/../yubico/u2flib-server',
'aliases' => array(),
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
'dev_requirement' => false,
),
),

View File

@@ -1,4 +1,4 @@
/doc/** export-ignore
/extra/** export-ignore
/tests export-ignore
/doc/ export-ignore
/extra/ export-ignore
/tests/ export-ignore
/phpunit.xml.dist export-ignore

View File

@@ -9,6 +9,9 @@ on:
env:
SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE: 1
permissions:
contents: read
jobs:
tests:
name: "PHP ${{ matrix.php-version }}"
@@ -25,36 +28,23 @@ jobs:
- '7.4'
- '8.0'
- '8.1'
composer-options: ['']
experimental: [false]
steps:
- name: "Checkout code"
uses: actions/checkout@v2.3.3
uses: actions/checkout@v2
- name: "Install PHP with extensions"
uses: shivammathur/setup-php@2.7.0
uses: shivammathur/setup-php@v2
with:
coverage: "none"
php-version: ${{ matrix.php-version }}
ini-values: memory_limit=-1
tools: composer:v2
- name: "Add PHPUnit matcher"
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: "Set composer cache directory"
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: "Cache composer"
uses: actions/cache@v2.1.2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('composer.json') }}
restore-keys: ${{ runner.os }}-${{ matrix.php-version }}-composer-
- run: composer install ${{ matrix.composer-options }}
- run: composer install
- name: "Install PHPUnit"
run: vendor/bin/simple-phpunit install
@@ -92,35 +82,22 @@ jobs:
- 'extra/markdown-extra'
- 'extra/string-extra'
- 'extra/twig-extra-bundle'
composer-options: ['']
experimental: [false]
steps:
- name: "Checkout code"
uses: actions/checkout@v2.3.3
uses: actions/checkout@v2
- name: "Install PHP with extensions"
uses: shivammathur/setup-php@2.7.0
uses: shivammathur/setup-php@v2
with:
coverage: "none"
php-version: ${{ matrix.php-version }}
ini-values: memory_limit=-1
tools: composer:v2
- name: "Add PHPUnit matcher"
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: "Set composer cache directory"
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: "Cache composer"
uses: actions/cache@v2.1.2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-${{ matrix.extension }}-${{ hashFiles('composer.json') }}
restore-keys: ${{ runner.os }}-${{ matrix.php-version }}-${{ matrix.extension }}-
- run: composer install
- name: "Install PHPUnit"
@@ -129,10 +106,6 @@ jobs:
- name: "PHPUnit version"
run: vendor/bin/simple-phpunit --version
- if: matrix.extension == 'extra/markdown-extra' && matrix.php-version == '8.0'
working-directory: ${{ matrix.extension}}
run: composer config platform.php 7.4.99
- name: "Composer install"
working-directory: ${{ matrix.extension}}
run: composer install
@@ -140,6 +113,7 @@ jobs:
- name: "Run tests"
working-directory: ${{ matrix.extension}}
run: ../../vendor/bin/simple-phpunit
#
# Drupal does not support Twig 3 now!
#
@@ -160,10 +134,10 @@ jobs:
#
# steps:
# - name: "Checkout code"
# uses: actions/checkout@v2.3.3
# uses: actions/checkout@v2
#
# - name: "Install PHP with extensions"
# uses: shivammathur/setup-php@2.7.0
# uses: shivammathur/setup-php@2
# with:
# coverage: "none"
# extensions: "gd, pdo_sqlite"

View File

@@ -4,8 +4,12 @@ on:
pull_request:
push:
branches:
- '2.x'
- '3.x'
permissions:
contents: read
jobs:
build:
name: "Build"
@@ -16,32 +20,32 @@ jobs:
- name: "Checkout code"
uses: actions/checkout@v2
- name: "Set up Python 3.7"
uses: actions/setup-python@v1
- name: "Set-up PHP"
uses: shivammathur/setup-php@v2
with:
python-version: '3.7' # Semantic version range syntax or exact version of a Python version
php-version: 8.1
coverage: none
tools: "composer:v2"
- name: "Display Python version"
run: python -c "import sys; print(sys.version)"
- name: Get composer cache directory
id: composercache
working-directory: doc/_build
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: "Install Sphinx dependencies"
run: sudo apt-get install python-dev build-essential
- name: "Cache pip"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('_build/.requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: "Install Sphinx + requirements via pip"
working-directory: "doc"
run: pip install -r _build/.requirements.txt
- name: "Install dependencies"
working-directory: doc/_build
run: composer install --prefer-dist --no-progress
- name: "Build documentation"
working-directory: "doc"
run: make -C _build SPHINXOPTS="-nqW -j auto" html
- name: "Build the docs"
working-directory: doc/_build
run: php build.php --disable-cache
doctor-rst:
name: "DOCtor-RST"

View File

@@ -1,3 +1,5 @@
/doc/_build/vendor
/doc/_build/output
/composer.lock
/phpunit.xml
/vendor

View File

@@ -1,6 +1,36 @@
# 3.4.3 (2022-09-28)
* Fix a security issue on filesystem loader (possibility to load a template outside a configured directory)
# 3.4.2 (2022-08-12)
* Allow inherited magic method to still run with calling class
* Fix CallExpression::reflectCallable() throwing TypeError
* Fix typo in naming (currency_code)
# 3.4.1 (2022-05-17)
* Fix optimizing non-public named closures
# 3.4.0 (2022-05-22)
* Add support for named closures
# 3.3.10 (2022-04-06)
* Enable bytecode invalidation when auto_reload is enabled
# 3.3.9 (2022-03-25)
* Fix custom escapers when using multiple Twig environments
* Add support for "constant('class', object)"
* Do not reuse internally generated variable names during parsing
# 3.3.8 (2022-02-04)
* Fix a security issue when in a sandbox: the `sort` filter must require a Closure for the `arrow` parameter
* Fix deprecation notice on `round`
* Fix call to deprecated `convertToHtml` method
# 3.3.7 (2022-01-03)

View File

@@ -44,7 +44,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.3-dev"
"dev-master": "3.4-dev"
}
}
}

View File

@@ -38,11 +38,11 @@ use Twig\TokenParser\TokenParserInterface;
*/
class Environment
{
public const VERSION = '3.3.8';
public const VERSION_ID = 30308;
public const VERSION = '3.4.3';
public const VERSION_ID = 30403;
public const MAJOR_VERSION = 3;
public const MINOR_VERSION = 3;
public const RELEASE_VERSION = 8;
public const MINOR_VERSION = 4;
public const RELEASE_VERSION = 3;
public const EXTRA_VERSION = '';
private $charset;
@@ -228,7 +228,7 @@ class Environment
{
if (\is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new FilesystemCache($cache);
$this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new NullCache();

View File

@@ -485,7 +485,7 @@ class ExpressionParser
}
}
} else {
throw new SyntaxError('Expected name or number.', $lineno, $stream->getSourceContext());
throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
}
if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {

View File

@@ -1359,6 +1359,10 @@ function twig_source(Environment $env, $name, $ignoreMissing = false)
function twig_constant($constant, $object = null)
{
if (null !== $object) {
if ('class' === $constant) {
return \get_class($object);
}
$constant = \get_class($object).'::'.$constant;
}
@@ -1376,6 +1380,10 @@ function twig_constant($constant, $object = null)
function twig_constant_is_defined($constant, $object = null)
{
if (null !== $object) {
if ('class' === $constant) {
return true;
}
$constant = \get_class($object).'::'.$constant;
}

View File

@@ -387,13 +387,8 @@ function twig_escape_filter(Environment $env, $string, $strategy = 'html', $char
return rawurlencode($string);
default:
static $escapers;
if (null === $escapers) {
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
}
if (isset($escapers[$strategy])) {
$escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
if (array_key_exists($strategy, $escapers)) {
return $escapers[$strategy]($env, $string, $charset);
}

View File

@@ -91,11 +91,11 @@ final class SandboxExtension extends AbstractExtension
}
}
public function checkPropertyAllowed($obj, $method, int $lineno = -1, Source $source = null): void
public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null): void
{
if ($this->isSandboxed()) {
try {
$this->policy->checkPropertyAllowed($obj, $method);
$this->policy->checkPropertyAllowed($obj, $property);
} catch (SecurityNotAllowedPropertyError $e) {
$e->setSourceContext($source);
$e->setTemplateLine($lineno);

View File

@@ -183,9 +183,9 @@ class FilesystemLoader implements LoaderInterface
}
try {
$this->validateName($name);
list($namespace, $shortname) = $this->parseName($name);
$this->validateName($shortname);
} catch (LoaderError $e) {
if (!$throw) {
return null;

View File

@@ -24,19 +24,20 @@ abstract class CallExpression extends AbstractExpression
{
$callable = $this->getAttribute('callable');
$closingParenthesis = false;
$isArray = false;
if (\is_string($callable) && false === strpos($callable, '::')) {
$compiler->raw($callable);
} else {
list($r, $callable) = $this->reflectCallable($callable);
if ($r instanceof \ReflectionMethod && \is_string($callable[0])) {
if ($r->isStatic()) {
[$r, $callable] = $this->reflectCallable($callable);
if (\is_string($callable)) {
$compiler->raw($callable);
} elseif (\is_array($callable) && \is_string($callable[0])) {
if (!$r instanceof \ReflectionMethod || $r->isStatic()) {
$compiler->raw(sprintf('%s::%s', $callable[0], $callable[1]));
} else {
$compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
}
} elseif ($r instanceof \ReflectionMethod && $callable[0] instanceof ExtensionInterface) {
} elseif (\is_array($callable) && $callable[0] instanceof ExtensionInterface) {
$class = \get_class($callable[0]);
if (!$compiler->getEnvironment()->hasExtension($class)) {
// Compile a non-optimized call to trigger a \Twig\Error\RuntimeError, which cannot be a compile-time error
@@ -47,17 +48,11 @@ abstract class CallExpression extends AbstractExpression
$compiler->raw(sprintf('->%s', $callable[1]));
} else {
$closingParenthesis = true;
$isArray = true;
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), ', ucfirst($this->getAttribute('type')), $this->getAttribute('name')));
$compiler->raw(sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $this->getAttribute('name')));
}
}
$this->compileArguments($compiler, $isArray);
if ($closingParenthesis) {
$compiler->raw(')');
}
$this->compileArguments($compiler);
}
protected function compileArguments(Compiler $compiler, $isArray = false): void
@@ -244,10 +239,7 @@ abstract class CallExpression extends AbstractExpression
private function getCallableParameters($callable, bool $isVariadic): array
{
list($r) = $this->reflectCallable($callable);
if (null === $r) {
return [[], false];
}
[$r, , $callableName] = $this->reflectCallable($callable);
$parameters = $r->getParameters();
if ($this->hasNode('node')) {
@@ -274,11 +266,6 @@ abstract class CallExpression extends AbstractExpression
array_pop($parameters);
$isPhpVariadic = true;
} else {
$callableName = $r->name;
if ($r instanceof \ReflectionMethod) {
$callableName = $r->getDeclaringClass()->name.'::'.$callableName;
}
throw new \LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $this->getAttribute('name')));
}
}
@@ -292,29 +279,41 @@ abstract class CallExpression extends AbstractExpression
return $this->reflector;
}
if (\is_array($callable)) {
if (!method_exists($callable[0], $callable[1])) {
// __call()
return [null, []];
}
$r = new \ReflectionMethod($callable[0], $callable[1]);
} elseif (\is_object($callable) && !$callable instanceof \Closure) {
$r = new \ReflectionObject($callable);
$r = $r->getMethod('__invoke');
$callable = [$callable, '__invoke'];
} elseif (\is_string($callable) && false !== $pos = strpos($callable, '::')) {
$class = substr($callable, 0, $pos);
$method = substr($callable, $pos + 2);
if (!method_exists($class, $method)) {
// __staticCall()
return [null, []];
}
$r = new \ReflectionMethod($callable);
$callable = [$class, $method];
} else {
$r = new \ReflectionFunction($callable);
if (\is_string($callable) && false !== $pos = strpos($callable, '::')) {
$callable = [substr($callable, 0, $pos), substr($callable, 2 + $pos)];
}
return $this->reflector = [$r, $callable];
if (\is_array($callable) && method_exists($callable[0], $callable[1])) {
$r = new \ReflectionMethod($callable[0], $callable[1]);
return $this->reflector = [$r, $callable, $r->class.'::'.$r->name];
}
$checkVisibility = $callable instanceof \Closure;
try {
$closure = \Closure::fromCallable($callable);
} catch (\TypeError $e) {
throw new \LogicException(sprintf('Callback for %s "%s" is not callable in the current scope.', $this->getAttribute('type'), $this->getAttribute('name')), 0, $e);
}
$r = new \ReflectionFunction($closure);
if (false !== strpos($r->name, '{closure}')) {
return $this->reflector = [$r, $callable, 'Closure'];
}
if ($object = $r->getClosureThis()) {
$callable = [$object, $r->name];
$callableName = (\function_exists('get_debug_type') ? get_debug_type($object) : \get_class($object)).'::'.$r->name;
} elseif ($class = $r->getClosureScopeClass()) {
$callableName = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name;
} else {
$callable = $callableName = $r->name;
}
if ($checkVisibility && \is_array($callable) && method_exists(...$callable) && !(new \ReflectionMethod(...$callable))->isPublic()) {
$callable = $r->getClosure();
}
return $this->reflector = [$r, $callable, $callableName];
}
}

View File

@@ -58,7 +58,7 @@ class Parser
public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode
{
$vars = get_object_vars($this);
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']);
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']);
$this->stack[] = $vars;
// node visitors
@@ -78,7 +78,6 @@ class Parser
$this->blockStack = [];
$this->importedSymbols = [[]];
$this->embeddedTemplates = [];
$this->varNameSalt = 0;
try {
$body = $this->subparse($test, $dropNeedle);

View File

@@ -19,17 +19,27 @@ namespace Twig\Sandbox;
interface SecurityPolicyInterface
{
/**
* @param string[] $tags
* @param string[] $filters
* @param string[] $functions
*
* @throws SecurityError
*/
public function checkSecurity($tags, $filters, $functions): void;
/**
* @param object $obj
* @param string $method
*
* @throws SecurityNotAllowedMethodError
*/
public function checkMethodAllowed($obj, $method): void;
/**
* @param object $obj
* @param string $property
*
* @throws SecurityNotAllowedPropertyError
*/
public function checkPropertyAllowed($obj, $method): void;
public function checkPropertyAllowed($obj, $property): void;
}

View File

@@ -66,8 +66,9 @@ $qrprovider = new RobThree\Auth\Providers\Qr\QRServerProvider();
$tfa = new RobThree\Auth\TwoFactorAuth($OTP_LABEL, 6, 30, 'sha1', $qrprovider);
// FIDO2
$server_name = parse_url('https://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST);
$formats = $GLOBALS['FIDO2_FORMATS'];
$WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $_SERVER['HTTP_HOST'], $formats);
$WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $server_name, $formats);
// only include root ca's when needed
if (getenv('WEBAUTHN_ONLY_TRUSTED_VENDORS') == 'y') $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates');
@@ -194,9 +195,65 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
// Set language
if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) {
if ($DETECT_LANGUAGE && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$header_lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
if (array_key_exists($header_lang, $AVAILABLE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $header_lang;
// regex inspired from @GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
$langs = $lang_parse[1];
$ranks = $lang_parse[4];
// (create an associative array 'language' => 'preference')
$lang2pref = array();
for ($i=0; $i<count($langs); $i++) {
$lang2pref[strtolower($langs[$i])] = (float) (!empty($ranks[$i]) ? $ranks[$i] : 1);
}
// (comparison function for uksort)
$cmpLangs = function ($a, $b) use ($lang2pref) {
if ($lang2pref[$a] > $lang2pref[$b])
return -1;
elseif ($lang2pref[$a] < $lang2pref[$b])
return 1;
elseif (strlen($a) > strlen($b))
return -1;
elseif (strlen($a) < strlen($b))
return 1;
else
return 0;
};
// sort the languages by prefered language and by the most specific region
uksort($lang2pref, $cmpLangs);
// generate language array without the region part
$AVAILABLE_BASE_LANGUAGES=array();
foreach ($AVAILABLE_LANGUAGES as $code => $lang) {
$base_code = substr($code, 0, 2);
if (!array_key_exists($base_code, $AVAILABLE_BASE_LANGUAGES)) {
$AVAILABLE_BASE_LANGUAGES[$base_code] = $code;
}
}
// Find a perfect match or partial match
// Match en-gb or en
foreach ($lang2pref as $lang => $q) {
if (array_key_exists($lang, $AVAILABLE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $lang;
break;
} elseif (array_key_exists($lang, $AVAILABLE_BASE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $AVAILABLE_BASE_LANGUAGES[$lang];
break;
}
}
// Try suggest match
// e.g. suggest en-gb when only en-us is provided
if (!isset($_COOKIE['mailcow_locale'])) {
foreach ($lang2pref as $lang => $q) {
if (array_key_exists(substr($lang, 0, 2), $AVAILABLE_BASE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $AVAILABLE_BASE_LANGUAGES[substr($lang, 0, 2)];
break;
}
}
}
}
else {
@@ -214,7 +271,7 @@ if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $AVAILABLE_LANGUAGES
/*
* load language
*/
$lang = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.json'), true);
$lang = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en-gb.json'), true);
$langFile = $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.json';
if(file_exists($langFile)) {

View File

@@ -1,24 +1,24 @@
<?php
if (isset($_POST["verify_tfa_login"])) {
if (verify_tfa_login($_SESSION['pending_mailcow_cc_username'], $_POST, $WebAuthn)) {
if (verify_tfa_login($_SESSION['pending_mailcow_cc_username'], $_POST)) {
$_SESSION['mailcow_cc_username'] = $_SESSION['pending_mailcow_cc_username'];
$_SESSION['mailcow_cc_role'] = $_SESSION['pending_mailcow_cc_role'];
unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_method']);
unset($_SESSION['pending_tfa_methods']);
header("Location: /user");
} else {
unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_method']);
unset($_SESSION['pending_tfa_methods']);
}
}
if (isset($_GET["cancel_tfa_login"])) {
unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_method']);
unset($_SESSION['pending_tfa_methods']);
header("Location: /");
}
@@ -34,6 +34,7 @@ if (isset($_POST["quick_delete"])) {
if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
$login_user = strtolower(trim($_POST["login_user"]));
$as = check_login($login_user, $_POST["pass_user"]);
if ($as == "admin") {
$_SESSION['mailcow_cc_username'] = $login_user;
$_SESSION['mailcow_cc_role'] = "admin";
@@ -47,22 +48,22 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
elseif ($as == "user") {
$_SESSION['mailcow_cc_username'] = $login_user;
$_SESSION['mailcow_cc_role'] = "user";
$http_parameters = explode('&', $_SESSION['index_query_string']);
unset($_SESSION['index_query_string']);
if (in_array('mobileconfig', $http_parameters)) {
if (in_array('only_email', $http_parameters)) {
header("Location: /mobileconfig.php?email_only");
die();
}
header("Location: /mobileconfig.php");
die();
}
$http_parameters = explode('&', $_SESSION['index_query_string']);
unset($_SESSION['index_query_string']);
if (in_array('mobileconfig', $http_parameters)) {
if (in_array('only_email', $http_parameters)) {
header("Location: /mobileconfig.php?email_only");
die();
}
header("Location: /mobileconfig.php");
die();
}
header("Location: /user");
}
elseif ($as != "pending") {
unset($_SESSION['pending_mailcow_cc_username']);
unset($_SESSION['pending_mailcow_cc_role']);
unset($_SESSION['pending_tfa_method']);
unset($_SESSION['pending_tfa_methods']);
unset($_SESSION['mailcow_cc_username']);
unset($_SESSION['mailcow_cc_role']);
}

View File

@@ -76,31 +76,35 @@ $autodiscover_config = array(
$DETECT_LANGUAGE = true;
// Change default language
$DEFAULT_LANG = 'en';
$DEFAULT_LANG = 'en-gb';
// Available languages
// https://www.iso.org/obp/ui/#search
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
// https://en.wikipedia.org/wiki/IETF_language_tag
$AVAILABLE_LANGUAGES = array(
'cs' => 'Čeština (Czech)',
'da' => 'Danish (Dansk)',
'de' => 'Deutsch (German)',
'en' => 'English',
'es' => 'Español (Spanish)',
'fi' => 'Suomi (Finish)',
'fr' => 'Français (French)',
'hu' => 'Magyar (Hungarian)',
'it' => 'Italiano (Italian)',
'ko' => '한국어 (Korean)',
'lv' => 'latviešu (Latvian)',
'nl' => 'Nederlands (Dutch)',
'pl' => 'Język Polski (Polish)',
'pt' => 'Português (Portuguese)',
'ro' => 'Română (Romanian)',
'ru' => 'Pусский (Russian)',
'sk' => 'Slovenčina (Slovak)',
'sv' => 'Svenska (Swedish)',
'zh' => '中文 (Chinese)'
// 'ca-es' => 'Català (Catalan)',
'cs-cz' => 'Čeština (Czech)',
'da-dk' => 'Danish (Dansk)',
'de-de' => 'Deutsch (German)',
'en-gb' => 'English',
'es-es' => 'Español (Spanish)',
'fi-fi' => 'Suomi (Finish)',
'fr-fr' => 'Français (French)',
'hu-hu' => 'Magyar (Hungarian)',
'it-it' => 'Italiano (Italian)',
'ko-kr' => '한국어 (Korean)',
'lv-lv' => 'latviešu (Latvian)',
'nl-nl' => 'Nederlands (Dutch)',
'pl-pl' => 'Język Polski (Polish)',
'pt-pt' => 'Português (Portuguese)',
'ro-ro' => 'Română (Romanian)',
'ru-ru' => 'Pусский (Russian)',
'sk-sk' => 'Slovenčina (Slovak)',
'sv-se' => 'Svenska (Swedish)',
'tr-tr' => 'Türkçe (Turkish)',
'uk-ua' => 'Українська (Ukrainian)',
'zh-cn' => '简体中文 (Simplified Chinese)',
'zh-tw' => '繁體中文 (Traditional Chinese)',
);
// Change theme (default: lumen)
@@ -148,6 +152,9 @@ $ACCESS_TOKEN_LIFETIME = 86400;
// Logout from mailcow after first OAuth2 session profile request
$OAUTH2_FORGET_SESSION_AFTER_LOGIN = false;
// Set a limit for mailbox and domain tagging
$TAGGING_LIMIT = 25;
// MAILBOX_DEFAULT_ATTRIBUTES define default attributes for new mailboxes
// These settings will not change existing mailboxes
@@ -224,3 +231,131 @@ $RSPAMD_MAPS = array(
'Monitoring Hosts' => 'monitoring_nolog.map'
)
);
$IMAPSYNC_OPTIONS = array(
'whitelist' => array(
'authmech1',
'authmech2',
'authuser1',
'authuser2',
'debugcontent',
'disarmreadreceipts',
'logdir',
'debugcrossduplicates',
'maxsize',
'minsize',
'minage',
'search',
'noabletosearch',
'pidfile',
'pidfilelocking',
'search1',
'search2',
'sslargs1',
'sslargs2',
'syncduplicates',
'usecache',
'synclabels',
'truncmess',
'domino2',
'expunge1',
'filterbuggyflags',
'justconnect',
'justfolders',
'maxlinelength',
'useheader',
'noabletosearch1',
'nolog',
'prefix1',
'prefix2',
'sep1',
'sep2',
'nofoldersizesatend',
'justfoldersizes',
'proxyauth1',
'skipemptyfolders',
'include',
'subfolder1',
'subscribed',
'subscribe',
'debug',
'debugimap2',
'domino1',
'exchange1',
'exchange2',
'justlogin',
'keepalive1',
'keepalive2',
'noabletosearch2',
'noexpunge2',
'noresyncflags',
'nossl1',
'nouidexpunge2',
'syncinternaldates',
'idatefromheader',
'useuid',
'debugflags',
'debugimap',
'delete1emptyfolders',
'delete2folders',
'gmail2',
'office1',
'testslive6',
'debugimap1',
'errorsmax',
'tests',
'gmail1',
'maxmessagespersecond',
'maxbytesafter',
'maxsleep',
'abort',
'resyncflags',
'resynclabels',
'syncacls',
'nosyncacls',
'nousecache',
'office2',
'testslive',
'debugmemory',
'exitwhenover',
'noid',
'noexpunge1',
'authmd51',
'logfile',
'proxyauth2',
'domain1',
'domain2',
'oauthaccesstoken1',
'oauthaccesstoken2',
'oauthdirect1',
'oauthdirect2',
'folder',
'folderrec',
'folderfirst',
'folderlast',
'nomixfolders',
'authmd52',
'debugfolders',
'nossl2',
'ssl2',
'tls2',
'notls2',
'debugssl',
'notls1',
'inet4',
'inet6',
'log',
'showpasswords'
),
'blacklist' => array(
'skipmess',
'delete2foldersonly',
'delete2foldersbutnot',
'regexflag',
'regexmess',
'pipemess',
'regextrans2',
'maxlinelengthcmd'
)
);

View File

@@ -156,6 +156,12 @@ $(document).ready(function() {
});
if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject();
// parse possible JSON Strings
for (var [key, value] of Object.entries(attr_to_merge)) {
try {
attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
} catch {}
}
var api_attr = $.extend(api_attr, attr_to_merge)
} else {
return false;
@@ -263,6 +269,12 @@ $(document).ready(function() {
});
if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject();
// parse possible JSON Strings
for (var [key, value] of Object.entries(attr_to_merge)) {
try {
attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
} catch {}
}
var api_attr = $.extend(api_attr, attr_to_merge)
} else {
return false;
@@ -329,6 +341,7 @@ $(document).ready(function() {
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
multi_data[id].push($(this).data('item'));
}
if (typeof $(this).data('text') !== 'undefined') {
$("#DeleteText").empty();
$("#DeleteText").text($(this).data('text'));
@@ -340,9 +353,9 @@ $(document).ready(function() {
$("#ItemsToDelete").empty();
for (var i in data_array) {
data_array[i] = decodeURIComponent(data_array[i]);
$("#ItemsToDelete").append("<li>" + data_array[i] + "</li>");
$("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
}
})
});
$('#ConfirmDeleteModal').modal({
backdrop: 'static',
keyboard: false

View File

@@ -48,7 +48,7 @@ $(document).ready(function() {
$(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
}
$(div).animate({ left: 0},interval);
}
}
// form cache
$('[data-cached-form="true"]').formcache({key: $(this).data('id')});
@@ -273,4 +273,51 @@ $(document).ready(function() {
}
}
});
// tag boxes
$('.tag-box .tag-add').click(function(){
addTag(this);
});
$(".tag-box .tag-input").keydown(function (e) {
if (e.which == 13){
e.preventDefault();
addTag(this);
}
});
function addTag(tagAddElem){
var tagboxElem = $(tagAddElem).parent();
var tagInputElem = $(tagboxElem).find(".tag-input")[0];
var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
var tag = escapeHtml($(tagInputElem).val());
if (!tag) return;
var value_tags = [];
try {
value_tags = JSON.parse($(tagValuesElem).val());
} catch {}
if (!Array.isArray(value_tags)) value_tags = [];
if (value_tags.includes(tag)) return;
$('<span class="badge badge-primary tag-badge btn-badge"><i class="bi bi-tag-fill"></i> ' + tag + '</span>').insertBefore('.tag-input').click(function(){
var del_tag = unescapeHtml($(this).text());
var del_tags = [];
try {
del_tags = JSON.parse($(tagValuesElem).val());
} catch {}
if (Array.isArray(del_tags)){
del_tags.splice(del_tags.indexOf(del_tag), 1);
$(tagValuesElem).val(JSON.stringify(del_tags));
}
$(this).remove();
});
value_tags.push($(tagInputElem).val());
$(tagValuesElem).val(JSON.stringify(value_tags));
$(tagInputElem).val('');
}
});
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
function escapeHtml(n){var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function unescapeHtml(t){var n={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#x2F;":"/","&#x60;":"`","&#x3D;":"="};return String(t).replace(/&amp;|&lt;|&gt;|&quot;|&#39;|&#x2F|&#x60|&#x3D;/g,function(t){return n[t]})}

View File

@@ -99,37 +99,6 @@ $(document).ready(function() {
});
auto_fill_quota($('#addSelectDomain').val());
// Read bcc local dests
// Using ajax to not be a blocking moo
$.get("/api/v1/get/bcc-destination-options", function(data){
// Domains
var optgroup = "<optgroup label='" + lang.domains + "'>";
$.each(data.domains, function(index, domain){
optgroup += "<option value='" + domain + "'>" + domain + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
// Alias domains
var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
$.each(data.alias_domains, function(index, alias_domain){
optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
// Mailboxes and aliases
$.each(data.mailboxes, function(mailbox, aliases){
var optgroup = "<optgroup label='" + mailbox + "'>";
$.each(aliases, function(index, alias){
optgroup += "<option value='" + alias + "'>" + alias + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
});
// Finish
$('#bcc-local-dest').find('option:selected').remove();
$('#bcc-local-dest').selectpicker('refresh');
});
$(".goto_checkbox").click(function( event ) {
$("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
@@ -236,9 +205,6 @@ $(document).ready(function() {
});
jQuery(function($){
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
function unix_time_format(i){return""==i?'<i class="bi bi-x-lg"></i>':new Date(i?1e3*i:0).toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}
@@ -293,6 +259,7 @@ jQuery(function($){
{"name":"rl","title":"RL","breakpoints":"xs sm md lg","style":{"min-width":"100px","width":"100px"}},
{"name":"backupmx","filterable": false,"style":{"min-width":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md lg","formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
{"name":"domain_admins","title":lang.domain_admins,"style":{"word-break":"break-all","min-width":"200px"},"breakpoints":"xs sm md lg","filterable":(role == "admin"),"visible":(role == "admin")},
{"name":"tags","title":"Tags","style":{},"breakpoints":"xs sm md lg"},
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
@@ -330,6 +297,13 @@ jQuery(function($){
'<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
}
if (Array.isArray(item.tags)){
var tags = '';
for (var i = 0; i < item.tags.length; i++)
tags += '<span class="badge badge-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
item.tags = tags;
}
if (item.backupmx == 1) {
if (item.relay_unknown_only == 1) {
item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
@@ -418,6 +392,7 @@ jQuery(function($){
},
{"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
/* {"name":"rl","title":"RL","breakpoints":"all","style":{"width":"125px"}}, */
{"name":"tags","title":"Tags","style":{},"breakpoints":"xs sm md lg"},
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':(0==value?'<i class="bi bi-x-lg"></i>':2==value&&'&#8212;');}},
{"name":"action","filterable": false,"sortable": false,"style":{"min-width":"290px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
@@ -497,6 +472,13 @@ jQuery(function($){
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
item.username = escapeHtml(item.username);
if (Array.isArray(item.tags)){
var tags = '';
for (var i = 0; i < item.tags.length; i++)
tags += '<span class="badge badge-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
item.tags = tags;
}
});
}
}),
@@ -571,6 +553,7 @@ jQuery(function($){
'</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.name = escapeHtml(item.name);
item.description = escapeHtml(item.description);
});
}
}),
@@ -610,6 +593,37 @@ jQuery(function($){
});
}
function draw_bcc_table() {
// Read bcc local dests
// Using ajax to not be a blocking moo
$.get("/api/v1/get/bcc-destination-options", function(data){
// Domains
var optgroup = "<optgroup label='" + lang.domains + "'>";
$.each(data.domains, function(index, domain){
optgroup += "<option value='" + domain + "'>" + domain + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
// Alias domains
var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
$.each(data.alias_domains, function(index, alias_domain){
optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
// Mailboxes and aliases
$.each(data.mailboxes, function(mailbox, aliases){
var optgroup = "<optgroup label='" + mailbox + "'>";
$.each(aliases, function(index, alias){
optgroup += "<option value='" + alias + "'>" + alias + "</option>"
});
optgroup += "</optgroup>"
$('#bcc-local-dest').append(optgroup);
});
// Finish
$('#bcc-local-dest').find('option:selected').remove();
$('#bcc-local-dest').selectpicker('refresh');
});
ft_bcc_table = FooTable.init('#bcc_table', {
"columns": [
{"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
@@ -1009,7 +1023,7 @@ jQuery(function($){
if (!item.exclude > 0) {
item.exclude = '-';
} else {
item.exclude = '<code>' + item.exclude + '</code>';
item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>';
}
item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
item.action = '<div class="btn-group footable-actions">' +
@@ -1147,15 +1161,33 @@ jQuery(function($){
event.stopPropagation();
})
draw_domain_table();
draw_mailbox_table();
draw_resource_table();
draw_alias_table();
draw_aliasdomain_table();
draw_sync_job_table();
draw_filter_table();
draw_bcc_table();
draw_recipient_map_table();
draw_tls_policy_table();
// detect element visibility changes
function onVisible(element, callback) {
$(element).ready(function() {
element_object = document.querySelector(element)
new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.intersectionRatio > 0) {
callback(element_object);
observer.disconnect();
}
});
}).observe(element_object);
});
}
// Load only if the tab is visible
onVisible("[id^=tab-domains]", () => draw_domain_table());
onVisible("[id^=tab-mailboxes]", () => draw_mailbox_table());
onVisible("[id^=tab-resources]", () => draw_resource_table());
onVisible("[id^=tab-mbox-aliases]", () => draw_alias_table());
onVisible("[id^=tab-domain-aliases]", () => draw_aliasdomain_table());
onVisible("[id^=tab-syncjobs]", () => draw_sync_job_table());
onVisible("[id^=tab-filters]", () => draw_filter_table());
onVisible("[id^=tab-bcc]", () => {
draw_bcc_table();
draw_recipient_map_table();
});
onVisible("[id^=tab-tls-policy]", () => draw_tls_policy_table());
});

View File

@@ -14,17 +14,20 @@ function api_log($_data) {
if ($data == 'csrf_token') {
continue;
}
if ($value = json_decode($value, true)) {
unset($value["csrf_token"]);
$value = json_decode($value, true);
if ($value) {
if (is_array($value)) unset($value["csrf_token"]);
foreach ($value as $key => &$val) {
if(preg_match("/pass/i", $key)) {
$val = '*';
}
}
$value = json_encode($value);
$value = json_encode($value);
}
$data_var[] = $data . "='" . $value . "'";
}
try {
$log_line = array(
'time' => time(),
@@ -41,7 +44,7 @@ function api_log($_data) {
'msg' => 'Redis: '.$e
);
return false;
}
}
}
if (isset($_GET['query'])) {
@@ -82,10 +85,10 @@ if (isset($_GET['query'])) {
if ($action == 'delete') {
$_POST['items'] = $request;
}
}
api_log($_POST);
$request_incomplete = json_encode(array(
'type' => 'error',
'msg' => 'Cannot find attributes in post data'
@@ -175,15 +178,22 @@ if (isset($_GET['query'])) {
// parse post data
$post = trim(file_get_contents('php://input'));
if ($post) $post = json_decode($post);
// decode base64 strings
$clientDataJSON = base64_decode($post->clientDataJSON);
$attestationObject = base64_decode($post->attestationObject);
// process registration data from authenticator
try {
// decode base64 strings
$clientDataJSON = base64_decode($post->clientDataJSON);
$attestationObject = base64_decode($post->attestationObject);
// processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true, $failIfRootMismatch=true)
$data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $_SESSION['challenge'], false, true);
// safe authenticator in mysql `tfa` table
$_data['tfa_method'] = $post->tfa_method;
$_data['key_id'] = $post->key_id;
$_data['confirm_password'] = $post->confirm_password;
$_data['registration'] = $data;
set_tfa($_data);
}
catch (Throwable $ex) {
// err
@@ -194,11 +204,6 @@ if (isset($_GET['query'])) {
exit;
}
// safe authenticator in mysql `tfa` table
$_data['tfa_method'] = $post->tfa_method;
$_data['key_id'] = $post->key_id;
$_data['registration'] = $data;
set_tfa($_data);
// send response
$return = new stdClass();
@@ -416,7 +421,7 @@ if (isset($_GET['query'])) {
// }
$ids = NULL;
$getArgs = $WebAuthn->getGetArgs($ids, 30, true, true, true, true, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
$getArgs = $WebAuthn->getGetArgs($ids, 30, false, false, false, false, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
print(json_encode($getArgs));
$_SESSION['challenge'] = $WebAuthn->getChallenge();
return;
@@ -425,8 +430,11 @@ if (isset($_GET['query'])) {
case "webauthn-tfa-registration":
if (isset($_SESSION["mailcow_cc_role"])) {
// Exclude existing CredentialIds, if any
$stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username");
$stmt->execute(array(':username' => $_SESSION['mailcow_cc_username']));
$stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
$stmt->execute(array(
':username' => $_SESSION['mailcow_cc_username'],
':authmech' => 'webauthn'
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$excludeCredentialIds[] = base64_decode($row['keyHandle']);
@@ -447,20 +455,24 @@ if (isset($_GET['query'])) {
}
break;
case "webauthn-tfa-get-args":
$stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username");
$stmt->execute(array(':username' => $_SESSION['pending_mailcow_cc_username']));
$stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
$stmt->execute(array(
':username' => $_SESSION['pending_mailcow_cc_username'],
':authmech' => 'webauthn'
));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while($row = array_shift($rows)) {
$cids[] = base64_decode($row['keyHandle']);
}
if (count($cids) == 0) {
if (count($rows) == 0) {
print(json_encode(array(
'type' => 'error',
'msg' => 'Cannot find matching credentialIds'
)));
exit;
}
while($row = array_shift($rows)) {
$cids[] = base64_decode($row['keyHandle']);
}
$getArgs = $WebAuthn->getGetArgs($cids, 30, true, true, true, true, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN']);
$getArgs = $WebAuthn->getGetArgs($cids, 30, false, false, false, false, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN']);
$getArgs->publicKey->extensions = array('appid' => "https://".$getArgs->publicKey->rpId);
print(json_encode($getArgs));
$_SESSION['challenge'] = $WebAuthn->getChallenge();
@@ -486,7 +498,12 @@ if (isset($_GET['query'])) {
case "domain":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
$tags = null;
if (isset($_GET['tags']) && $_GET['tags'] != '')
$tags = explode(',', $_GET['tags']);
$domains = mailbox('get', 'domains', null, $tags);
if (!empty($domains)) {
foreach ($domains as $domain) {
if ($details = mailbox('get', 'domain_details', $domain)) {
@@ -952,23 +969,20 @@ if (isset($_GET['query'])) {
switch ($object) {
case "all":
case "reduced":
if (empty($extra)) {
$domains = mailbox('get', 'domains');
}
else {
$domains = explode(',', $extra);
}
$tags = null;
if (isset($_GET['tags']) && $_GET['tags'] != '')
$tags = explode(',', $_GET['tags']);
if (empty($extra)) $domains = mailbox('get', 'domains');
else $domains = explode(',', $extra);
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
$mailboxes = mailbox('get', 'mailboxes', $domain, $tags);
if (!empty($mailboxes)) {
foreach ($mailboxes as $mailbox) {
if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) {
$data[] = $details;
}
else {
continue;
}
if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) $data[] = $details;
else continue;
}
}
}
@@ -980,8 +994,23 @@ if (isset($_GET['query'])) {
break;
default:
$data = mailbox('get', 'mailbox_details', $object);
process_get_return($data);
$tags = null;
if (isset($_GET['tags']) && $_GET['tags'] != '')
$tags = explode(',', $_GET['tags']);
if ($tags === null) {
$data = mailbox('get', 'mailbox_details', $object);
process_get_return($data);
} else {
$mailboxes = mailbox('get', 'mailboxes', $object, $tags);
if (is_array($mailboxes)) {
foreach ($mailboxes as $mailbox) {
if ($details = mailbox('get', 'mailbox_details', $mailbox))
$data[] = $details;
}
}
process_get_return($data, false);
}
break;
}
break;
@@ -1472,6 +1501,11 @@ if (isset($_GET['query'])) {
'solr_documents' => $solr_documents
));
break;
case "version":
echo json_encode(array(
'version' => $GLOBALS['MAILCOW_GIT_VERSION']
));
break;
}
}
break;
@@ -1575,13 +1609,25 @@ if (isset($_GET['query'])) {
process_delete_return(dkim('delete', array('domains' => $items)));
break;
case "domain":
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
switch ($object){
case "tag":
process_delete_return(mailbox('delete', 'tags_domain', array('tags' => $items, 'domain' => $extra)));
break;
default:
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
}
break;
case "alias-domain":
process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
break;
case "mailbox":
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
switch ($object){
case "tag":
process_delete_return(mailbox('delete', 'tags_mailbox', array('tags' => $items, 'username' => $extra)));
break;
default:
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
}
break;
case "resource":
process_delete_return(mailbox('delete', 'resource', array('name' => $items)));

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