Compare commits

..

4 Commits

Author SHA1 Message Date
Ashitaka
e8d9315d4a Merge pull request #6905 from Ashitaka57/6646-pbkdf2-sha512-verify-hash
Support for PBKDF2-SHA512 hash algorithm in verify_hash() (FreeIPA compatibility) (issue 6646)
2025-12-12 14:08:21 +01:00
DerLinkman
d977ddb501 backup: add image prefetch function to verify latest image is used 2025-12-12 14:07:57 +01:00
DerLinkman
e76f5237ed ofelia: revert fixed cron syntax for sa-rules download 2025-12-12 14:07:47 +01:00
Copilot
c11ed5dd1e Prevent duplicate/plaintext login announcement rendering (#6963)
* Initial plan

* Fix duplicate login announcement display

Co-authored-by: DerLinkman <62480600+DerLinkman@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: DerLinkman <62480600+DerLinkman@users.noreply.github.com>
2025-12-12 14:07:36 +01:00
5 changed files with 72 additions and 41 deletions

View File

@@ -139,13 +139,9 @@ docker_daemon_edit(){
exit 1
fi
else
echo -e "${YELLOW}User declined Docker update skipping Docker daemon configuration.${NC}"
echo -e "${YELLOW}IPv6 will be disabled for mailcow.${NC}"
echo ""
echo -e "${YELLOW}If you change your mind later, please insert these changes manually to $DOCKER_DAEMON_CONFIG:${NC}"
echo -e "${YELLOW}User declined Docker update please insert these changes manually:${NC}"
echo "${MISSING[*]}"
echo ""
return 1
exit 1
fi
fi
@@ -189,23 +185,9 @@ EOF
(command -v systemctl &>/dev/null && systemctl restart docker) || service docker restart
echo "Docker restarted."
else
echo -e "${YELLOW}User declined to create daemon.json skipping Docker daemon configuration.${NC}"
echo -e "${YELLOW}IPv6 will be disabled for mailcow.${NC}"
echo ""
echo -e "${YELLOW}If you change your mind later, please create $DOCKER_DAEMON_CONFIG with these settings:${NC}"
if [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 27 ]]; then
echo ' "ipv6": true,'
echo ' "fixed-cidr-v6": "fd00:dead:beef:c0::/80",'
echo ' "ip6tables": true,'
echo ' "experimental": true'
elif [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 28 ]]; then
echo ' "ipv6": true,'
echo ' "fixed-cidr-v6": "fd00:dead:beef:c0::/80"'
else
echo ' "ipv6": true'
fi
echo ""
return 1
echo "User declined to create daemon.json please manually merge the docker daemon with these configs:"
echo "${MISSING[*]}"
exit 1
fi
fi
}
@@ -241,22 +223,7 @@ configure_ipv6() {
return
fi
if ! docker_daemon_edit; then
# User declined Docker daemon configuration
# When called from update.sh, MAILCOW_CONF is set and we modify the existing file
# When called from generate_config.sh, MAILCOW_CONF is not set and we export IPV6_BOOL
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
sed -i 's/^ENABLE_IPV6=.*/ENABLE_IPV6=false/' "$MAILCOW_CONF"
else
echo "ENABLE_IPV6=false" >> "$MAILCOW_CONF"
fi
else
export IPV6_BOOL=false
fi
echo "IPv6 configuration complete: ENABLE_IPV6=false"
return 0
fi
docker_daemon_edit
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then

View File

@@ -814,6 +814,32 @@ function verify_hash($hash, $password) {
$hash = $components[4];
return hash_equals(hash_pbkdf2('sha1', $password, $salt, $rounds), $hash);
case "PBKDF2-SHA512":
// Handle FreeIPA-style hash: {PBKDF2-SHA512}10000$<base64_salt>$<base64_hash>
$components = explode('$', $hash);
if (count($components) !== 3) return false;
// 1st part: iteration count (integer)
$iterations = intval($components[0]);
if ($iterations <= 0) return false;
// 2nd part: salt (base64-encoded)
$salt = $components[1];
// 3rd part: hash (base64-encoded)
$stored_hash_b64 = $components[2];
// Decode salt and hash from base64
$salt_bin = base64_decode($salt, true);
$hash_bin = base64_decode($stored_hash_b64, true);
if ($salt_bin === false || $hash_bin === false) return false;
// Get length of hash in bytes
$hash_len = strlen($hash_bin);
if ($hash_len === 0) return false;
// Calculate PBKDF2-SHA512 hash for provided password
$test_hash = hash_pbkdf2('sha512', $password, $salt_bin, $iterations, $hash_len, true);
return hash_equals($hash_bin, $test_hash);
case "PLAIN-MD4":
return hash_equals(hash('md4', $password), $hash);

View File

@@ -144,7 +144,7 @@
<form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active and not is_root_uri %}
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active and not is_root_uri and mailcow_cc_username %}
<div class="container mt-4">
<div class="alert alert-{{ ui_texts.ui_announcement_type }}">{{ ui_texts.ui_announcement_text }}</div>
</div>

View File

@@ -321,7 +321,7 @@ services:
ofelia.job-exec.dovecot_clean_q_aged.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/clean_q_aged.sh || exit 0\""
ofelia.job-exec.dovecot_maildir_gc.schedule: "0 */30 * * * *"
ofelia.job-exec.dovecot_maildir_gc.command: "/bin/bash -c \"source /source_env.sh ; /usr/local/bin/gosu vmail /usr/local/bin/maildir_gc.sh\""
ofelia.job-exec.dovecot_sarules.schedule: "0 0 0 * * *"
ofelia.job-exec.dovecot_sarules.schedule: "@every 24h"
ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\""
ofelia.job-exec.dovecot_fts.schedule: "0 0 0 * * *"
ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\""

View File

@@ -91,6 +91,44 @@ if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then
exit 1
fi
# Add image prefetch function
function prefetch_image() {
echo "Checking Docker image: ${DEBIAN_DOCKER_IMAGE}"
# Get local image digest if it exists
local local_digest=$(docker image inspect ${DEBIAN_DOCKER_IMAGE} --format='{{index .RepoDigests 0}}' 2>/dev/null | cut -d'@' -f2)
# Get remote image digest without pulling
local remote_digest=$(docker manifest inspect ${DEBIAN_DOCKER_IMAGE} 2>/dev/null | grep -oP '"digest":\s*"\K[^"]+' | head -1)
if [[ -z "${remote_digest}" ]]; then
echo "Warning: Unable to check remote image"
if [[ -n "${local_digest}" ]]; then
echo "Using cached version"
echo
return 0
else
echo "Error: Image ${DEBIAN_DOCKER_IMAGE} not found locally or remotely"
exit 1
fi
fi
if [[ "${local_digest}" != "${remote_digest}" ]]; then
echo "Image update available, pulling ${DEBIAN_DOCKER_IMAGE}"
if docker pull ${DEBIAN_DOCKER_IMAGE} 2>/dev/null; then
echo "Successfully pulled ${DEBIAN_DOCKER_IMAGE}"
else
echo "Error: Failed to pull ${DEBIAN_DOCKER_IMAGE}"
exit 1
fi
else
echo "Image is up to date (${remote_digest:0:12}...)"
fi
echo
}
# Prefetch the image early in the script
prefetch_image
function backup() {
DATE=$(date +"%Y-%m-%d-%H-%M-%S")