diff --git a/.docker/release/Dockerfile b/.docker/release/Dockerfile index d6675462e..0e6473191 100644 --- a/.docker/release/Dockerfile +++ b/.docker/release/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 -FROM alpine:3.18.5 AS builder -RUN apk add --no-cache php82 php82-json php-phar php-zip +FROM alpine:3.24.3 AS builder +RUN apk add --no-cache php85 php85-json php-phar php-zip RUN apk add --no-cache npm RUN npm install -g gulp yarn WORKDIR /source @@ -23,7 +23,7 @@ RUN set -eux; \ rm -v /snappymail/README.md /snappymail/_include.php # Inspired by the original Rainloop dockerfile from youtous on GitLab -FROM php:8.2-fpm-alpine AS final +FROM php:8.5-fpm-alpine AS final LABEL org.label-schema.description="SnappyMail webmail client image using nginx, php-fpm on Alpine" @@ -99,9 +99,6 @@ RUN set -eux; \ # mysql RUN docker-php-ext-install pdo_mysql -# opcache -RUN docker-php-ext-install opcache - # postgres RUN set -eux; \ apk add --no-cache postgresql-libs; \ @@ -122,6 +119,13 @@ RUN set -eux; \ apk del .build-dependencies; \ apk del .deps +# sqlite +RUN set -eux; \ + apk add --no-cache sqlite-libs; \ + apk add --no-cache --virtual .deps sqlite-dev; \ + docker-php-ext-install pdo_sqlite; \ + apk del .deps + # tidy RUN set -eux; \ apk add --no-cache tidyhtml; \ diff --git a/.docker/release/files/entrypoint.sh b/.docker/release/files/entrypoint.sh index 75e82d729..c0ed7df0c 100755 --- a/.docker/release/files/entrypoint.sh +++ b/.docker/release/files/entrypoint.sh @@ -9,6 +9,12 @@ UPLOAD_MAX_SIZE=${UPLOAD_MAX_SIZE:-25M} MEMORY_LIMIT=${MEMORY_LIMIT:-128M} SECURE_COOKIES=${SECURE_COOKIES:-true} +# Disable listening on ipv6 for ipv4-only environments, or nginx will fail to start +if ! ip a | grep 'inet6 ' > /dev/null; then + echo "[INFO] ipv6 is disabled. Configuring nginx to not listen on ipv6" + sed -i '/listen \[::\]:/d' /etc/nginx/nginx.conf +fi + # Set attachment size limit sed -i "s//$UPLOAD_MAX_SIZE/g" /usr/local/etc/php-fpm.d/php-fpm.conf /etc/nginx/nginx.conf sed -i "s//$MEMORY_LIMIT/g" /usr/local/etc/php-fpm.d/php-fpm.conf diff --git a/SECURITY.md b/SECURITY.md index faaba8d68..11d1ddada 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -36,5 +36,5 @@ YMXQVq4SJt7UpWABAORudfJxsBqCRKtPlZMgGTJLjcOkyFJ9C2Fx7DeN0J4I ## Publishing and Credits I will analyze and fix the reported issue as fast as possible. -Together with the reporter I plan the disclosure of the found and fixed vulnerability. +Together with the reporter, I plan the disclosure of the found and fixed vulnerability. Credits to the reporter are granted and can be included in all public communication if desired. diff --git a/cli/release.php b/cli/release.php index aac915b02..fe406f7f3 100755 --- a/cli/release.php +++ b/cli/release.php @@ -9,7 +9,7 @@ if (isset($options['plugins'])) { require(ROOT_DIR . '/build/plugins.php'); } -$gulp = trim(`which gulp`); +$gulp = trim(shell_exec('which gulp')); if (!$gulp) { exit('gulp not installed, run as root: npm install --global gulp-cli'); } @@ -34,7 +34,7 @@ $options['aur'] = isset($options['aur']); // Docker build $options['docker'] = isset($options['docker']); -if ($options['docker'] && !($docker = trim(`which docker`))) { +if ($options['docker'] && !($docker = trim(shell_exec('which docker')))) { exit('docker not found'); } if ($options['docker'] && $options['aur']) { @@ -60,7 +60,7 @@ if (!isset($options['skip-gulp'])) { $cmddir = escapeshellcmd(ROOT_DIR) . '/snappymail/v/0.0.0/static'; - if ($gzip = trim(`which gzip`)) { + if ($gzip = trim(shell_exec('which gzip'))) { echo "\x1b[33;1m === Gzip *.js and *.css === \x1b[0m\n"; passthru("{$gzip} -k --best {$cmddir}/js/*.js"); passthru("{$gzip} -k --best {$cmddir}/js/min/*.js"); @@ -70,7 +70,7 @@ if (!isset($options['skip-gulp'])) { unlink(ROOT_DIR . '/snappymail/v/0.0.0/static/js/min/boot.min.js.gz'); } - if ($brotli = trim(`which brotli`)) { + if ($brotli = trim(shell_exec('which brotli'))) { echo "\x1b[33;1m === Brotli *.js and *.css === \x1b[0m\n"; passthru("{$brotli} -k --best {$cmddir}/js/*.js"); passthru("{$brotli} -k --best {$cmddir}/js/min/*.js"); @@ -188,7 +188,7 @@ file_put_contents("{$destPath}core.json", '{ // Arch User Repository if ($options['aur']) { // extension_loaded('blake2') - if (!function_exists('b2sum') && $b2sum = trim(`which b2sum`)) { + if (!function_exists('b2sum') && $b2sum = trim(shell_exec('which b2sum'))) { function b2sum($file) { $file = escapeshellarg($file); exec("b2sum --binary {$file} 2>&1", $output, $exitcode); diff --git a/dev/App/User.js b/dev/App/User.js index aafec7da3..5e28164ac 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -1,6 +1,7 @@ import 'External/User/ko'; import { SMAudio } from 'Common/Audio'; +import { arrayLength } from 'Common/Utils'; import { mailToHelper, setLayoutResizer, dropdownsDetectVisibility, loadAccountsAndIdentities } from 'Common/UtilsUser'; import { @@ -240,7 +241,15 @@ export class AppUser extends AbstractApp { showMessageComposer(params = []) { - showScreenPopup(ComposePopupView, params); + let msg = params[1]; + if (1 == arrayLength(msg)) { + msg = msg[0]; + } + if (msg) { + msg.decrypt().then((/*success*/)=>showScreenPopup(ComposePopupView, params)); + } else { + showScreenPopup(ComposePopupView, params); + } } } @@ -251,7 +260,8 @@ AskPopupView.password = function(sAskDesc, btnText, ask) { view => resolve({ password:view.passphrase(), username:/*ask & 2 ? */view.username(), - remember:/*ask & 4 ? */view.remember() + remember:/*ask & 4 ? */view.remember(), + rememberPermanent: view.rememberPermanent(), }), () => resolve(null), true, diff --git a/dev/Common/Html.js b/dev/Common/Html.js index 0be300ec9..072045f9a 100644 --- a/dev/Common/Html.js +++ b/dev/Common/Html.js @@ -232,6 +232,7 @@ export const detectHiddenImages = true, // !!SettingsGet('try_to_detect_hidden_images'), bqLevel = parseInt(SettingsUserStore.maxBlockquotesLevel()), + minFontSize = parseInt(SettingsUserStore.minFontSize()), result = { hasExternals: false, @@ -257,6 +258,15 @@ export const rightmargin: (value, node) => node.style.marginRight = pInt(value) + 'px' }, allowedAttributes = [ + // SnappyMail +// 'data-x-href-broken', +// 'data-x-href-tracking', + 'data-x-src', +// 'data-x-src-hidden', +// 'data-x-src-tracking', +// 'data-x-src-broken', +// 'data-x-style-url', +// 'data-x-style-broken-urls', // defaults 'name', 'dir', 'lang', 'style', 'title', @@ -299,6 +309,8 @@ export const // Not supported by