Jan(moo)uary Update 2022 - Revision A (2022-01a) (#4445)

* [API] Fix minor issue in api docs

* [GH-Actions][stale] Add neverstale label to exempt list

* [Web] add github version tag

* [Web] add github version tag error handling

* Passwordless SOGo auth: support for calendar invitations and calendar/contacts subscriptions

Inviting someone to a calendar event triggers a request to /SOGo/so/otheruser@example.com/freebusy.ifb/ajaxRead. Subscribing to someone's calendar/contacts triggers a request to /SOGo/so/otheruser@example.com/foldersSearch. The email address in the URL is different from the logged-in user, which needs to be handled appropriately by sogo-auth.php.

* [Web] add github version tag - adjust css

* [Compose] Update SOGo Autoreply Schedule to 5m

Based on the advice of inverse (SOGo developer). Thanks to https://github.com/jmber

Closes: https://github.com/mailcow/mailcow-dockerized/issues/4436

* [Web] add github version tag - move twig globals

* [Web] add github version tag - missing </div>

* Passwordless SOGo auth: improvements for when accessing other users

* [WebAuthn] fido2 passwordless auth - fix (#4440)

* [WebAuthn] fido2 revert

* [WebAuthn] set UV flags to 'discouraged'

* [WebAuthn] revert - set UV flags to 'discouraged'

Co-authored-by: ntimo <git@nowitzki.me>
Co-authored-by: Peter <magic@kthx.at>
Co-authored-by: FreddleSpl0it <patschul@posteo.de>
Co-authored-by: FreddleSpl0it <75116288+FreddleSpl0it@users.noreply.github.com>
Co-authored-by: Michael Kuron <mkuron@users.noreply.github.com>
This commit is contained in:
Niklas Meyer 2022-02-01 15:26:48 +01:00 committed by GitHub
parent 5a1ef72b82
commit 89fdd1986d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 112 additions and 50 deletions

1
.gitignore vendored
View File

@ -56,6 +56,7 @@ data/web/templates/cache/*
data/web/.well-known/acme-challenge data/web/.well-known/acme-challenge
data/web/css/build/0081-custom-mailcow.css data/web/css/build/0081-custom-mailcow.css
data/web/inc/vars.local.inc.php data/web/inc/vars.local.inc.php
data/web/inc/app_info.inc.php
data/web/nextcloud*/ data/web/nextcloud*/
data/web/rc*/ data/web/rc*/
docker-compose.override.yml docker-compose.override.yml

View File

@ -4805,7 +4805,7 @@ paths:
schema: schema:
example: example:
attr: attr:
rl_vlaue: "10" rl_value: "10"
rl_frame: "h" rl_frame: "h"
items: items:
- info@domain.tld - info@domain.tld
@ -4815,7 +4815,7 @@ paths:
rl_frame: rl_frame:
description: contains the frame for the ratelimit h,s,m description: contains the frame for the ratelimit h,s,m
type: string type: string
rl_vlaue: rl_value:
description: contains the rate for the ratelimit 10,20,50,1 description: contains the rate for the ratelimit 10,20,50,1
type: number type: number
type: object type: object
@ -4876,7 +4876,7 @@ paths:
schema: schema:
example: example:
attr: attr:
rl_vlaue: "10" rl_value: "10"
rl_frame: "h" rl_frame: "h"
items: items:
- domain.tld - domain.tld
@ -4886,7 +4886,7 @@ paths:
rl_frame: rl_frame:
description: contains the frame for the ratelimit h,s,m description: contains the frame for the ratelimit h,s,m
type: string type: string
rl_vlaue: rl_value:
description: contains the rate for the ratelimit 10,20,50,1 description: contains the rate for the ratelimit 10,20,50,1
type: number type: number
type: object type: object

View File

@ -202,6 +202,11 @@ legend {
margin-top: 27px; margin-top: 27px;
margin-bottom: 20px; margin-bottom: 20px;
color: #959595; color: #959595;
display: flex;
flex-direction: column;
}
.footer .version {
margin-left: auto;
} }
.slave-info { .slave-info {
padding: 15px 0px 15px 15px; padding: 15px 0px 15px 15px;

View File

@ -23,7 +23,12 @@ if (is_array($alertbox_log_parser)) {
unset($_SESSION['return']); unset($_SESSION['return']);
} }
// globals
$globalVariables = [ $globalVariables = [
'mailcow_info' => array(
'version_tag' => $GLOBALS['MAILCOW_GIT_VERSION'],
'git_project_url' => $GLOBALS['MAILCOW_GIT_URL']
),
'js_path' => '/cache/'.basename($JSPath), 'js_path' => '/cache/'.basename($JSPath),
'pending_tfa_method' => @$_SESSION['pending_tfa_method'], 'pending_tfa_method' => @$_SESSION['pending_tfa_method'],
'pending_mailcow_cc_username' => @$_SESSION['pending_mailcow_cc_username'], 'pending_mailcow_cc_username' => @$_SESSION['pending_mailcow_cc_username'],

View File

@ -10,11 +10,17 @@ $DEV_MODE = (getenv('DEV_MODE') == 'y');
}*/ }*/
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
$default_autodiscover_config = $autodiscover_config; $default_autodiscover_config = $autodiscover_config;
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) { if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php'; include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
} }
// auto-generated by generate-config.sh and update.sh
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/app_info.inc.php')) {
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/app_info.inc.php';
}
unset($https_port); unset($https_port);
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config); $autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);

View File

@ -24,4 +24,4 @@ $twig->addFunction(new TwigFunction('is_uri', function (string $uri, string $whe
// filters // filters
$twig->addFilter(new TwigFilter('rot13', 'str_rot13')); $twig->addFilter(new TwigFilter('rot13', 'str_rot13'));
$twig->addFilter(new TwigFilter('base64_encode', 'base64_encode')); $twig->addFilter(new TwigFilter('base64_encode', 'base64_encode'));
$twig->addFilter(new TwigFilter('formatBytes', 'formatBytes')); $twig->addFilter(new TwigFilter('formatBytes', 'formatBytes'));

View File

@ -409,16 +409,14 @@ if (isset($_GET['query'])) {
break; break;
case "fido2-get-args": case "fido2-get-args":
header('Content-Type: application/json'); header('Content-Type: application/json');
// fetch allowed credentialIds // Login without username, no ids!
$cids = fido2(array("action" => "get_all_cids")); // $ids = fido2(array("action" => "get_all_cids"));
if (count($cids) == 0) { // if (count($ids) == 0) {
print(json_encode(array( // return;
'type' => 'error', // }
'msg' => 'Cannot find matching credentialIds' $ids = NULL;
)));
}
$getArgs = $WebAuthn->getGetArgs($cids, 30, true, true, true, true, $GLOBALS['FIDO2_UV_FLAG_LOGIN']); $getArgs = $WebAuthn->getGetArgs($ids, 30, true, true, true, true, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
print(json_encode($getArgs)); print(json_encode($getArgs));
$_SESSION['challenge'] = $WebAuthn->getChallenge(); $_SESSION['challenge'] = $WebAuthn->getChallenge();
return; return;

View File

@ -75,20 +75,26 @@ elseif (isset($_SERVER['HTTP_X_ORIGINAL_URI']) && strcasecmp(substr($_SERVER['HT
session_start(); session_start();
// extract email address from "/SOGo/so/user@domain/xy" // extract email address from "/SOGo/so/user@domain/xy"
$url_parts = explode("/", $_SERVER['HTTP_X_ORIGINAL_URI']); $url_parts = explode("/", $_SERVER['HTTP_X_ORIGINAL_URI']);
$email = $url_parts[3]; $email_list = array(
// check if this email is in session allowed list $url_parts[3], // Requested mailbox
if ( ($_SESSION['mailcow_cc_username'] ?? ''), // Current user
!empty($email) && ($_SESSION["dual-login"]["username"] ?? ''), // Dual login user
filter_var($email, FILTER_VALIDATE_EMAIL) && );
is_array($_SESSION[$session_var_user_allowed]) && foreach($email_list as $email) {
in_array($email, $_SESSION[$session_var_user_allowed]) // check if this email is in session allowed list
) { if (
$username = $email; !empty($email) &&
$password = $_SESSION[$session_var_pass]; filter_var($email, FILTER_VALIDATE_EMAIL) &&
header("X-User: $username"); is_array($_SESSION[$session_var_user_allowed]) &&
header("X-Auth: Basic ".base64_encode("$username:$password")); in_array($email, $_SESSION[$session_var_user_allowed])
header("X-Auth-Type: Basic"); ) {
exit; $username = $email;
$password = $_SESSION[$session_var_pass];
header("X-User: $username");
header("X-Auth: Basic ".base64_encode("$username:$password"));
header("X-Auth-Type: Basic");
exit;
}
} }
} }

View File

@ -38,22 +38,24 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{% include 'admin/tab-config-admins.twig' %} <div class="tab-content" style="padding-top:20px">
{% include 'admin/tab-ldap.twig' %} {% include 'admin/tab-config-admins.twig' %}
{% include 'admin/tab-config-oauth2.twig' %} {% include 'admin/tab-ldap.twig' %}
{% include 'admin/tab-config-rspamd.twig' %} {% include 'admin/tab-config-oauth2.twig' %}
{% include 'admin/tab-routing.twig' %} {% include 'admin/tab-config-rspamd.twig' %}
{% include 'admin/tab-config-dkim.twig' %} {% include 'admin/tab-routing.twig' %}
{% include 'admin/tab-config-fwdhosts.twig' %} {% include 'admin/tab-config-dkim.twig' %}
{% include 'admin/tab-config-f2b.twig' %} {% include 'admin/tab-config-fwdhosts.twig' %}
{% include 'admin/tab-config-quarantine.twig' %} {% include 'admin/tab-config-f2b.twig' %}
{% include 'admin/tab-config-quota.twig' %} {% include 'admin/tab-config-quarantine.twig' %}
{% include 'admin/tab-config-rsettings.twig' %} {% include 'admin/tab-config-quota.twig' %}
{% include 'admin/tab-config-customize.twig' %} {% include 'admin/tab-config-rsettings.twig' %}
{% include 'admin/tab-config-password-policy.twig' %} {% include 'admin/tab-config-customize.twig' %}
{% include 'admin/tab-sys-mails.twig' %} {% include 'admin/tab-config-password-policy.twig' %}
{% include 'admin/tab-mailq.twig' %} {% include 'admin/tab-sys-mails.twig' %}
{% include 'admin/tab-globalfilter-regex.twig' %} {% include 'admin/tab-mailq.twig' %}
{% include 'admin/tab-globalfilter-regex.twig' %}
</div>
</div> <!-- /col-md-12 --> </div> <!-- /col-md-12 -->
</div> <!-- /row --> </div> <!-- /row -->

View File

@ -1,5 +1,4 @@
<div class="tab-content" style="padding-top:20px"> <div role="tabpanel" class="tab-pane active" id="tab-config-admins">
<div role="tabpanel" class="tab-pane active" id="tab-config-admins">
<div class="panel panel-danger"> <div class="panel panel-danger">
<div class="panel-heading xs-show">{{ lang.admin.admin_details }}</div> <div class="panel-heading xs-show">{{ lang.admin.admin_details }}</div>
<div class="panel-body"> <div class="panel-body">
@ -61,7 +60,8 @@
<th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th> <th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th>
</tr> </tr>
{% include 'fido2.twig' %} {% include 'fido2.twig' %}
</table> </table>
</div>
</div> </div>
<br> <br>
</div> </div>
@ -221,8 +221,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading xs-show">{{ lang.admin.domain_admins }}</div> <div class="panel-heading xs-show">{{ lang.admin.domain_admins }}</div>
<div class="panel-body"> <div class="panel-body">
@ -248,3 +246,4 @@
</div> </div>
</div> </div>
</div> </div>

View File

@ -423,6 +423,14 @@ function recursiveBase64StrToArrayBuffer(obj) {
{% if ui_texts.ui_footer %} {% if ui_texts.ui_footer %}
<hr><span class="rot-enc">{{ ui_texts.ui_footer|rot13|raw }}</span> <hr><span class="rot-enc">{{ ui_texts.ui_footer|rot13|raw }}</span>
{% endif %} {% endif %}
{% if mailcow_cc_username and mailcow_info.version_tag|default %}
<span class="version">
🐮 + 🐋 = 💕
<a href="{{ mailcow_info.git_project_url }}/releases/tag/{{ mailcow_info.version_tag }}" target="_blank">
Version: {{ mailcow_info.version_tag }}
</a>
</span>
{% endif %}
</div> </div>
</body> </body>
</html> </html>

View File

@ -200,7 +200,7 @@ services:
ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\"" ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\""
ofelia.job-exec.sogo_ealarms.schedule: "@every 1m" ofelia.job-exec.sogo_ealarms.schedule: "@every 1m"
ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/sieve.creds || exit 0\"" ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/sieve.creds || exit 0\""
ofelia.job-exec.sogo_eautoreply.schedule: "@every 24h" ofelia.job-exec.sogo_eautoreply.schedule: "@every 5m"
ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\"" ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\""
ofelia.job-exec.sogo_backup.schedule: "@every 24h" ofelia.job-exec.sogo_backup.schedule: "@every 24h"
ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\"" ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\""

View File

@ -361,3 +361,19 @@ echo "Generating snake-oil certificate..."
openssl req -x509 -newkey rsa:4096 -keyout data/assets/ssl-example/key.pem -out data/assets/ssl-example/cert.pem -days 365 -subj "/C=DE/ST=NRW/L=Willich/O=mailcow/OU=mailcow/CN=${MAILCOW_HOSTNAME}" -sha256 -nodes openssl req -x509 -newkey rsa:4096 -keyout data/assets/ssl-example/key.pem -out data/assets/ssl-example/cert.pem -days 365 -subj "/C=DE/ST=NRW/L=Willich/O=mailcow/OU=mailcow/CN=${MAILCOW_HOSTNAME}" -sha256 -nodes
echo "Copying snake-oil certificate..." echo "Copying snake-oil certificate..."
cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/ cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/
# Set app_info.inc.php
mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $? -eq 0 ]; then
mailcow_git_url=$(git config --get remote.origin.url)
echo '<?php' > data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_URL="'$mailcow_git_url'";' >> data/web/inc/app_info.inc.php
echo '?>' >> data/web/inc/app_info.inc.php
else
echo '<?php' > data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_VERSION="";' >> data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_URL="";' >> data/web/inc/app_info.inc.php
echo '?>' >> data/web/inc/app_info.inc.php
echo -e "\e[33mCannot determine current git repository version...\e[0m"
fi

View File

@ -719,6 +719,22 @@ if [ -f "data/conf/rspamd/local.d/metrics.conf" ]; then
mv data/conf/rspamd/local.d/metrics.conf data/conf/rspamd/local.d/metrics.conf_deprecated mv data/conf/rspamd/local.d/metrics.conf data/conf/rspamd/local.d/metrics.conf_deprecated
fi fi
# Set app_info.inc.php
mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`)
if [ $? -eq 0 ]; then
mailcow_git_url=$(git config --get remote.origin.url)
echo '<?php' > data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_URL="'$mailcow_git_url'";' >> data/web/inc/app_info.inc.php
echo '?>' >> data/web/inc/app_info.inc.php
else
echo '<?php' > data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_VERSION="";' >> data/web/inc/app_info.inc.php
echo ' $MAILCOW_GIT_URL="";' >> data/web/inc/app_info.inc.php
echo '?>' >> data/web/inc/app_info.inc.php
echo -e "\e[33mCannot determine current git repository version...\e[0m"
fi
if [[ ${SKIP_START} == "y" ]]; then if [[ ${SKIP_START} == "y" ]]; then
echo -e "\e[33mNot starting mailcow, please run \"docker-compose up -d --remove-orphans\" to start mailcow.\e[0m" echo -e "\e[33mNot starting mailcow, please run \"docker-compose up -d --remove-orphans\" to start mailcow.\e[0m"
else else