diff --git a/.docker/release/Dockerfile b/.docker/release/Dockerfile index 0e6473191..97757bb44 100644 --- a/.docker/release/Dockerfile +++ b/.docker/release/Dockerfile @@ -1,192 +1,51 @@ -# syntax=docker/dockerfile:1 - -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 -COPY package.json yarn.lock ./ -RUN yarn install -COPY . . -# Patch release.php with hotfix from: https://github.com/xgbstar1/snappymail-docker/blob/main/Dockerfile, so that release.php doesn't fail with error -RUN sed -i 's_^if.*rename.*snappymail.v.0.0.0.*$_if (!!system("mv snappymail/v/0.0.0 snappymail/v/{$package->version}")) {_' cli/release.php || true -RUN php release.php -RUN set -eux; \ - VERSION=$( ls build/dist/releases/webmail ); \ - ls -al build/dist/releases/webmail/$VERSION/snappymail-$VERSION.tar.gz; \ - mkdir -p /snappymail; \ - tar -zxvf build/dist/releases/webmail/$VERSION/snappymail-$VERSION.tar.gz -C /snappymail; \ - find /snappymail -type d -exec chmod 550 {} \; ; \ - find /snappymail -type f -exec chmod 440 {} \; ; \ - find /snappymail/data -type d -exec chmod 750 {} \; ; \ - # Remove unneeded files - rm -v /snappymail/README.md /snappymail/_include.php - # Inspired by the original Rainloop dockerfile from youtous on GitLab -FROM php:8.5-fpm-alpine AS final +FROM php:8.1-fpm-bullseye -LABEL org.label-schema.description="SnappyMail webmail client image using nginx, php-fpm on Alpine" +ARG FILES_ZIP + + + +LABEL org.label-schema.description="SnappyMail webmail client image using nginx, php-fpm based on Debian Buster" + +ENV UID=991 GID=991 UPLOAD_MAX_SIZE=25M LOG_TO_STDERR=true MEMORY_LIMIT=128M SECURE_COOKIES=true +ENV fpm.pool.clear_env=false # Install dependencies such as nginx -RUN apk add --no-cache ca-certificates nginx supervisor bash +RUN mkdir -p /usr/share/man/man1/ /usr/share/man/man3/ /usr/share/man/man7/ && \ + apt-get update -q --fix-missing && \ + apt-get -y upgrade && \ + apt-get install --no-install-recommends -y \ + apt-transport-https gnupg openssl wget curl ca-certificates nginx supervisor sudo \ + unzip libzip-dev libxml2-dev libldb-dev libldap2-dev \ + sqlite3 libsqlite3-dev libsqlite3-0 libpq-dev postgresql-client mariadb-client logrotate \ + zip mlocate libpcre3-dev libicu-dev \ + build-essential chrpath libssl-dev \ + libxft-dev libfreetype6 libfreetype6-dev \ + libpng-dev libjpeg62-turbo-dev \ + libfontconfig1 libfontconfig1-dev \ + && \ + rm -rf /var/lib/apt/lists/* # Install PHP extensions -# apcu -RUN set -eux; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - pecl install apcu; \ - docker-php-ext-enable apcu; \ - docker-php-source delete; \ - apk del .build-dependencies; - -# gd -RUN set -eux; \ - apk add --no-cache freetype libjpeg-turbo libpng; \ - apk add --no-cache --virtual .deps freetype-dev libjpeg-turbo-dev libpng-dev; \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ - docker-php-ext-install gd; \ - apk del .deps - -# gmagick -# RUN set -eux; \ -# apk add --no-cache graphicsmagick libgomp; \ -# apk add --no-cache --virtual .deps graphicsmagick-dev libtool; \ -# apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ -# pecl install gmagick-2.0.6RC1; \ -# docker-php-ext-enable gmagick; \ -# docker-php-source delete; \ -# apk del .build-dependencies; \ -# apk del .deps - -# gnupg -RUN set -eux; \ - apk add --no-cache gnupg gpgme; \ - apk add --no-cache --virtual .deps gpgme-dev; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - pecl install gnupg; \ - docker-php-ext-enable gnupg; \ - docker-php-source delete; \ - apk del .build-dependencies; \ - apk del .deps - -# imagick -RUN set -eux; \ - apk add --no-cache imagemagick libgomp; \ - apk add --no-cache --virtual .deps imagemagick-dev; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - echo | pecl install imagick; \ - docker-php-ext-enable imagick; \ - docker-php-source delete; \ - apk del .build-dependencies; \ - apk del .deps - -# intl -RUN set -eux; \ - apk add --no-cache icu-libs; \ - apk add --no-cache --virtual .deps icu-dev; \ - docker-php-ext-configure intl; \ - docker-php-ext-install intl; \ - apk del .deps - -# ldap -RUN set -eux; \ - apk add --no-cache libldap; \ - apk add --no-cache --virtual .deps openldap-dev; \ - docker-php-ext-configure ldap; \ - docker-php-ext-install ldap; \ - apk del .deps - -# mysql -RUN docker-php-ext-install pdo_mysql - -# postgres -RUN set -eux; \ - apk add --no-cache postgresql-libs; \ - apk add --no-cache --virtual .deps postgresql-dev; \ - docker-php-ext-install pdo_pgsql; \ - apk del .deps - -# redis -RUN set -eux; \ - apk add --no-cache liblzf zstd-libs; \ - apk add --no-cache --virtual .deps zstd-dev; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - pecl install igbinary; \ - docker-php-ext-enable igbinary; \ - pecl install --configureoptions 'enable-redis-igbinary="yes" enable-redis-lzf="yes" enable-redis-zstd="yes"' redis; \ - docker-php-ext-enable redis; \ - docker-php-source delete; \ - 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; \ - apk add --no-cache --virtual .deps tidyhtml-dev; \ - docker-php-ext-install tidy; \ - apk del .deps - -# uuid -RUN set -eux; \ - apk add --no-cache libuuid; \ - apk add --no-cache --virtual .deps util-linux-dev; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - pecl install uuid; \ - docker-php-ext-enable uuid; \ - docker-php-source delete; \ - apk del .build-dependencies; \ - apk del .deps - -# xxtea - Manually install php8 compatible version from https://github.com/xxtea/xxtea-pecl master branch -RUN set -eux; \ - apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS; \ - wget -q https://github.com/xxtea/xxtea-pecl/tarball/3f5888a29045e12301254151737c5dab4523a1c1 -O xxtea.tar; \ - echo '9cbfd9c27255767deb26ddedf69e738d401d88ac9762d82c8510f9768842ca18 xxtea.tar' | sha256sum -c -; \ - tar -C /usr/src -xvf xxtea.tar; \ - cd /usr/src/xxtea-xxtea-pecl-3f5888a; \ - phpize; \ - ./configure --with-php-config=/usr/local/bin/php-config --enable-xxtea=yes; \ - make install; \ - docker-php-ext-enable xxtea; \ - cd -; \ - rm -fv xxtea.tar; \ - rm -rfv /usr/src/xxtea*; \ - apk del .build-dependencies; - -# zip -RUN set -eux; \ - apk add --no-cache libzip; \ - apk add --no-cache --virtual .deps libzip-dev; \ - docker-php-ext-install zip; \ - apk del .deps +RUN php -m && \ + docker-php-ext-configure ldap --with-libdir=lib/$(uname -m)-linux-gnu/ && \ + docker-php-ext-configure intl && \ + docker-php-ext-configure gd --with-freetype --with-jpeg && \ + docker-php-ext-install ldap opcache pdo_mysql pdo_pgsql zip intl gd && \ + php -m # Install snappymail -# The 'www-data' user/group in alpine is 82:82. The 'nginx' user/group in alpine is 101:101, and is part of www-data group -COPY --chown=www-data:www-data --from=builder /snappymail /snappymail -# Use a custom snappymail data folder -RUN mv -v /snappymail/data /var/lib/snappymail; -# Setup configs -COPY --chown=root:root .docker/release/files / -RUN set -eux; \ - chown www-data:www-data /snappymail/include.php; \ - chmod 440 /snappymail/include.php; \ - chmod +x /entrypoint.sh; \ - # Disable the built-in php-fpm configs, since we're using our own config - mv -v /usr/local/etc/php-fpm.d/docker.conf /usr/local/etc/php-fpm.d/docker.conf.disabled; \ - mv -v /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.disabled; \ - mv -v /usr/local/etc/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf.disabled; +WORKDIR /tmp +COPY ${FILES_ZIP} . +RUN mkdir /snappymail && \ + unzip -q ${FILES_ZIP} -d /snappymail && \ + find /snappymail -type d -exec chmod 755 {} \; && \ + find /snappymail -type f -exec chmod 644 {} \; && \ + rm -rf ${FILES_ZIP} -USER root -WORKDIR /snappymail -VOLUME /var/lib/snappymail +# Install other content +COPY files / +RUN chmod +x /entrypoint.sh && chmod +x /logrotate-loop.sh +VOLUME /snappymail/data EXPOSE 8888 -EXPOSE 9000 -ENTRYPOINT [] CMD ["/entrypoint.sh"] diff --git a/.docker/release/files/entrypoint.sh b/.docker/release/files/entrypoint.sh old mode 100755 new mode 100644 index c0ed7df0c..eed82bf5b --- a/.docker/release/files/entrypoint.sh +++ b/.docker/release/files/entrypoint.sh @@ -1,26 +1,23 @@ #!/bin/sh -set -eu -DEBUG=${DEBUG:-} -if [ "$DEBUG" = 'true' ]; then - set -x -fi -UPLOAD_MAX_SIZE=${UPLOAD_MAX_SIZE:-25M} -MEMORY_LIMIT=${MEMORY_LIMIT:-128M} -SECURE_COOKIES=${SECURE_COOKIES:-true} +# Create not root user +groupadd --gid "$GID" php-cli -f +adduser --uid "$UID" --disabled-password --gid "$GID" --shell /bin/bash --home /home/php-cli php-cli --force --gecos "" -# 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 +# Set log output to STDERR if wanted (LOG_TO_STDERR=true) +if [ "$LOG_TO_STDERR" = true ]; then + echo "[INFO] Logging to stderr activated" + sed -i "s/.*error_log.*$/error_log \/dev\/stderr warn;/" /etc/nginx/nginx.conf + sed -i "s/.*error_log.*$/php_admin_value[error_log] = \/dev\/stderr/" /usr/local/etc/php-fpm.d/php-fpm.conf +fi + # Secure cookies -if [ "${SECURE_COOKIES}" = 'true' ]; then +if [ "${SECURE_COOKIES}" = true ]; then echo "[INFO] Secure cookies activated" { echo 'session.cookie_httponly = On'; @@ -29,58 +26,43 @@ if [ "${SECURE_COOKIES}" = 'true' ]; then } > /usr/local/etc/php/conf.d/cookies.ini; fi -echo "[INFO] Snappymail version: $( ls /snappymail/snappymail/v )" - -# Set permissions on snappymail data -echo "[INFO] Setting permissions on /var/lib/snappymail" -chown -R www-data:www-data /var/lib/snappymail/ -chmod 550 /var/lib/snappymail/ -find /var/lib/snappymail/ -type d -exec chmod 750 {} \; - -# Create snappymail default config if absent -SNAPPYMAIL_CONFIG_FILE=/var/lib/snappymail/_data_/_default_/configs/application.ini +# Copy snappymail default config if absent +SNAPPYMAIL_CONFIG_FILE=/snappymail/data/_data_/_default_/configs/application.ini if [ ! -f "$SNAPPYMAIL_CONFIG_FILE" ]; then - echo "[INFO] Creating default Snappymail configuration: $SNAPPYMAIL_CONFIG_FILE" - # Run snappymail and exit. This populates the snappymail data directory and generates the config file - # On error, print php exception and exit - EXITCODE= - su - www-data -s /bin/sh -c 'php /snappymail/index.php' > /tmp/out || EXITCODE=$? - if [ -n "$EXITCODE" ]; then - cat /tmp/out - exit "$EXITCODE" - fi + echo "[INFO] Creating default Snappymail configuration" + mkdir -p $(dirname $SNAPPYMAIL_CONFIG_FILE) + cp /usr/local/include/application.ini $SNAPPYMAIL_CONFIG_FILE fi -echo "[INFO] Overriding values in snappymail configuration: $SNAPPYMAIL_CONFIG_FILE" # Enable output of snappymail logs -sed '/^\; Enable logging/{ -N -s/enable = Off/enable = On/ -}' -i $SNAPPYMAIL_CONFIG_FILE -# Redirect snappymail logs to stderr /stdout -sed 's/^filename = .*/filename = "stderr"/' -i $SNAPPYMAIL_CONFIG_FILE -sed 's/^write_on_error_only = .*/write_on_error_only = Off/' -i $SNAPPYMAIL_CONFIG_FILE -sed 's/^write_on_php_error_only = .*/write_on_php_error_only = On/' -i $SNAPPYMAIL_CONFIG_FILE +if [ "${LOG_TO_STDERR}" = true ]; then + sed -z 's/\; Enable logging\nenable = Off/\; Enable logging\nenable = On/' -i $SNAPPYMAIL_CONFIG_FILE + sed 's/^filename = .*/filename = "errors.log"/' -i $SNAPPYMAIL_CONFIG_FILE + sed 's/^write_on_error_only = .*/write_on_error_only = Off/' -i $SNAPPYMAIL_CONFIG_FILE + sed 's/^write_on_php_error_only = .*/write_on_php_error_only = On/' -i $SNAPPYMAIL_CONFIG_FILE +else + sed -z 's/\; Enable logging\nenable = On/\; Enable logging\nenable = Off/' -i $SNAPPYMAIL_CONFIG_FILE +fi # Always enable snappymail Auth logging sed 's/^auth_logging = .*/auth_logging = On/' -i $SNAPPYMAIL_CONFIG_FILE sed 's/^auth_logging_filename = .*/auth_logging_filename = "auth.log"/' -i $SNAPPYMAIL_CONFIG_FILE sed 's/^auth_logging_format = .*/auth_logging_format = "[{date:Y-m-d H:i:s}] Auth failed: ip={request:ip} user={imap:login} host={imap:host} port={imap:port}"/' -i $SNAPPYMAIL_CONFIG_FILE -sed 's/^auth_syslog = .*/auth_syslog = Off/' -i $SNAPPYMAIL_CONFIG_FILE +# Redirect snappymail logs to stderr /stdout +mkdir -p /snappymail/data/_data_/_default_/logs/ +# empty logs +cp /dev/null /snappymail/data/_data_/_default_/logs/errors.log +cp /dev/null /snappymail/data/_data_/_default_/logs/auth.log +chown -R php-cli:php-cli /snappymail/data/ -( - while ! nc -vz -w 1 127.0.0.1 8888 > /dev/null 2>&1; do echo "[INFO] Checking whether nginx is alive"; sleep 1; done - while ! nc -vz -w 1 127.0.0.1 9000 > /dev/null 2>&1; do echo "[INFO] Checking whether php-fpm is alive"; sleep 1; done - # Create snappymail admin password if absent - SNAPPYMAIL_ADMIN_PASSWORD_FILE=/var/lib/snappymail/_data_/_default_/admin_password.txt - if [ ! -f "$SNAPPYMAIL_ADMIN_PASSWORD_FILE" ]; then - echo "[INFO] Creating Snappymail admin password file: $SNAPPYMAIL_ADMIN_PASSWORD_FILE" - wget -T 1 -qO- 'http://127.0.0.1:8888/?/AdminAppData/0/12345/' > /dev/null - echo "[INFO] Snappymail Admin Panel ready at http://localhost:8888/?admin. Login using password in $SNAPPYMAIL_ADMIN_PASSWORD_FILE" - fi +# Fix permissions +chown -R $UID:$GID /snappymail/data /var/log /var/lib/nginx +chmod o+w /dev/stdout +chmod o+w /dev/stderr - wget -T 1 -qO- 'http://127.0.0.1:8888/' > /dev/null - echo "[INFO] Snappymail ready at http://localhost:8888/" -) & + +# Touch supervisord PID file in order to fix permissions +touch /run/supervisord.pid +chown php-cli:php-cli /run/supervisord.pid # RUN ! -exec /usr/bin/supervisord -c /supervisor.conf --pidfile /run/supervisord.pid +exec sudo -u php-cli -g php-cli /usr/bin/supervisord -c '/supervisor.conf' --pidfile '/run/supervisord.pid' diff --git a/.docker/release/files/etc/logrotate.d/snappymail b/.docker/release/files/etc/logrotate.d/snappymail new file mode 100644 index 000000000..701631d98 --- /dev/null +++ b/.docker/release/files/etc/logrotate.d/snappymail @@ -0,0 +1,5 @@ +/snappymail/data/_data_/_default_/logs/* { + size 10M + rotate 0 + missingok +} \ No newline at end of file diff --git a/.docker/release/files/etc/nginx/nginx.conf b/.docker/release/files/etc/nginx/nginx.conf index aff3829cf..1bb643f23 100644 --- a/.docker/release/files/etc/nginx/nginx.conf +++ b/.docker/release/files/etc/nginx/nginx.conf @@ -11,7 +11,7 @@ http { default_type application/octet-stream; access_log off; - error_log /dev/stderr error; + error_log /tmp/ngx_error.log error; sendfile on; keepalive_timeout 15; @@ -52,8 +52,6 @@ http { server { listen 8888; - listen [::]:8888; - #listen [::]:8888 ipv6only=off; root /snappymail; index index.php; charset utf-8; @@ -97,7 +95,7 @@ http { fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param HTTP_PROXY ""; fastcgi_index index.php; - fastcgi_pass 127.0.0.1:9000; + fastcgi_pass unix:/tmp/php-fpm.sock; fastcgi_intercept_errors on; fastcgi_request_buffering off; fastcgi_param REMOTE_ADDR $http_x_real_ip; diff --git a/.docker/release/files/logrotate-loop.sh b/.docker/release/files/logrotate-loop.sh new file mode 100644 index 000000000..ba1d42469 --- /dev/null +++ b/.docker/release/files/logrotate-loop.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# ---------------------------------------------------------------------- +# Simple script to invoke logrotate at regular intervals +# ---------------------------------------------------------------------- + +# from https://github.com/misho-kr/docker-appliances/blob/master/nginx-nodejs/logrotate-loop.sh + +LOGROTATE_BIN="logrotate" + +STATE="$HOME/logrotate.state" +CONF="/etc/logrotate.d/snappymail" + +export LOGROTATE_BIN STATE CONF + +RUN_INTERVAL="3600" # every hour + +# helper functions for logging +export FMT="%a %b %d %Y %H:%M:%S GMT%z (%Z)" + +function log_date() { + echo "$(date +"$FMT"): $*" +} + +# ---------------------------------------------------------------------- +# Main loop of the logrotate service: +# +# while True: +# sleep N seconds +# run logrotate +# +# ---------------------------------------------------------------------- + +function logrotate_loop() { + + trap on_terminate TERM INT + + local interval="${1}" + + log_date "====================================================" + log_date + log_date "logrotate service starting (pid=$$)" + log_date "logrotate process will run every ${interval} seconds" + + while true; do + + current_time=$(date "+%s") + next_run_time=$(( current_time + interval )) + + while (( current_time < next_run_time )) + do + logrotate_sleep $(( next_run_time - current_time )) + current_time=$(date "+%s") + done + + logrotate_run + done +} + +# helper function to execute logrotate and pass it the right parameters +function logrotate_run() { + + log_date "logrotate will run now" + ${LOGROTATE_BIN} -s ${STATE} ${CONF} +} + +# ---------------------------------------------------------------------- +# Procedure to idle the execution for a number of seconds +# +# There are two requirements: +# +# - export the PID of the sleep command so that it can be terminated +# in case the logrotate service is being shutdown +# - keep this (bash) process responsive to SIGTERM while in sleep +# mode (normally the signal will be masked and will not be delivered +# until the subprocess completes) +# ---------------------------------------------------------------------- + +proc_sleep_pid="" + +function logrotate_sleep() { + + local sleep_interval=${1} + + log_date "logrotate will sleep for ${sleep_interval} seconds" + + ( exec -a "logrotate: sleep" sleep ${sleep_interval} )& + + proc_sleep_pid=$! + wait ${proc_sleep_pid} +} + +# ---------------------------------------------------------------------- +# Signal handler for logrotate service to make sure the process exits: +# +# - properly by terminating the sleep process that is used to idle +# the service +# - gracefully by writing a message in the log +# ---------------------------------------------------------------------- + +function on_terminate() { + + log_date "logrotate will terminate" + log_date + + kill -TERM ${proc_sleep_pid} + exit 0 +} + +# ---------------------------------------------------------------------- +# main +# ---------------------------------------------------------------------- + +logrotate_loop ${1:-RUN_INTERVAL} diff --git a/.docker/release/files/snappymail/include.php b/.docker/release/files/snappymail/include.php deleted file mode 100644 index 53ba30722..000000000 --- a/.docker/release/files/snappymail/include.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/.docker/release/files/supervisor.conf b/.docker/release/files/supervisor.conf index 13a12a290..da6c6aefe 100644 --- a/.docker/release/files/supervisor.conf +++ b/.docker/release/files/supervisor.conf @@ -1,13 +1,10 @@ [supervisord] nodaemon=true -user=root -logfile=/dev/null -logfile_maxbytes=0 [program:nginx] command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;' process_name=%(program_name)s_%(process_num)02d -user=root +user=php-cli numprocs=1 autostart=true autorestart=false @@ -20,7 +17,7 @@ stderr_logfile_maxbytes=0 [program:php-fpm] command=php-fpm -F process_name=%(program_name)s_%(process_num)02d -user=root +user=php-cli numprocs=1 autostart=true autorestart=false @@ -30,11 +27,34 @@ stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 +; reads snappymail logs +[program:snappymail-auth] +command=tail -f /snappymail/data/_data_/_default_/logs/auth.log +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:snappymail-errors] +command=tail -f /snappymail/data/_data_/_default_/logs/errors.log +# everything is an error +stdout_logfile=/dev/stderr +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:logrotate] +command=/logrotate-loop.sh +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + [eventlistener:subprocess-stopped] command=php /listener.php process_name=%(program_name)s_%(process_num)02d -user=root +user=php-cli numprocs=1 events=PROCESS_STATE_EXITED,PROCESS_STATE_STOPPED,PROCESS_STATE_FATAL autostart=true -autorestart=unexpected +autorestart=unexpected \ No newline at end of file diff --git a/.docker/release/files/usr/local/etc/php-fpm.d/php-fpm.conf b/.docker/release/files/usr/local/etc/php-fpm.d/php-fpm.conf index fbee3d4e0..456fdb798 100644 --- a/.docker/release/files/usr/local/etc/php-fpm.d/php-fpm.conf +++ b/.docker/release/files/usr/local/etc/php-fpm.d/php-fpm.conf @@ -1,21 +1,15 @@ [global] daemonize = no -error_log = /dev/stderr -log_buffering = no [default] -listen = 9000 -user = www-data -listen.owner = www-data -listen.group = www-data +listen = /tmp/php-fpm.sock pm = ondemand pm.max_children = 30 pm.process_idle_timeout = 10s pm.max_requests = 500 catch_workers_output = yes -decorate_workers_output = no chdir = / -pm.status_path = /status +php_admin_value[error_log] = /tmp/php_error.log php_admin_value[log_errors] = On php_admin_value[expose_php] = Off php_admin_value[display_errors] = Off diff --git a/.docker/release/files/usr/local/include/application.ini b/.docker/release/files/usr/local/include/application.ini new file mode 100644 index 000000000..0345c10cb --- /dev/null +++ b/.docker/release/files/usr/local/include/application.ini @@ -0,0 +1,308 @@ +; SnappyMail configuration file +; Please don't add custom parameters here, those will be overwritten + +[webmail] +; Text displayed as page title +title = "SnappyMail Webmail" + +; Text displayed on startup +loading_description = "SnappyMail" +favicon_url = "" + +; Theme used by default +theme = "Default" + +; Allow theme selection on settings screen +allow_themes = On +allow_user_background = Off + +; Language used by default +language = "en" + +; Admin Panel interface language +language_admin = "en" + +; Allow language selection on settings screen +allow_languages_on_settings = On +allow_additional_accounts = On +allow_additional_identities = On + +; Number of messages displayed on page by default +messages_per_page = 20 + +; Mark message read after N seconds +message_read_delay = 5 + +; File size limit (MB) for file upload on compose screen +; 0 for unlimited. +attachment_size_limit = 2 + +[interface] +show_attachment_thumbnail = On +new_move_to_folder_button = On + +[contacts] +; Enable contacts +enable = Off +allow_sync = Off +sync_interval = 20 +type = "sqlite" +pdo_dsn = "host=127.0.0.1;port=3306;dbname=snappymail" +pdo_user = "root" +pdo_password = "" +suggestions_limit = 30 + +[security] +; Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery) +csrf_protection = On +custom_server_signature = "SnappyMail" +x_frame_options_header = "DENY" +x_xss_protection_header = "1; mode=block" +openpgp = Off + +; Login and password for web admin panel +admin_login = "admin" +admin_password = "" +admin_totp = "" + +; Access settings +allow_admin_panel = On +hide_x_mailer_header = On +admin_panel_host = "" +admin_panel_key = "admin" +content_security_policy = "" +csp_report = Off +encrypt_cipher = "aes-256-cbc-hmac-sha1" + +[admin_panel] +allow_update = Off + +[ssl] +; Require verification of SSL certificate used. +verify_certificate = Off + +; Allow self-signed certificates. Requires verify_certificate. +allow_self_signed = On + +; https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html +security_level = 1 + +; Location of Certificate Authority file on local filesystem (/etc/ssl/certs/ca-certificates.crt) +cafile = "" + +; capath must be a correctly hashed certificate directory. (/etc/ssl/certs/) +capath = "" + +; Location of client certificate file (pem format with private key) on local filesystem +client_cert = "" + +[capa] +quota = On +search = On +search_adv = On +dangerous_actions = On +message_actions = On +attachments_actions = On + +[login] +default_domain = "" + +; Allow language selection on webmail login screen +allow_languages_on_login = On +determine_user_language = On +determine_user_domain = Off +hide_submit_button = On +login_lowercase = On + +; This option allows webmail to remember the logged in user +; once they closed the browser window. +; +; Values: +; "DefaultOff" - can be used, disabled by default; +; "DefaultOn" - can be used, enabled by default; +; "Unused" - cannot be used +sign_me_auto = "DefaultOff" + +[plugins] +; Enable plugin support +enable = Off + +; List of enabled plugins +enabled_list = "" + +[defaults] +; Editor mode used by default (Plain, Html) +view_editor_type = "Html" + +; layout: 0 - no preview, 1 - side preview, 2 - bottom preview +view_layout = 1 +view_use_checkboxes = On +autologout = 30 +view_html = On +show_images = Off +contacts_autosave = On +mail_use_threads = Off +allow_draft_autosave = On +mail_reply_same_folder = Off + +[logs] +; Enable logging +enable = Off + +; Log messages of set RFC 5424 section 6.2.1 Severity level and higher (0 = highest, 7 = lowest). +; 0 = Emergency +; 1 = Alert +; 2 = Critical +; 3 = Error +; 4 = Warning +; 5 = Notice +; 6 = Informational +; 7 = Debug +level = 4 + +; Logs entire request only if error occured (php requred) +write_on_error_only = Off + +; Logs entire request only if php error occured +write_on_php_error_only = Off + +; Logs entire request only if request timeout (in seconds) occured. +write_on_timeout_only = 0 + +; Required for development purposes only. +; Disabling this option is not recommended. +hide_passwords = On +time_zone = "UTC" +session_filter = "" + +; Log filename. +; For security reasons, some characters are removed from filename. +; Allows for pattern-based folder creation (see examples below). +; +; Patterns: +; {date:Y-m-d} - Replaced by pattern-based date +; Detailed info: http://www.php.net/manual/en/function.date.php +; {user:email} - Replaced by user's email address +; If user is not logged in, value is set to "unknown" +; {user:login} - Replaced by user's login (the user part of an email) +; If user is not logged in, value is set to "unknown" +; {user:domain} - Replaced by user's domain name (the domain part of an email) +; If user is not logged in, value is set to "unknown" +; {user:uid} - Replaced by user's UID regardless of account currently used +; +; {user:ip} +; {request:ip} - Replaced by user's IP address +; +; Others: +; {imap:login} {imap:host} {imap:port} +; {smtp:login} {smtp:host} {smtp:port} +; +; Examples: +; filename = "log-{date:Y-m-d}.txt" +; filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log" +; filename = "{user:email}-{date:Y-m-d}.txt" +; filename = "syslog" +filename = "log-{date:Y-m-d}.txt" + +; Enable auth logging in a separate file (for fail2ban) +auth_logging = Off +auth_logging_filename = "fail2ban/auth-{date:Y-m-d}.txt" +auth_logging_format = "[{date:Y-m-d H:i:s}] Auth failed: ip={request:ip} user={imap:login} host={imap:host} port={imap:port}" + +; Enable auth logging to syslog for fail2ban +auth_syslog = On + +[debug] +; Special option required for development purposes +enable = Off + +[cache] +; The section controls caching of the entire application. +; +; Enables caching in the system +enable = On + +; Additional caching key. If changed, cache is purged +index = "v1" + +; Can be: files, APCU, memcache, redis (beta) +fast_cache_driver = "files" + +; Additional caching key. If changed, fast cache is purged +fast_cache_index = "v1" + +; Browser-level cache. If enabled, caching is maintainted without using files +http = On + +; Browser-level cache time (seconds, Expires header) +http_expires = 3600 + +; Caching message UIDs when searching and sorting (threading) +server_uids = On + +[labs] +cache_system_data = On +date_from_headers = On +autocreate_system_folders = Off +allow_message_append = Off +login_fault_delay = 1 +log_ajax_response_write_limit = 300 +allow_html_editor_biti_buttons = Off +allow_ctrl_enter_on_compose = On +try_to_detect_hidden_images = Off +use_app_debug_js = Off +use_mobile_version_for_tablets = Off +use_app_debug_css = Off +use_imap_sort = On +use_imap_force_selection = Off +use_imap_thread = On +use_imap_move = Off +use_imap_expunge_all_on_delete = Off +imap_body_text_limit = 555000 +imap_message_list_fast_simple_search = On +imap_message_list_count_limit_trigger = 0 +imap_message_list_date_filter = 0 +imap_message_list_permanent_filter = "" +imap_message_all_headers = Off +imap_large_thread_limit = 50 +imap_folder_list_limit = 200 +imap_show_login_alert = On +imap_use_list_status = On +imap_timeout = 300 +imap_disable_metadata = Off +smtp_show_server_errors = Off +smtp_timeout = 60 +sieve_auth_plain_initial = On +sieve_allow_fileinto_inbox = Off +sieve_timeout = 10 +sasl_allow_plain = On +sasl_allow_scram_sha = Off +sasl_allow_cram_md5 = Off +mail_func_clear_headers = On +mail_func_additional_parameters = Off +folders_spec_limit = 50 +curl_proxy = "" +curl_proxy_auth = "" +in_iframe = Off +force_https = Off +custom_login_link = "" +custom_logout_link = "" +allow_external_login = Off +http_client_ip_check_proxy = Off +fast_cache_memcache_host = "127.0.0.1" +fast_cache_memcache_port = 11211 +fast_cache_redis_host = "127.0.0.1" +fast_cache_redis_port = 6379 +use_local_proxy_for_external_images = On +image_exif_auto_rotate = Off +cookie_default_path = "" +cookie_default_secure = Off +check_new_messages = On +replace_env_in_configuration = "" +boundary_prefix = "" +dev_email = "" +dev_password = "" + +[version] +current = "2.18.2" +saved = "Fri, 04 Mar 2022 08:55:26 +0000" diff --git a/.docker/release/test/build_and_test.sh b/.docker/release/test/build_and_test.sh deleted file mode 100755 index f332ad2c2..000000000 --- a/.docker/release/test/build_and_test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -# This script uses docker buildx to build a docker image, and loads it into the docker daemon. Then it executes ./test.sh to test the docker image -# It is useful for testing release builds in development -set -eu -IMAGE=snappymail/snappymail:test -DOCKER_BUILDX=1 docker build -t "$IMAGE" -f .docker/release/Dockerfile . -.docker/release/test/test.sh "$IMAGE" diff --git a/.docker/release/test/config.yaml b/.docker/release/test/config.yaml deleted file mode 100644 index 47cf00ea9..000000000 --- a/.docker/release/test/config.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# See: https://github.com/GoogleContainerTools/container-structure-test -# See: https://github.com/GoogleContainerTools/container-structure-test/issues/78 -schemaVersion: 2.0.0 -commandTests: - - name: Integration test - command: /bin/sh - args: - - -c - - | - set -eux - DEBUG=true /entrypoint.sh > /tmp/test 2>&1 & - sleep 5 - cat /tmp/test - pidof supervisord - pidof nginx - pidof php-fpm - ls -al /var/lib/snappymail/_data_/_default_/configs/application.ini - ls -al /var/lib/snappymail/_data_/_default_/admin_password.txt - nc -vz 127.0.0.1 8888 - nc -vz 127.0.0.1 9000 - wget -S -T 3 -O /dev/null http://127.0.0.1:8888 - kill `pidof supervisord` -metadataTest: - exposedPorts: ["8888", "9000"] - volumes: ["/var/lib/snappymail"] - entrypoint: [] - cmd: ["/entrypoint.sh"] - workdir: /snappymail - user: root diff --git a/.docker/release/test/test.sh b/.docker/release/test/test.sh deleted file mode 100755 index 1981cb358..000000000 --- a/.docker/release/test/test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# This script tests a given docker image using https://github.com/GoogleContainerTools/container-structure-test -set -eu -SCRIPT_DIR=$( cd "$(dirname "$0")" && pwd ) -IMAGE=${1:-} -echo "Testing image: $IMAGE" -docker run --rm -i \ - -v /var/run/docker.sock:/var/run/docker.sock:ro \ - -v "$SCRIPT_DIR/config.yaml:/config.yaml:ro" \ - gcr.io/gcp-runtimes/container-structure-test:latest test --image "$IMAGE" --config config.yaml diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 16ef81459..000000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -/.git -/node_modules diff --git a/.eslintrc.js b/.eslintrc.js index e22cb986d..80846798b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { // extends: ['eslint:recommended', 'plugin:prettier/recommended'], extends: ['eslint:recommended'], parserOptions: { - ecmaVersion: 11, + ecmaVersion: 6, sourceType: 'module' }, env: { @@ -27,6 +27,8 @@ module.exports = { 'SquireUI': "readonly", // node_modules/knockout but dev/External/ko.js is used 'ko': "readonly", + // dev/External/ifvisible.js + 'ifvisible': "readonly", // vendors/routes/ 'hasher': "readonly", 'Crossroads': "readonly", @@ -35,17 +37,10 @@ module.exports = { // vendors/bootstrap/bootstrap.native.js 'BSN': "readonly", // Mailvelope - 'mailvelope': "readonly", - // Punycode - 'IDN': "readonly", - // Turndown - 'TurndownService': "readonly", - // Marked - 'marked': "readonly" + 'mailvelope': "readonly" }, // http://eslint.org/docs/rules/ rules: { - 'no-cond-assign': 0, // plugins 'no-mixed-spaces-and-tabs': 'off', 'max-len': [ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index b37d3418e..fc1bece3e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ -github: the-djmaze +community_bridge: SnappyMail custom: ["https://www.paypal.me/thedjmaze", "https://snappymail.eu"] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 998692964..2f48abb98 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -28,11 +28,9 @@ If applicable, add screenshots to help explain your problem. - IMAP daemon: [e.g. courier, dovecot] - PHP version: - SnappyMail Version: -- Mode: [e.g. standalone, nextcloud, cyberpanel, docker] -**Debug/logging information** -[Read here how to log](https://github.com/the-djmaze/snappymail/wiki/FAQ#how-do-i-enable-logging) -- [ ] I've placed them here (few lines) or as attachments (many lines) +**[Debug/logging information](https://github.com/the-djmaze/snappymail/wiki/FAQ#how-do-i-enable-logging)** +Place them here (few lines) or as attachments (many lines) **Additional context** Add any other context about the problem here. diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml deleted file mode 100644 index af069cdf6..000000000 --- a/.github/workflows/docker-pr.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: docker-pr - -on: - pull_request: - branches: - - master - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - # This step generates the docker tags - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - env: - # This env var ensures {{sha}} is a real commit SHA for type=ref,event=pr - DOCKER_METADATA_PR_HEAD_SHA: 'true' - with: - images: | - djmaze/snappymail - ghcr.io/${{ github.repository }} - # type=ref,event=pr generates tag(s) on PRs only. E.g. 'pr-123', 'pr-123-abc0123' - tags: | - type=ref,event=pr - type=ref,suffix=-{{sha}},event=pr - # The rest of the org.opencontainers.image.xxx labels are dynamically generated - labels: | - org.opencontainers.image.description=SnappyMail - org.opencontainers.image.licenses=AGPLv3 - - # See: https://github.com/docker/build-push-action/blob/v2.6.1/docs/advanced/cache.md#github-cache - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Cache Docker layers - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - # See: https://github.com/docker/buildx/issues/59 - - name: Build - id: build - uses: docker/build-push-action@v3 - with: - context: '.' - file: ./.docker/release/Dockerfile - platforms: linux/amd64 - push: false - load: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - - - name: Docker images - run: | - docker images - - - name: Test - run: | - TAG=$( echo "${{ steps.meta.outputs.tags }}" | head -n1 ) - .docker/release/test/test.sh "$TAG" - - - name: Build all archs - uses: docker/build-push-action@v3 - with: - context: '.' - file: ./.docker/release/Dockerfile - platforms: linux/386,linux/amd64,linux/arm64 - push: false - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index b957e2fc8..000000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: docker - -on: - push: - tags: - - 'v2.*' - -# This is needed to push to GitHub Container Registry. See https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry -permissions: - contents: read - packages: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - # This step generates the docker tags - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - env: - # This env var ensures {{sha}} is a real commit SHA for type=ref,event=pr - DOCKER_METADATA_PR_HEAD_SHA: 'true' - with: - images: | - djmaze/snappymail - ghcr.io/${{ github.repository }} - # type=ref,event=branch generates tag(s) on branch only. E.g. 'master', 'master-abc0123' - # type=ref,event=tag generates tag(s) on tags only. E.g. 'v0.0.0', 'v0.0.0-abc0123', and 'latest' - tags: | - type=ref,event=branch - type=ref,event=tag - # The rest of the org.opencontainers.image.xxx labels are dynamically generated - labels: | - org.opencontainers.image.description=SnappyMail - org.opencontainers.image.licenses=AGPLv3 - - # See: https://github.com/docker/build-push-action/blob/v2.6.1/docs/advanced/cache.md#github-cache - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Cache Docker layers - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Login to Docker Hub registry - if: startsWith(github.ref, 'refs/tags/') # Login only on tags - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Login to GitHub Container Registry - if: startsWith(github.ref, 'refs/tags/') # Login only on tags - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # See: https://github.com/docker/buildx/issues/59 - - name: Build - id: build - uses: docker/build-push-action@v3 - with: - context: '.' - file: ./.docker/release/Dockerfile - platforms: linux/amd64 - push: false - load: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - - - name: Docker images - run: | - docker images - - - name: Test - run: | - TAG=$( echo "${{ steps.meta.outputs.tags }}" | head -n1 ) - .docker/release/test/test.sh "$TAG" - - - name: Build and push - id: build-and-push - uses: docker/build-push-action@v3 - with: - context: '.' - file: ./.docker/release/Dockerfile - # TODO: Add more arches? - # platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/s390x - platforms: linux/386,linux/amd64,linux/arm64 - push: ${{ startsWith(github.ref, 'refs/tags/') }} # Push only on tags - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.gitignore b/.gitignore index 5f49d65d5..46428042c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ /data /MULTIPLY /include.php -/issues .idea/ .env /test @@ -25,8 +24,6 @@ /vendors/knockout/spec /vendors/openpgp-5 !/vendors/openpgp-5/dist -/vendors/squire2 -!/vendors/squire2/dist /vendors/vanillaqr.js/ /integrations/nextcloud/rainloop /integrations/owncloud/rainloop diff --git a/.gitmodules b/.gitmodules index ccf1009a6..cfb771834 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ [submodule "vendors/openpgp-5"] path = vendors/openpgp-5 url = git@github.com:the-djmaze/openpgpjs.git -[submodule "vendors/squire2"] - path = vendors/squire2 - url = git@github.com:the-djmaze/Squire.git - branch = snappymail diff --git a/.htaccess b/.htaccess index 71041371a..449dcc730 100644 --- a/.htaccess +++ b/.htaccess @@ -1,15 +1,7 @@ - - AcceptPathInfo On - - RewriteEngine On # Redirect cPanel RewriteRule cpsess.* https://%{HTTP_HOST}/ [L,R=301] - - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule ^(.+)$ index.php/$1 [L,QSA] @@ -34,6 +26,7 @@ # Header set Strict-Transport-Security "max-age=31536000" Header set imagetoolbar "no" # Header set X-Content-Type-Options "nosniff" +# Header set X-Frame-Options "DENY" # Header set X-XSS-Protection "1; mode=block" Header set Service-Worker-Allowed "/" diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d31a1b771..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,2422 +0,0 @@ -## 2.38.2 – 2024-10-09 -### Fixed -- error '$index is not defined' in Settings > Accounts - [#1797](https://github.com/the-djmaze/snappymail/issues/1797) - - -## 2.38.1 – 2024-10-08 - -### Added -- Admin - Extensions search filter -- Options to unset current font family and size - [#1726](https://github.com/the-djmaze/snappymail/issues/1726) -- Option to allow insecure cryptkey - [#1746](https://github.com/the-djmaze/snappymail/issues/1746) -- Save vCard FN property - [#1761](https://github.com/the-djmaze/snappymail/issues/1761) -- Docker Nginx should listen on IPv6 addresses in addition to IPv4 - [#1770](https://github.com/the-djmaze/snappymail/issues/1770) -- Full-screen Message View on Double-Click - [#1787](https://github.com/the-djmaze/snappymail/issues/1787) - -### Changed -- Use the custom Squire as submodule vendors/squire2 -- Disallow noembed and noframes HTML elements -- Keep 1 space between HTML elements in compressed templates -- Squire: sanitizeToDOMFragment now uses cleanHTML() -- Squire: improved handling of BR elements - [#1389](https://github.com/the-djmaze/snappymail/issues/1389) -- Nextcloud border-radius by @gnilebein - [#1790](https://github.com/the-djmaze/snappymail/pull/1790) -- Compose window sentFolder handling for - [#1793](https://github.com/the-djmaze/snappymail/pull/1793) -- Update Portuguese by @ner00 -- Update Polish by @tinola -- Update French by @hguilbert -- Update Portuguese (Brazil) by @mstolf - -### Fixed -- Composer dialog scroll got broken in v2.28 -- Composer dialog "from" triangle button wrong position due to font changes -- Admin - Config `search` should be ko.observable() not ko.observableArray() -- Squire: paste images - [#1389](https://github.com/the-djmaze/snappymail/issues/1389) -- Domain whitelist failures on login - [#1706](https://github.com/the-djmaze/snappymail/issues/1706) -- Sieve parse errors -- Sieve support `index` was not optional for - [#1709](https://github.com/the-djmaze/snappymail/issues/1709) -- Pagination problem for large mailbox after 2.36.1 - [#1716](https://github.com/the-djmaze/snappymail/issues/1716) -- Undefined constant "LOG_ERROR" - [#1754](https://github.com/the-djmaze/snappymail/issues/1754) -- Search Filter Capital "B" not working - [#1780](https://github.com/the-djmaze/snappymail/issues/1780) -- PHP 8.4: Implicitly nullable parameter declarations deprecated - - -## 2.38.0 – 2024-09-16 - -### Added -- Remove `tel:` links when converting HTML to plain - [#1724](https://github.com/the-djmaze/snappymail/issues/1724) -- Convert HTML to Markdown instead of plain, by using [Turndown](https://github.com/mixmark-io/turndown) - [#1604](https://github.com/the-djmaze/snappymail/issues/1604) -- Check HTMLInputElement.validity() for - [#1733](https://github.com/the-djmaze/snappymail/issues/1733) - -### Changed -- Use a modified [Squire 2.3.2](https://github.com/the-djmaze/Squire/commits/snappymail/) -- cleanHtml use allowedTags instead of disallowedTags and improved CSS handling -- Update Portuguese by @ner00 - -### Fixed -- mXSS exploit found by SonarSource - [CVE-2024-45800](https://github.com/the-djmaze/snappymail/security/advisories/GHSA-2rq7-79vp-ffxm) -- Call to a member function Email() on null - [#1706](https://github.com/the-djmaze/snappymail/issues/1706) -- IMAP capabilities via IMAP Proxy - [#1725](https://github.com/the-djmaze/snappymail/issues/1725) -- Messages on page setting is not validated against 999 max - [#1733](https://github.com/the-djmaze/snappymail/issues/1733) - - -## 2.37.3 – 2024-08-27 - -### Added -- Mark images with width=1 as tracking pixel -- Show warning in Admin -> About when PHP runs in 32bit -- Edit ACL rules - [#157](https://github.com/the-djmaze/snappymail/issues/157) -- Show GnuPG version for - [#1560](https://github.com/the-djmaze/snappymail/issues/1560) -- Make sure only scalar values are allowed in $_ENV for - [#1560](https://github.com/the-djmaze/snappymail/issues/1560) -- Change minimum new mail check interval - [#1678](https://github.com/the-djmaze/snappymail/issues/1678) -- Sieve editor does not support "index" extension - [#1709](https://github.com/the-djmaze/snappymail/issues/1709) - -### Changed -- Improved domain autoconfig interaction -- MS autodiscover priorities DNS over subdomain -- Simplify sieve scripts list - [#1675](https://github.com/the-djmaze/snappymail/issues/1675) -- Handling of (token) errors due to - [#1706](https://github.com/the-djmaze/snappymail/issues/1706) -- Sabre/Xml to v4.0.5 -- Update Chinese by @Artoria2e5 -- Update French by @hguilbert - -### Fixed -- Thread sorting visible after disabling the imap capability - [#1574](https://github.com/the-djmaze/snappymail/issues/1574) -- Creating new message impossible as long as a draft exists? - [#1710](https://github.com/the-djmaze/snappymail/issues/1710) -- InvalidToken error at login - [#1706](https://github.com/the-djmaze/snappymail/issues/1706) - -### Nextcloud -- Force Nextcloud personal language by default - [#1428](https://github.com/the-djmaze/snappymail/issues/1428) - - -## 2.37.2 – 2024-08-13 - -### Added -- Validate Fetch JSON response - -### Fixed -- PATH_INFO bug due to Office365 OAuth login -- Prevent logout loop on error - -### Nextcloud -- Failed loading due to Office365 OAuth2 attempt - [#1703](https://github.com/the-djmaze/snappymail/issues/1703) - - -## 2.37.1 – 2024-08-12 - -### Fixed -- Gulp v5 broke the fonts - -### Nextcloud -- Support v30 - - -## 2.37.0 – 2024-08-12 - -### Added -- JavaScript event `rl-vm-visible` -- Detailed error message on account switch failure for - [#1594](https://github.com/the-djmaze/snappymail/issues/1594) -- Workarounds for Microsoft OAuth2 (currently requires Apache AcceptPathInfo) - [#1645](https://github.com/the-djmaze/snappymail/issues/1645) -- Support "mark for deletion" - [#1657](https://github.com/the-djmaze/snappymail/issues/1657) by @smsoft-ru -- Invoke "Update Identity" pop up right after login (when not initialized) - [#1689](https://github.com/the-djmaze/snappymail/issues/1689) -- Keyboard shortcut for "Swap default (background) color" - [#1690](https://github.com/the-djmaze/snappymail/issues/1690) - -### Changed -- Updated gulp to v5 -- Replaced vulnerable gulp-header with gulp-append-prepend -- Removed abandoned vulnerable rollup-plugin-html -- Align save button in admin security settings -- Made registerProtocolHandler('mailto') optional by activating at Settings -> General -- Improved InvalidToken handling for - [#1653](https://github.com/the-djmaze/snappymail/issues/1653) -- Cleanup localizations -- Update French by @hguilbert -- Update German by @tkasch -- Update Polish by @tinola -- Update Portuguese by @ner00 - -### Fixed -- prevent multiple afterShow() and afterHide() due to `transitionend` on multiple CSS properties -- Attempt to read property "smimeSigned" on null -- Refreshing mail list doesn't update current message - [#1654](https://github.com/the-djmaze/snappymail/issues/1654) -- Deletion of CACHE folder causing error - [#1660](https://github.com/the-djmaze/snappymail/issues/1660) -- Multiple line breaks are not displayed - [#1666](https://github.com/the-djmaze/snappymail/issues/1666) -- RainLoop\Exceptions\ClientException::__construct(): Argument #2 ($oPrevious) must be of type ?Throwable, string given - [#1686](https://github.com/the-djmaze/snappymail/issues/1686) -- SpamAssassin Division by zero - [#1694](https://github.com/the-djmaze/snappymail/issues/1694) -- Failed to parse RFC 2822 date '6 Jul 2024 16:42:09 +0200' - [#1694](https://github.com/the-djmaze/snappymail/issues/1694) -- Fix capabilities when THREAD is disabled - [#1698](https://github.com/the-djmaze/snappymail/pull/1698) by @akhil1508 - -### Nextcloud -- Failed loading due to incorrect `app_path` -- Bugfix language detection -- Allow multi-account in nc with oauth login - [#1699](https://github.com/the-djmaze/snappymail/pull/1699) by @akhil1508 - - -## 2.36.4 – 2024-06-25 - -### Added -- Customize private key passphrase expiration interval - [#1545](https://github.com/the-djmaze/snappymail/discussions/1545) -- AdvancedSearch support for filtering mails before a given date - [#1606](https://github.com/the-djmaze/snappymail/pull/1606) by @codiflow -- Control valid spam and virus headers - [#1607](https://github.com/the-djmaze/snappymail/issues/1607) -- Remember S/MIME private Key without function - [#1611](https://github.com/the-djmaze/snappymail/issues/1611) -- Resize compose dialog -- Magnetic theme - [#1637](https://github.com/the-djmaze/snappymail/pull/1637) by @TheCuteFoxxy - -### Changed -- Improved signing messages by allowing to choose between the options -- Improved language detection code -- More detailed Decrypt errors -- Update French by @hguilbert -- Update Polish by @tinola -- Update Portuguese by @ner00 -- Update Spanish by @huloza - -### Fixed -- Default language error -- Undefined $sEmail in DoAdminDomainMatch -- Handling Autocrypt header failed on `=` - [#1608](https://github.com/the-djmaze/snappymail/issues/1608) -- Blank lines are inserted when editing draft - [#1609](https://github.com/the-djmaze/snappymail/issues/1609) -- Workaround Cyrus MAILBOXID bug (disable OBJECTID capability by default due to impact) - [#1640](https://github.com/the-djmaze/snappymail/issues/1640) -- Workaround HTML with multiple body elements or MIME with multiple text/html - [#1641](https://github.com/the-djmaze/snappymail/issues/1641) - -### Nextcloud -- OIDC stay logged in - [#1620](https://github.com/the-djmaze/snappymail/pull/1620) by @avinash-0007 - - -## 2.36.3 – 2024-05-27 - -### Changed -- UserAuth prevent plugin errors (like the Nextcloud plugin did) - -### Fixed -- Undefined variable $aTokenData - [#1567](https://github.com/the-djmaze/snappymail/issues/1567) - - -## 2.36.2 – 2024-05-26 - -### Added -- "copy to" action in menu's for - [#1559](https://github.com/the-djmaze/snappymail/issues/1559) -- Log signal info for - [#1569](https://github.com/the-djmaze/snappymail/issues/1569) -- OpenPGP.js automatically import backup keys from server - -### Changed -- Improved "remember me" cookie handling -- Update Basque by @Thadah -- Update Portuguese by @ner00 - -### Fixed -- "Account already exists" - [#1561](https://github.com/the-djmaze/snappymail/issues/1561) -- Properly escape path separator in tar.php file list regex - [#1562](https://github.com/the-djmaze/snappymail/pull/1562) by @sevmonster -- Prevent mkdir() error - [#1565](https://github.com/the-djmaze/snappymail/issues/1565) -- SCRAM Exception when trying to log in to SMTP - [#1575](https://github.com/the-djmaze/snappymail/issues/1575) -- Error when redirected back to instance after Gmail OAuth - [#1580](https://github.com/the-djmaze/snappymail/issues/1580) -- Uncaught TypeError: hasPublicKeyForEmails(...).then is not a function - [#1589](https://github.com/the-djmaze/snappymail/issues/1589) -- Undefined variable $sFilename -- GPG/PGP exec() return false handling - -### Nextcloud -- OIDC login active again - [#1572](https://github.com/the-djmaze/snappymail/pull/1572) by @avinash-0007 - - -## 2.36.1 – 2024-04-23 - -### Added -- Autoconfig detect through DNS SRV (RFC 6186 & 8314) and disable MX -- Have I Been Pwned class to check breached passwords and email addresses -- Handle RFC 5987 in Content-Disposition header -- Ignore text/x-amp-html -- Show SMTP error to user - [#1521](https://github.com/the-djmaze/snappymail/issues/1521) -- OAuth2 for login using gmail (and others) - -### Changed -- logMask all AUTHENTICATE requests -- ErrorTip use white-space: pre -- Simplify LoginProcess handling -- ES2020 everywhere (require Safari 13.1) -- Modified Squire to be more in line with v2.2.8 -- CSS set min-width for .attachmentParent and .flagParent to line them up -- cPanel use extension login-cpanel instead of login-remote -- Improved login credentials handling -- Speedup Knockout a bit and removed `with($context)` scope -- Update Belarusian by @spoooyders -- Update Chinese by @mayswind -- Update French by @hguilbert -- Update Polish by @tinola -- Update Portuguese by @ner00 - -### Fixed -- Content encoding and type detection in JavaScript could fail due to case-sensitivity. -- Extensions set logger failed -- GnuPG check open_basedir and if shell_exec is disabled - [#1385](https://github.com/the-djmaze/snappymail/issues/1385) - [#1496](https://github.com/the-djmaze/snappymail/issues/1496) - [#1555](https://github.com/the-djmaze/snappymail/issues/1555) -- Hide pagination when search result has no messages -- Prevent mbstring error before setup.php -- Prevent MessagesPerPage Infinity - [#1540](https://github.com/the-djmaze/snappymail/issues/1540) -- Reseal CryptKey failed - [#1543](https://github.com/the-djmaze/snappymail/issues/1543) - -### Nextcloud -- Add an occ command to set up the login settings - [#1552](https://github.com/the-djmaze/snappymail/issues/1552) - - -## 2.36.0 – 2024-03-18 - -### Added -- Allow setting the supported THREAD algorithm -- Icon to system folders -- Remove remembered password after 15 minutes of inactivity - [#1142](https://github.com/the-djmaze/snappymail/issues/1142) -- Swap background and text color for unreadable text on dark background - [#1486](https://github.com/the-djmaze/snappymail/issues/1486) -- Generate TOTP code at ?Admin -> Security - [#1501](https://github.com/the-djmaze/snappymail/issues/1501) -- Button to change S/MIME private key passphrase - [#1505](https://github.com/the-djmaze/snappymail/issues/1505) -- Belarusian - [#1512](https://github.com/the-djmaze/snappymail/pull/1512) by @spoooyders -- Log some domain idn_to_ascii issues - [#1513](https://github.com/the-djmaze/snappymail/issues/1513) - -### Changed -- On folder/mailbox rename, also rename all children instead of reloading all -- Seal MainAccount CryptKey and on error ask old login passphrase to reseal key. -- Moved cache drivers outside core into extensions -- Sieve always allow fileinto INBOX - [#1510](https://github.com/the-djmaze/snappymail/issues/1510) -- Moved application.ini `sieve_auth_plain_initial` to per domain config -- Languages use rfc5646, by using the shortest ISO 639 code by default -- Update French by @hguilbert -- Update Portuguese by @ner00 - -### Fixed -- On folder/mailbox rename, the old fullName must be removed from cache -- On folder/mailbox rename, the checkable option was not renamed -- Sort accounts drag & drop -- S/MIME encrypted and opaque signed not visible - [#1450](https://github.com/the-djmaze/snappymail/issues/1450) -- Wrong last UID of thread - [#1507](https://github.com/the-djmaze/snappymail/issues/1507) -- Creation of dynamic property SnappyMail\DAV\Client::$HTTP - [#1509](https://github.com/the-djmaze/snappymail/issues/1509) -- "Download as ZIP" fails for messages - [#1514](https://github.com/the-djmaze/snappymail/issues/1514) -- SMTP "Authentication failed" when IMAP uses `shortLogin` and SMTP not - [#1517](https://github.com/the-djmaze/snappymail/issues/1517) - - -## 2.35.4 – 2024-03-16 - -### Added -- \SnappyMail\IDN::toAscii() - -### Changed -- OpenPGP.js to v5.11.1 -- punycode.js lowercase domain names -- application.ini `login_lowercase` removed and now configurable per domain JSON `lowerLogin` -- Update Portuguese by @ner00 - -### Fixed -- Raise JS TypeEroor "toLowerCase" after update - [#1491](https://github.com/the-djmaze/snappymail/issues/1491) -- Call to undefined function shell_exec - [#1496](https://github.com/the-djmaze/snappymail/issues/1496) -- Download attachments as ZIP doesn't work for PGP encrypted mail - [#1499](https://github.com/the-djmaze/snappymail/issues/1499) -- Importing or downloading a PGP public key attachment from a PGP encrypted message doesn't work - [#1500](https://github.com/the-djmaze/snappymail/issues/1500) -- VCard PHP Notice: Undefined index: ENCODING - -### Nextcloud -- Changed stored password handling -- Can't login from nextcloud with 2.35.3 bug Nextcloud - [#1490](https://github.com/the-djmaze/snappymail/issues/1490) - - -## 2.35.3 – 2024-03-12 - -### Added -- GnuPG can be disabled -- Missing strings for localization inside identity popup (Cryptography > S/MIME) - [#1458](https://github.com/the-djmaze/snappymail/issues/1458) -- Automatically verify PGP and S/MIME signed messages -- TNEFDecoder for - [#1012](https://github.com/the-djmaze/snappymail/discussions/1012) -- RTF to HTML converter for - [#1012](https://github.com/the-djmaze/snappymail/discussions/1012) -- Polyfill for PHP ctype - [#1250](https://github.com/the-djmaze/snappymail/issues/1250) - -### Changed -- `new Error()` to `Error()` -- Reduce KnockoutJS footprint by removing unused code -- CSS reposition rainloopErrorTip location -- Improved error handling on PGP and S/MIME decrypt -- Improved OpenPGP.js import keys -- Use Identity S/MIME key and certificate from server instead of POST -- application.ini `[webmail]language_admin` to `[admin_panel]language` -- application.ini `[security]admin_panel_host` to `[admin_panel]host` -- application.ini `[security]admin_panel_key` to `[admin_panel]key` -- Drop deprecated Domain::SetConfig() -- Internationalized domain names are now handled as punycode -- Cacher->Get() can now return NULL -- Update French by @hguilbert -- Update Polish by @tinola -- Update Portuguese by @ner00 - -### Fixed -- Handling of Internationalized Domain Names in several areas -- Decrypt error message -- Stalwart ManageSieve Error 352 when getting Filters - [#1455](https://github.com/the-djmaze/snappymail/issues/1455) -- Nextcloud V25+ theme slightly broken - [#1463](https://github.com/the-djmaze/snappymail/issues/1463) -- PGP decryption fails with "Not armored text" - [#1462](https://github.com/the-djmaze/snappymail/issues/1462) -- AUTH_BASIC falling through as AUTH_BEARER; change AUTH_BEARER to a different value - [#1461](https://github.com/the-djmaze/snappymail/issues/1461) -- SetPassword expects \SnappyMail\SensitiveString -- Crash on importing corrupt OpenPGP keys -- Crash on old browsers instead of showing error -- Ignore popups on logoutReload() - [#1467](https://github.com/the-djmaze/snappymail/issues/1467) -- Custom SASLMechanisms fail in IMAP when the connection is secure - [#1484](https://github.com/the-djmaze/snappymail/pull/1484) by @botsarenthuman - - -## 2.35.2 – 2024-02-27 - -### Added -- GnuPG error handling -- Missing strings for localization inside identity popup (Cryptography > S/MIME) - [#1458](https://github.com/the-djmaze/snappymail/issues/1458) - -### Changed -- Update Portuguese by @ner00 - -### Fixed -- Drop support for gnupg PECL extension as it fails with "no passphrase" issues -- Error 352 when getting Filters - [#1455](https://github.com/the-djmaze/snappymail/issues/1455) - -### Nextcloud -- SetPassword(): Argument #1 must be of type SensitiveString, string given - [#1456](https://github.com/the-djmaze/snappymail/issues/1456) - - -## 2.35.1 – 2024-02-26 - -### Added -- Search functionality in Admin -> Config -- Cache S/MIME passphrases when "remember" is checked -- Import S/MIME certificate popup -- pre-verify S/MIME opaque signed messages so we have a body to view -- Sort PGP keys and S/MIME certificates on email address -- Optionally use existing private key to generate S/MIME certificate - -### Changed -- Better handling to detect which PGP or S/MIME sign/encrypt to use -- Improved StorageType handling -- Cleanup and improved Capa handling -- OPEN_PGP should be OPENPGP as it is one word -- Use get_debug_type() instead of gettype() -- Require OpenSSL due to S/MIME -- AbstractProvider::IsActive() is now an abstract method and must be defined in child class -- Make better use of SnappyMail\SensitiveString -- Update Polish translation by @tinola - -### Fixed -- Verify S/MIME signatures got broken allong the way while implementing this -- Generate S/MIME self-signed certificate failed to keep existing private key -- MIME parser RegExp didn't escape boundary which caused issues -- TypeError: b64Encode(...).match(...) is null on saving compose draft -- Fix timestampToString() for future dates - - -## 2.35.0 – 2024-02-20 - -### Added -- S/MIME support - [#259](https://github.com/the-djmaze/snappymail/issues/259) - -### Changed -- Disable IMAP METADATA by default (hardly used) -- Update Polish translation by @tinola -- Rename CSS .openpgp-control to .crypto-control -- Renamed some methods in PHP - -### Fixed -- When moving a folder/mailbox check for parent delimiter -- Mask `passphrase` in the logs for PHP < 8.2 -- Added some missing translations -- Sign messages using PGP -- Check for CONDSTORE or QRESYNC to get the HIGHESTMODSEQ -- Unable to login on certain IMAP server since 2.34.2 - [#1438](https://github.com/the-djmaze/snappymail/issues/1438) - -### Nextcloud -- Save as .eml - [#1425](https://github.com/the-djmaze/snappymail/issues/1425) - - -## 2.34.2 – 2024-02-14 - -### Fixed -- Message was sent but not saved to sent items folder - [#1432](https://github.com/the-djmaze/snappymail/issues/1432) -- Login with scram failed - [#1433](https://github.com/the-djmaze/snappymail/issues/1433) - - -## 2.34.1 – 2024-02-13 - -### Added -- Autocrypt support - [#342](https://github.com/the-djmaze/snappymail/issues/342) -- Load the mailboxes/folders of all namespaces (other users, global, shared, etc.) -- Load keys from server into OpenPGP.js - [#973](https://github.com/the-djmaze/snappymail/issues/973) -- Import PGP Keys from remote key servers -- Sort Inbox Folders with Unread Messages First - [#1427](https://github.com/the-djmaze/snappymail/issues/1427) -- Define JMAP FolderModel.myRights -- Identity Management: add identity display name - [#1405](https://github.com/the-djmaze/snappymail/issues/1405) -- Identity Management: add per-identity "sent" folder - [#1404](https://github.com/the-djmaze/snappymail/issues/1404) -- Some support for JSON-LD / Structured Email - [#1422](https://github.com/the-djmaze/snappymail/issues/1422) -- Domain Autoconfig and Microsoft's autodiscover (and also as extension/plugin) -- View MMS messages that are received via email - [#1294](https://github.com/the-djmaze/snappymail/issues/1294) -- Draft code for S/MIME - [#259](https://github.com/the-djmaze/snappymail/issues/259) - -### Changed -- Many OpenPGP improvements - [#89](https://github.com/the-djmaze/snappymail/issues/89) -- Allow CSP connect-src CORS for keys.openpgp.org to directly fetch PGP keys -- Improved handling of visible folders -- KnockoutJS Replace some ko.exportSymbol('*') in favour of ko['*'] -- KnockoutJS use Symbol for isObservableArray() -- Simplify generating folderListVisible -- Drop the bSearchSecretWords param from logger -- Transparent background for text - [#1412](https://github.com/the-djmaze/snappymail/issues/1412) -- Enable OpenPGP.js by default at install -- Added folder edit popup for improved IMAP ACL Support - [#157](https://github.com/the-djmaze/snappymail/issues/157) -- Process all IMAP namespaces -- Update Polish by @tinola -- Update Portuguese by @ner00 - -### Fixed -- Make time_zone a select list due to PEBKAC -- Workaround Outlook generated double spacing - [#1415](https://github.com/the-djmaze/snappymail/issues/1415) -- HTML Parser is not picking up the full Unsubscribe URL in the attached text file - [#1225](https://github.com/the-djmaze/snappymail/issues/1225) -- Contacts - it auto "Select All", after entry delete - [#1411](https://github.com/the-djmaze/snappymail/issues/1411) -- Message header parsing issue - [#1403](https://github.com/the-djmaze/snappymail/issues/1403) -- apple-touch-icon should not be transparent - [#1408](https://github.com/the-djmaze/snappymail/issues/1408) -- Creation of dynamic property is deprecated - [#1409](https://github.com/the-djmaze/snappymail/issues/1409) -- Ask/send readReceipt was broken -- OpenPGP public key can not be removed anymore after importing private key of subkey - [#1384](https://github.com/the-djmaze/snappymail/issues/1384) -- KnockoutJS failed to output text '0' -- JavaScript friendlySize() failed on 0 -- Workaround Dovecot `PREAUTH [CAPABILITY (null)]` issue -- Workaround disabled ACL could cause "Disconnected: Too many invalid IMAP commands" - -### Nextcloud -- Save multiple as .eml - [#1425](https://github.com/the-djmaze/snappymail/issues/1425) -- Disabled support for Nextcloud OpenID Connect - [#1420](https://github.com/the-djmaze/snappymail/issues/1420) - - -## 2.33.0 – 2024-01-22 - -### Added -- Feature to use the SQLite AddressBook per login account instead of global (on by default). -- Return all fetched messages headers in JSON. - -### Changed -- Docker hub use Alpine linux 3.18.5 and PHP 8.2 -- Some InvalidArgumentException to the better suited ValueError -- Removed some unused KnockoutJS code -- KnockoutJS drop unused rateLimit method -- Cleanup some data-bind="" -- Drop the disabled KnockoutJS twoWayBindings -- Drop support for KnockoutJS _ko_property_writers and for two-way binding they must be observables -- Login form use method="POST" to prevent uri exposure when javascript fails -- Merge code to generate MIME PGP parts and MIME Plain parts -- SMTP sendRequestWithCheck for future support of RFC's -- Cleanup mime header handling - -### Fixed -- Sorting not supported since 2.32.0 - [#1373](https://github.com/the-djmaze/snappymail/issues/1373) -- FILE_ON_SAVING_ERROR is not defined - [#1379](https://github.com/the-djmaze/snappymail/issues/1379) -- Saving EML files with same subject result in only saving latest email - [#1381](https://github.com/the-djmaze/snappymail/issues/1381) -- Some Sieve parser issues -- Handling of RainLoop Sieve script -- Sieve rfc5429 RejectCommand and ErejectCommand -- KnockoutJS title:value was removed, use attr:{title:value} -- dataBaseUpgrade() always runs on sqlite and pgsql -- Message was sent but not saved to sent items folder - [#1397](https://github.com/the-djmaze/snappymail/issues/1397) -- DKIM `pass` detection sometimes failed - - -## 2.32.0 – 2023-12-26 - -### Added -- Run full GetUids() in background when message_list_limit is set -- MessageListThreadsMap as background task when message_list_limit is set -- Properly set CACHEDIR.TAG -- Sending group email to all contact addresses - [#1286](https://github.com/the-djmaze/snappymail/pull/1286) by @rezaei92 - -### Changed -- Default IMAP message_list_limit to 10000 -- DoMessageCopy() return toFolder hash/etag -- Improved Squire WYSIWYG -- Sort real attachments and inline attachments for - [#1360](https://github.com/the-djmaze/snappymail/issues/1360) -- Nextcloud Theme fixes and improvements - [#1363](https://github.com/the-djmaze/snappymail/pull/1363) by @hampoelz -- Improve display of attachments - [#1361](https://github.com/the-djmaze/snappymail/issues/1361) -- Rename messageVisibility to messageVisible -- All CSS font-size to % instead of px -- Flip source code view of .eml attachments - [#1332](https://github.com/the-djmaze/snappymail/issues/1332) - -### Fixed -- Folders array_filter(): Argument 1 must be of type array, null given -- At upgrade set `static` and `themes` folder to 0755 -- Preview tooltip shows "null" when PREVIEW capability is disabled - -### Nextcloud -- Improved language handling - [#1362](https://github.com/the-djmaze/snappymail/pull/1362) by @avinash-0007 -- FilterLanguage had wrong parameter order -- Use NextcloudV25+ theme by default - - -## 2.31.0 – 2023-12-08 - -### Added -- PHP Hook `filter.language` to allow remote language selection - -### Changed -- Cleaner language detection -- Get Squire in sync with v2.2.5 and some bugfixes -- Update French by @Cwpute -- Squire: drop support for iPod - -### Fixed -- Call to undefined method FolderMyRights() - [#1344](https://github.com/the-djmaze/snappymail/issues/1344) -- NO Mailbox does not exist, or must be subscribed to") - [#1354](https://github.com/the-djmaze/snappymail/issues/1354) -- Flag indicators are added to wrong message - [#1347](https://github.com/the-djmaze/snappymail/pull/1347) by @SergeyMosin -- Squire: issue when using the enter key in a reply window - [#1296](https://github.com/the-djmaze/snappymail/issues/1296) -- Squire: crash on cut/delete range - -### Nextcloud -- Use language as defined in Nextcloud settings - [#1293](https://github.com/the-djmaze/snappymail/issues/1293) -- Plugin Call to undefined method RainLoop\Model\MainAccount::ImapConnectAndLoginHelper() -- SnappyMail failed due to Nextcloud Symfony polyfill - - -## 2.30.0 – 2023-12-04 - -### Added -- SnappyMail\SensitiveString class to secure passwords -- Allow to disable all IMAP features through Admin -> Domain -- Setting to open mails in a tab or new window - [#951](https://github.com/the-djmaze/snappymail/issues/951) -- Fully support IMAP PREVIEW - [#1338](https://github.com/the-djmaze/snappymail/issues/1338) -- Disable "Mark message as read after", offer manual toggle - [#1289](https://github.com/the-djmaze/snappymail/issues/1289) -- A "Move to" button inside message view as an icon/button and in the drop down menu. - [#1295](https://github.com/the-djmaze/snappymail/issues/1295) -- Support for IMAP WITHIN -- Support \noinferiors to disallow creating subfolders -- A test due to Failed loading libs.min.js - [#358](https://github.com/the-djmaze/snappymail/issues/358), - [#862](https://github.com/the-djmaze/snappymail/issues/862), - [#890](https://github.com/the-djmaze/snappymail/issues/890), - [#895](https://github.com/the-djmaze/snappymail/issues/895), - [#1238](https://github.com/the-djmaze/snappymail/issues/1238), - [#1320](https://github.com/the-djmaze/snappymail/issues/1320) - -### Changed -- Split PHP 8 polyfills from include.php -- Disable snappymail/v/0.0.0/static/.htaccess for now as many servers have issues with it -- Merged all Domain `disable_*` settings into `disabled_capabilities:[]` -- Prioritize LIST-EXTENDED over LSUB (LSUB deprecated in IMAP4rev2) -- Removed unused ImapClient::IsSupported() -- Removed obsolete `$_ENV['SNAPPYMAIL_NEXTCLOUD']` -- Removed unused Plugin->replaceTemplate() -- Removed openDropdownTrigger - -### Fixed -- Move to button does not work - [#1328](https://github.com/the-djmaze/snappymail/issues/1328) -- Mark passwords as sensitive information - [#1343](https://github.com/the-djmaze/snappymail/issues/1343) -- Account sSmtpPassword wrong value -- SCRAM sign-in failed - [#1245](https://github.com/the-djmaze/snappymail/issues/1245) -- Squire generates to many `

` - [#1339](https://github.com/the-djmaze/snappymail/issues/1339) -- Creation of dynamic property SnappyMail\Stream\ZipEntry::$compression is deprecated -- `json.after-*` hooks didn't send $aResponse as recursive array -- Sieve: Move to folder with trailing space does not work - [#1329](https://github.com/the-djmaze/snappymail/issues/1329) -- Squire: cantFocusEmptyTextNodes var is always undefined - [#1337](https://github.com/the-djmaze/snappymail/issues/1337) -- Squire: Remove redundant after replacing styles -- Squire: Handle empty nodes in moveRangeBoundariesDownTree -- Theme "Nextcloud V25+" can't be translated - [#1331](https://github.com/the-djmaze/snappymail/issues/1331) - - -## 2.29.4 – 2023-11-21 - -### Fixed -- Contacts not work - [#1319](https://github.com/the-djmaze/snappymail/issues/1319) - - -## 2.29.3 – 2023-11-21 - -### Added -- Docker Hub image - [#965](https://github.com/the-djmaze/snappymail/pull/965) by @leojonathanoh - -### Changed -- Sabre/VObject 4.5.4 and Sabre/Xml 4.0.4 - [#1311](https://github.com/the-djmaze/snappymail/issues/1311) - -### Fixed -- '#/mailbox/folder/mUID/search' uri/route handling - [#1301](https://github.com/the-djmaze/snappymail/pull/1301) by @SergeyMosin -- "Remember me" doesn't work when browser is closed - [#1313](https://github.com/the-djmaze/snappymail/issues/1313) -- Blank email displayed when "Prefer HTML to plain text" is unchecked and the message is html only - [#1302](https://github.com/the-djmaze/snappymail/issues/1302) -- Parent folder of Sub folder not useable. - [#1008](https://github.com/the-djmaze/snappymail/issues/1008) -- Large detailed header don't display body - [#1284](https://github.com/the-djmaze/snappymail/issues/1284) - -### Nextcloud -- Improvements for Install / update issues #929 - [#929](https://github.com/the-djmaze/snappymail/issues/929) -- Should use language as defined in cloud settings #1293 - [#1293](https://github.com/the-djmaze/snappymail/issues/1293) - - -## 2.29.2 – 2023-11-14 - -### Added -- Show size of folders in folders list #1303 - [#1303](https://github.com/the-djmaze/snappymail/issues/1303) - -### Fixed -- Configuration failed when using special chars in MySQL password #1308 - [#1308](https://github.com/the-djmaze/snappymail/issues/1308) -- With email open, "delete" doesn't delete #1274 - [#1274](https://github.com/the-djmaze/snappymail/issues/1274) -- Fix threading view in Thunderbird (others?) - [#1304](https://github.com/the-djmaze/snappymail/pull/1304) by @tkasch - - -## 2.29.1 – 2023-10-02 - -### Fixed -- Some small messages list bugs - - -## 2.29.0 – 2023-10-02 - -### Added -- Modern UI / Nextcloud Theme - [#629](https://github.com/the-djmaze/snappymail/pull/629) by @hampoelz -- "Add/Edit signature" label to PopupsIdentity.html - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- use calendar icon in message list for messages with '.ics' or 'text/calendar' attachments by @SergeyMosin - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) -- Show unseen message count when the message list is threaded - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- in mobile mode hide folders(left) panel when a folder is clicked - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- spellcheck the subject when 'allowSpellcheck' setting is true - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- 'collapse_blockquotes', 'allow_spellcheck' and 'mail_list_grouped' to admin settings ('defaults' section) - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- Browser support for autocompleting TOTP code - [#1251](https://github.com/the-djmaze/snappymail/issues/1251) - -### Changed -- URL strip tracking for - [#1225](https://github.com/the-djmaze/snappymail/issues/1225) -- Color picker use color blind palette "Tableau 10" by Maureen Stone by default - [#1199](https://github.com/the-djmaze/snappymail/issues/1199) -- Draft code to improve mobile breakpoints - [#1150](https://github.com/the-djmaze/snappymail/issues/1150) -- address input: space character can trigger '_parseValue' if the email address looks complete - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- if applicable set '\\answered' or '$forwarded' flag after a message is sent so the proper icon is shown in the message list view - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin - -### Fixed -- CHARSET is not valid in UTF8 mode - [#1230](https://github.com/the-djmaze/snappymail/issues/1230) -- Spam score is always "acceptable" - [#1228](https://github.com/the-djmaze/snappymail/issues/1228) -- Undefined constant PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT - [#1205](https://github.com/the-djmaze/snappymail/issues/1205) -- Fetch controller.abort(reason) handling - [#1220](https://github.com/the-djmaze/snappymail/issues/1220) -- "Request failed" on message move - [#1220](https://github.com/the-djmaze/snappymail/issues/1220) -- Unwrapped text nodes attached to squire._root - [#1234](https://github.com/the-djmaze/snappymail/pull/1234) by @SergeyMosin -- Extra wrapper div is added in Squire every time a Draft is open (or closed) after save. - [#1208](https://github.com/the-djmaze/snappymail/issues/1208) -- foreach() argument must be of type array|object - [#1237](https://github.com/the-djmaze/snappymail/issues/1237) -- `` tag 'style' is lost in replies - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- unseen indicator is not shown in thread view when 'listGrouped' settings is false - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- TOTP plugin is dependent on ctype - [#1250](https://github.com/the-djmaze/snappymail/issues/1250) - -### Nextcloud -- iFrame mode: click on unified search result opens inner iFrame - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- set 'smremember' cookie if 'sign_me_auto' is set to 'DefaultOn' when using 'snappymail-autologin*', otherwise nextcloud users need to re-login when the browser is re-opened - [#1248](https://github.com/the-djmaze/snappymail/pull/1248) by @SergeyMosin -- Improve UX of "Put in Calendar" option in plugin - [#1259](https://github.com/the-djmaze/snappymail/pull/1259) by @theronakpatel - - -## 2.28.4 – 2023-07-10 - -### Added -- application.ini msg_default_action - [#1204](https://github.com/the-djmaze/snappymail/pull/1204) by @SergeyMosin -- application.ini view_show_next_message - [#1204](https://github.com/the-djmaze/snappymail/pull/1204) by @SergeyMosin -- application.ini view_images - [#1204](https://github.com/the-djmaze/snappymail/pull/1204) by @SergeyMosin -- nextcloud add ability to include custom php file in InstallStep migration - [#1197](https://github.com/the-djmaze/snappymail/pull/1197) by @SergeyMosin -- Support plugin for Squire editor - [#1192](https://github.com/the-djmaze/snappymail/issues/1192) - -### Changed -- only show 'Add "domain.tld" as an application for mailto links?' message after login (firefox shows the message on every reload otherwise). - [#1204](https://github.com/the-djmaze/snappymail/issues/1204) -- Convert getPdoAccessData() : array to a RainLoop\Pdo\Settings object instance -- New bidi buttons to Squire editor - [#1200](https://github.com/the-djmaze/snappymail/pull/1200) by @rezaei92 - -### Fixed -- Undefined constant PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT - [#1205](https://github.com/the-djmaze/snappymail/issues/1205) -- 'reloadTime' function result is passed into 'setInterval' instead of the function - [#1204](https://github.com/the-djmaze/snappymail/pull/1204) by @SergeyMosin -- UNKNOWN-CTE Invalid data in MIME part - [#1186](https://github.com/the-djmaze/snappymail/issues/1186) - - -## 2.28.3 – 2023-06-22 - -### Added -- Attachments in "new window" view - [#1166](https://github.com/the-djmaze/snappymail/issues/1166) - -### Changed -- Update Portuguese by @ner00 -- Update French by @hguilbert - -### Fixed -- Some emails with inline CSS break the UI - [#1187](https://github.com/the-djmaze/snappymail/issues/1187) -- Remote.get() Promise broken by previous change - [#1185](https://github.com/the-djmaze/snappymail/issues/1185) -- Class "MailSo\Base\Exceptions\InvalidArgumentException" not found - [#1182](https://github.com/the-djmaze/snappymail/issues/1182) -- First account not showed in the right list (dropbox) - [#1180](https://github.com/the-djmaze/snappymail/issues/1180) - - -## 2.28.2 – 2023-06-19 - -### Added -- Detailed error for "Cannot access the repository at the moment" - [#1164](https://github.com/the-djmaze/snappymail/issues/1164) -- Bidi in Squire editor - [#1158](https://github.com/the-djmaze/snappymail/issues/1158) -- Translate Squire UI -- Nextcloud 27 compatibility by @LarsBel -- JWT class for handling JSON Web Tokens - -### Changed -- Update German by @cm-schl -- Update French by @hguilbert -- Update Polish by @tinola -- Merge handling of local Account Settings. Found while investigating - [#1170](https://github.com/the-djmaze/snappymail/issues/1170) -- Image max-width now 100% instead of 90vw - -### Fixed -- Cannot modify header information - [#929](https://github.com/the-djmaze/snappymail/issues/929) (comment) -- Admin Panel broken when admin_panel_host is set - [#1169](https://github.com/the-djmaze/snappymail/issues/1169) -- Invalid CSP report-uri -- Prevent MessageList multiple request at the same time - [#1071](https://github.com/the-djmaze/snappymail/issues/1071) -- Error in Addressbook Sync - [#1179](https://github.com/the-djmaze/snappymail/issues/1179) -- base64_decode() second parameter must be true - - -## 2.28.1 – 2023-06-05 - -### Changed -- Optical issue with input fields for mail and folder search - [#1149](https://github.com/the-djmaze/snappymail/issues/1149) -- Update Chinese translation - [#1157](https://github.com/the-djmaze/snappymail/pull/1157) by @mayswind -- Update Polish translation - [#1156](https://github.com/the-djmaze/snappymail/pull/1156) by @tinola - -### Fixed -- Undefined SIG constants - [#1147](https://github.com/the-djmaze/snappymail/issues/1147) - - -## 2.28.0 – 2023-05-30 - -### Added -- Threaded view make number orange when unread sub-messages - [#1028](https://github.com/the-djmaze/snappymail/issues/1028) -- Handle PHP pctnl messages -- addEventListener('rl-view-model') missing for Settings - [#1013](https://github.com/the-djmaze/snappymail/issues/1013) -- CSS `--btn-border-radius` - -### Changed -- Improved RTL languages support - [#1056](https://github.com/the-djmaze/snappymail/issues/1056) -- Composer text/attachments as tabs - [#1119](https://github.com/the-djmaze/snappymail/issues/1119) -- Filter dialog doesn't refer to folder names consistently - [#1111](https://github.com/the-djmaze/snappymail/issues/1111) -- TLS connection for MYSQL contact db - [#1078](https://github.com/the-djmaze/snappymail/issues/1078) -- Allow empty message body when there are attachments - [#1052](https://github.com/the-djmaze/snappymail/issues/1052) -- PHP inherit logger as Trait -- Update Portuguese - [#1124](https://github.com/the-djmaze/snappymail/pull/1124) by @ner00 -- Update Traditional Chinese (Taiwan) - [#1107](https://github.com/the-djmaze/snappymail/pull/1107) by @chiyi4488 -- Update Russian - [#1108](https://github.com/the-djmaze/snappymail/pull/1108) by @konkere -- Update Italian - [#1094](https://github.com/the-djmaze/snappymail/pull/1094) by @cm-schl -- Update French - [#1102](https://github.com/the-djmaze/snappymail/pull/1102) by @hguilbert -- Update German - [#1087](https://github.com/the-djmaze/snappymail/pull/1087) by @cm-schl - -### Fixed -- Show messagelist timeout/abort error for - [#1071](https://github.com/the-djmaze/snappymail/issues/1071) -- DesktopNotifications setting not saved - [#1137](https://github.com/the-djmaze/snappymail/issues/1137) -- PHP Deprecation warning for $_openPipes - [#1141](https://github.com/the-djmaze/snappymail/issues/1141) -- Images size wrong - [#1134](https://github.com/the-djmaze/snappymail/issues/1134) -- Unable to preview body of encrypted mail in mailvelope reply-to - [#1130](https://github.com/the-djmaze/snappymail/issues/1130) -- Replace ` - - \ No newline at end of file diff --git a/plugins/search-filters/templates/PopupsSearchFilters.html b/plugins/search-filters/templates/PopupsSearchFilters.html deleted file mode 100644 index c85ca8914..000000000 --- a/plugins/search-filters/templates/PopupsSearchFilters.html +++ /dev/null @@ -1,54 +0,0 @@ -
- × -

-
- -
- -
diff --git a/plugins/search-filters/templates/STabSearchFilters.html b/plugins/search-filters/templates/STabSearchFilters.html deleted file mode 100644 index d006da345..000000000 --- a/plugins/search-filters/templates/STabSearchFilters.html +++ /dev/null @@ -1,39 +0,0 @@ -
-
-
- -     - -
- -
- -
- - - -
- - -
-
- - -
-
\ No newline at end of file diff --git a/plugins/send-save-in/LICENSE b/plugins/send-save-in/LICENSE deleted file mode 100644 index f709b02e2..000000000 --- a/plugins/send-save-in/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 RainLoop Team - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/send-save-in/index.php b/plugins/send-save-in/index.php deleted file mode 100644 index 2289c18f3..000000000 --- a/plugins/send-save-in/index.php +++ /dev/null @@ -1,23 +0,0 @@ -UseLangs(true); // start use langs folder - $this->addJs('savein.js'); - } -} diff --git a/plugins/send-save-in/savein.js b/plugins/send-save-in/savein.js deleted file mode 100644 index b95e18892..000000000 --- a/plugins/send-save-in/savein.js +++ /dev/null @@ -1,75 +0,0 @@ -(rl => { - const templateId = 'PopupsCompose', - folderListOptionsBuilder = () => { - const - aResult = [{ - id: '', - name: '', - system: false, - disabled: false - }], - sDeepPrefix = '\u00A0\u00A0\u00A0', - showUnsubscribed = true/*!SettingsUserStore.hideUnsubscribed()*/, - - foldersWalk = folders => { - folders.forEach(oItem => { - if (showUnsubscribed || oItem.hasSubscriptions() || !oItem.exists) { - aResult.push({ - id: oItem.fullName, - name: sDeepPrefix.repeat(oItem.deep) + oItem.detailedName(), - system: false, - disabled: !oItem.selectable() - }); - } - - if (oItem.subFolders.length) { - foldersWalk(oItem.subFolders()); - } - }); - }; - - - // FolderUserStore.folderList() - foldersWalk(rl.app.folderList() || []); - - return aResult; - }; - - let oldSentFolderFn; - - addEventListener('rl-view-model.create', e => { - if (templateId === e.detail.viewModelTemplateID) { - const view = e.detail; // ComposePopupView - - view.sentFolderValue = ko.observable(''); - view.sentFolderSelectList = ko.computed(folderListOptionsBuilder, {'pure':true}); - view.defaultOptionsAfterRender = (domItem, item) => - item && undefined !== item.disabled && domItem?.classList.toggle('disabled', domItem.disabled = item.disabled); - - oldSentFolderFn = view.sentFolder.bind(view); - view.sentFolder = () => view.sentFolderValue() || oldSentFolderFn(); - - document.getElementById(templateId).content.querySelector('.b-header tbody').append(Element.fromHTML(` - - Store in - - - (When send, store a copy of the message in the selected folder) - - `)); - - view.currentIdentity.subscribe(()=>{ - view.sentFolderValue(oldSentFolderFn()); - }); - } - }); - - addEventListener('rl-vm-visible', e => { - if (templateId === e.detail.viewModelTemplateID) { - const view = e.detail; // ComposePopupView - view.sentFolderValue(oldSentFolderFn()); - } - }); - -})(window.rl); diff --git a/plugins/set-remote-addr/LICENSE b/plugins/set-remote-addr/LICENSE deleted file mode 100644 index 271342337..000000000 --- a/plugins/set-remote-addr/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 RainLoop Team - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/set-remote-addr/index.php b/plugins/set-remote-addr/index.php deleted file mode 100644 index dbc10f8a6..000000000 --- a/plugins/set-remote-addr/index.php +++ /dev/null @@ -1,23 +0,0 @@ -addHook('filter.smtp-from', 'FilterDetectFrom'); - $this->addHook('smtp.before-connect', 'FilterSmtpConnect'); - $this->addHook('smtp.before-login', 'FilterSmtpCredentials'); - } - - /** - * \RainLoop\Model\Account $oAccount - * \MailSo\Mime\Message $oMessage - * string &$sFrom - */ - public function FilterDetectFrom(\RainLoop\Model\Account $oAccount, \MailSo\Mime\Message $oMessage, string &$sFrom) - { - $sWhiteList = \trim($this->Config()->Get('plugin', 'from_adress_pattern', '')); - $sFoundValue = ''; - if (\strlen($sWhiteList) && \RainLoop\Plugins\Helper::ValidateWildcardValues($sFrom, $sWhiteList, $sFoundValue) && $sFrom != $oAccount->Email()) { - \SnappyMail\LOG::info(get_class($this) ,'From address different from account recognized: '. $oAccount->Email().' -> '.$sFrom . '(~ '.$sFoundValue.')'); - $oMainAccount; - $oFromAccount; - if ($oAccount instanceof \RainLoop\Model\MainAccount ) { - $oMainAccount=$oAccount; - } else { - $oMainAccount=$this->Manager()->Actions()->getMainAccountFromToken(); - if ($oMainAccount->Email() == $sFrom) { - $this->aFromAccount[$oAccount->Email()]=$oMainAccount; - return; - } - } - $aAccounts = $this->Manager()->Actions()->getAccounts($oMainAccount); - foreach ($aAccounts as &$value) { - $oValue=\RainLoop\Model\AdditionalAccount::NewInstanceFromTokenArray($this->Manager()->Actions(), $value); - if ($oValue->Email()==$sFrom) { - $oFromAccount = $oValue; - break; - } - } - if (is_null($oFromAccount)){ - \SnappyMail\LOG::info(get_class($this),'No Account found for '. $sFrom); - if ($this->Config()->Get('plugin', 'throw_notfound_exception', true)) { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountDoesNotExist); - } - return; - } - $this->aFromAccount[$oAccount->Email()]=$oFromAccount; - } - } - /** - * @param \RainLoop\Model\Account $oAccount - * @param \MailSo\Smtp\SmtpClient $oSmtpClient - * @param \MailSo\Smtp\Settings $oSettings - */ - public function FilterSmtpConnect(\RainLoop\Model\Account $oAccount, \MailSo\Smtp\SmtpClient $oSmtpClient, \MailSo\Smtp\Settings $oSettings) - { - if ( isset($this->aFromAccount[$oAccount->Email()]) ) { - $oFromAccount = $this->aFromAccount[$oAccount->Email()]; - $oSettings->host = $oFromAccount->Domain()->SmtpSettings()->host; - $oSettings->port = (int) $oFromAccount->Domain()->SmtpSettings()->port; - $oSettings->type = $oFromAccount->Domain()->SmtpSettings()->type; - \SnappyMail\LOG::info(get_class($this),'Smtp config rewrite: '. $oSettings->host); - } - } - - /** - * @param \RainLoop\Model\Account $oAccount - * @param \MailSo\Smtp\SmtpClient $oSmtpClient - * @param \MailSo\Smtp\Settings $oSettings - */ - public function FilterSmtpCredentials(\RainLoop\Model\Account $oAccount, \MailSo\Smtp\SmtpClient $oSmtpClient, \MailSo\Smtp\Settings $oSettings) - { - if ( isset($this->aFromAccount[$oAccount->Email()]) ) { - $oFromAccount = $this->aFromAccount[$oAccount->Email()]; - unset($this->aFromAccount[$oAccount->Email()]); - $oSettings->useAuth = $oFromAccount->Domain()->SmtpSettings()->useAuth; - $oSettings->username = $oFromAccount->OutLogin(); - $oSettings->passphrase = $oFromAccount->IncPassword(); - \SnappyMail\LOG::info(get_class($this),'user/pwd rewrite: '. $oFromAccount->Email()); - } - } - - /** - * @return array - */ - protected function configMapping() : array - { - return array( - \RainLoop\Plugins\Property::NewInstance('from_adress_pattern')->SetLabel('From-Address pattern') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) - ->SetDescription('space as delimiter, wildcard supported.') - ->SetDefaultValue('user@example.com *@example2.com'), - \RainLoop\Plugins\Property::NewInstance('throw_notfound_exception')->SetLabel('Throw Exception, if from-adr is not found as account') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) - ->SetDescription('it is not possible to send eMails in this case, regardless of whether the smtp-server would do it') - ->SetDefaultValue(true) - ); - } - -} diff --git a/plugins/two-factor-auth/index.php b/plugins/two-factor-auth/index.php index 21b449daa..df3f959ac 100644 --- a/plugins/two-factor-auth/index.php +++ b/plugins/two-factor-auth/index.php @@ -1,16 +1,15 @@ removeBackupCodeFromTwoFactorInfo($oAccount, $sCode); + $this->removeBackupCodeFromTwoFactorInfo($oAccount->Email(), $sCode); } } @@ -111,7 +110,11 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin $sSecret = $this->TwoFactorAuthProvider($oAccount)->CreateSecret(); - $aCodes = \array_map(function(){return \rand(100000000, 900000000);}, \array_fill(0, 8, null)); + $aCodes = array(); + for ($iIndex = 9; $iIndex > 0; $iIndex--) + { + $aCodes[] = \rand(100000000, 900000000); + } $this->StorageProvider()->Put($oAccount, \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, @@ -120,7 +123,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin 'User' => $sEmail, 'Enable' => false, 'Secret' => $sSecret, - 'QRCode' => static::getQRCode($oAccount, $sSecret), + 'QRCode' => static::getQRCode($sEmail, $sSecret), 'BackupCodes' => \implode(' ', $aCodes) )) ); @@ -128,10 +131,10 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->jsonResponse(__FUNCTION__, $this->getTwoFactorInfo($oAccount)); } - private static function getQRCode(MainAccount $oAccount, string $secret) : string + private static function getQRCode(string $email, string $secret) : string { - $email = \rawurlencode($oAccount->Email()); -// $issuer = \rawurlencode(\RainLoop\Api::Config()->Get('webmail', 'title', 'SnappyMail')); + $email = \rawurlencode($email); +// $issuer = \rawurlencode(\RainLoop\API::Config()->Get('webmail', 'title', 'SnappyMail')); $QR = \SnappyMail\QRCode::getMinimumQRCode( // "otpauth://totp/{$issuer}:{$email}?secret={$secret}&issuer={$issuer}", "otpauth://totp/{$email}?secret={$secret}", @@ -151,7 +154,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin $aResult = $this->getTwoFactorInfo($oAccount); unset($aResult['BackupCodes']); - $aResult['QRCode'] = static::getQRCode($oAccount, $aResult['Secret']); + $aResult['QRCode'] = static::getQRCode($oAccount->Email(), $aResult['Secret']); return $this->jsonResponse(__FUNCTION__, $aResult); } @@ -164,17 +167,18 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->jsonResponse(__FUNCTION__, false); } - $oActions = $this->Manager()->Actions(); - if ($oActions->HasActionParam('EnableTwoFactor')) { - $sValue = $oActions->GetActionParam('EnableTwoFactor', ''); - $oActions->SettingsProvider()->Load($oAccount)->SetConf('EnableTwoFactor', !empty($sValue)); + $oSettings = $this->Manager()->Actions()->SettingsProvider()->Load($oAccount); + if ($this->Manager()->Actions()->HasActionParam('EnableTwoFactor')) { + $sValue = $this->GetActionParam('EnableTwoFactor', ''); + $oSettings->SetConf('EnableTwoFactor', !empty($sValue)); } $sEmail = $oAccount->Email(); $bResult = false; $mData = $this->getTwoFactorInfo($oAccount); - if (isset($mData['Secret'], $mData['BackupCodes'])) { + if (isset($mData['Secret'], $mData['BackupCodes'])) + { $bResult = $this->StorageProvider()->Put($oAccount, \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'two_factor', @@ -236,7 +240,7 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin return $this->Manager()->Actions()->StorageProvider(); } - private $oTwoFactorAuthProvider = null; + private $oTwoFactorAuthProvider; protected function TwoFactorAuthProvider(MainAccount $oAccount) : ?TwoFactorAuthInterface { if (!$this->oTwoFactorAuthProvider) { @@ -261,7 +265,8 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin 'BackupCodes' => '' ); - if (!empty($sEmail)) { + if (!empty($sEmail)) + { $aResult['User'] = $sEmail; $sData = $this->StorageProvider()->Get($oAccount, @@ -269,7 +274,8 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin 'two_factor' ); - if ($sData) { + if ($sData) + { $mData = static::DecodeKeyValues($sData); } } @@ -282,15 +288,18 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin $aResult['Enable'] = isset($mData['Enable']) ? !!$mData['Enable'] : false; $aResult['Secret'] = $mData['Secret']; $aResult['BackupCodes'] = $mData['BackupCodes']; - $aResult['QRCode'] = static::getQRCode($oAccount, $mData['Secret']); + $aResult['QRCode'] = static::getQRCode($oAccount->Email(), $mData['Secret']); } - if ($bRemoveSecret) { - if (isset($aResult['Secret'])) { + if ($bRemoveSecret) + { + if (isset($aResult['Secret'])) + { unset($aResult['Secret']); } - if (isset($aResult['BackupCodes'])) { + if (isset($aResult['BackupCodes'])) + { unset($aResult['BackupCodes']); } } @@ -300,7 +309,8 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin protected function removeBackupCodeFromTwoFactorInfo(MainAccount $oAccount, string $sCode) : bool { - if (!$oAccount || empty($sCode)) { + if (!$oAccount || empty($sCode)) + { return false; } @@ -309,10 +319,12 @@ class TwoFactorAuthPlugin extends \RainLoop\Plugins\AbstractPlugin 'two_factor' ); - if ($sData) { + if ($sData) + { $mData = static::DecodeKeyValues($sData); - if (!empty($mData['BackupCodes'])) { + if (!empty($mData['BackupCodes'])) + { $sBackupCodes = \preg_replace('/[^\d]+/', ' ', ' '.$mData['BackupCodes'].' '); $sBackupCodes = \str_replace(' '.$sCode.' ', '', $sBackupCodes); diff --git a/plugins/two-factor-auth/js/TwoFactorAuthLogin.js b/plugins/two-factor-auth/js/TwoFactorAuthLogin.js index aa71747c2..d4e4c61e5 100644 --- a/plugins/two-factor-auth/js/TwoFactorAuthLogin.js +++ b/plugins/two-factor-auth/js/TwoFactorAuthLogin.js @@ -17,7 +17,7 @@ + '⏱' + '' + '')); @@ -27,7 +27,7 @@ // https://github.com/the-djmaze/snappymail/issues/349 addEventListener('sm-show-screen', e => { - if (!e.detail.startsWith('settings') && rl.settings.get('SetupTwoFactor')) { + if ('settings' !== e.detail && rl.settings.get('SetupTwoFactor')) { e.preventDefault(); forceTOTP(); } diff --git a/plugins/two-factor-auth/langs/cs.ini b/plugins/two-factor-auth/langs/cs-CZ.ini similarity index 93% rename from plugins/two-factor-auth/langs/cs.ini rename to plugins/two-factor-auth/langs/cs-CZ.ini index 2324476fc..bcffceb9c 100644 --- a/plugins/two-factor-auth/langs/cs.ini +++ b/plugins/two-factor-auth/langs/cs-CZ.ini @@ -12,8 +12,8 @@ BUTTON_SHOW_SECRET = "Show Secret" BUTTON_HIDE_SECRET = "Hide Secret" TWO_FACTOR_SECRET_CONFIGURED_DESC = "Configured" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Not configured" -TWO_FACTOR_SECRET_DESC = "Import this info into your Google Authenticator client (or other TOTP client) using the provided QR code below or by entering the code manually." -TWO_FACTOR_BACKUP_CODES_DESC = "If you can't receive codes via Google Authenticator (or other TOTP client), you can use backup codes to sign in. After you’ve used a backup code to sign in, it will become inactive." +TWO_FACTOR_SECRET_DESC = "Import this info into your Google Authenticator client (or other TOTP client) using the provided QR code below or by entering the code manually.\n" +TWO_FACTOR_BACKUP_CODES_DESC = "If you can't receive codes via Google Authenticator (or other TOTP client), you can use backup codes to sign in. After you’ve used a backup code to sign in, it will become inactive.\n" TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "You can't change this setting before test." TITLE_TEST_CODE = "2-Step verification test" LABEL_CODE = "Code" diff --git a/plugins/two-factor-auth/langs/de.ini b/plugins/two-factor-auth/langs/de_DE.ini similarity index 100% rename from plugins/two-factor-auth/langs/de.ini rename to plugins/two-factor-auth/langs/de_DE.ini diff --git a/plugins/two-factor-auth/langs/en.ini b/plugins/two-factor-auth/langs/en.ini index 003a50a31..fb94a5e56 100644 --- a/plugins/two-factor-auth/langs/en.ini +++ b/plugins/two-factor-auth/langs/en.ini @@ -12,8 +12,8 @@ BUTTON_SHOW_SECRET = "Show Secret" BUTTON_HIDE_SECRET = "Hide Secret" TWO_FACTOR_SECRET_CONFIGURED_DESC = "Configured" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Not configured" -TWO_FACTOR_SECRET_DESC = "Import this info into your Google Authenticator client (or other TOTP client) using the provided QR code below or by entering the code manually." -TWO_FACTOR_BACKUP_CODES_DESC = "If you can't receive codes via Google Authenticator (or other TOTP client), you can use backup codes to sign in. After you’ve used a backup code to sign in, it will become inactive." +TWO_FACTOR_SECRET_DESC = "Import this info into your Google Authenticator client (or other TOTP client) using the provided QR code below or by entering the code manually.\n" +TWO_FACTOR_BACKUP_CODES_DESC = "If you can't receive codes via Google Authenticator (or other TOTP client), you can use backup codes to sign in. After you’ve used a backup code to sign in, it will become inactive.\n" TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "You can't change this setting before test." TITLE_TEST_CODE = "2-Step verification test" LABEL_CODE = "Code" diff --git a/plugins/two-factor-auth/langs/es.ini b/plugins/two-factor-auth/langs/es_ES.ini similarity index 100% rename from plugins/two-factor-auth/langs/es.ini rename to plugins/two-factor-auth/langs/es_ES.ini diff --git a/plugins/two-factor-auth/langs/fr.ini b/plugins/two-factor-auth/langs/fr_FR.ini similarity index 100% rename from plugins/two-factor-auth/langs/fr.ini rename to plugins/two-factor-auth/langs/fr_FR.ini diff --git a/plugins/two-factor-auth/langs/hu.ini b/plugins/two-factor-auth/langs/hu-HU.ini similarity index 90% rename from plugins/two-factor-auth/langs/hu.ini rename to plugins/two-factor-auth/langs/hu-HU.ini index a847b1be4..c97b8b192 100644 --- a/plugins/two-factor-auth/langs/hu.ini +++ b/plugins/two-factor-auth/langs/hu-HU.ini @@ -12,8 +12,8 @@ BUTTON_SHOW_SECRET = "Titok megjelenítése" BUTTON_HIDE_SECRET = "Titok elrejtése" TWO_FACTOR_SECRET_CONFIGURED_DESC = "Beállítva" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Nincs beállítva" -TWO_FACTOR_SECRET_DESC = "Importáld ezt az infót a Google Authenticator kliensedbe (vagy más TOTP kliensbe) az alábbi QR kód használatával vagy a kód manuális megadatásával." -TWO_FACTOR_BACKUP_CODES_DESC = "Ha nem kapod meg a kódokat a Google Authenticator kliensből (vagy más TOTP kliensből), akkor a bejelentkezéshez használhatod a biztonsági kódot. A biztonsági kód használata után inaktívvá válik." +TWO_FACTOR_SECRET_DESC = "Importáld ezt az infót a Google Authenticator kliensedbe (vagy más TOTP kliensbe) az alábbi QR kód használatával vagy a kód manuális megadatásával.\n" +TWO_FACTOR_BACKUP_CODES_DESC = "Ha nem kapod meg a kódokat a Google Authenticator kliensből (vagy más TOTP kliensből), akkor a bejelentkezéshez használhatod a biztonsági kódot. A biztonsági kód használata után inaktívvá válik.\n" TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "Tesztelés nélkül nem lehet megváltoztatni ezt a beállítást." TITLE_TEST_CODE = "2-lépéses hitelesítés teszt" LABEL_CODE = "Kód" diff --git a/plugins/two-factor-auth/langs/it.ini b/plugins/two-factor-auth/langs/it_IT.ini similarity index 94% rename from plugins/two-factor-auth/langs/it.ini rename to plugins/two-factor-auth/langs/it_IT.ini index fbd44f45d..1b1faccac 100644 --- a/plugins/two-factor-auth/langs/it.ini +++ b/plugins/two-factor-auth/langs/it_IT.ini @@ -12,8 +12,8 @@ BUTTON_SHOW_SECRET = "Mostra la chiave segreta" BUTTON_HIDE_SECRET = "Nascondi la chiave segreta" TWO_FACTOR_SECRET_CONFIGURED_DESC = "Configurato" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Non configurato" -TWO_FACTOR_SECRET_DESC = "Importa queste informazioni nella tua app Google Authenticator (o un altro programma per l'autenticazione a due fattori) utilizzando il codice QR fornito qui sotto o inserendo il codice manualmente." -TWO_FACTOR_BACKUP_CODES_DESC = "Se non riesci a ricevere i codici tramite Google Authenticator (o un altro programma per l'autenticazione a due fattori), puoi utilizzare i codici di backup per accedere. Dopo che hai utilizzato un codice di backup per accedere, diventerà inattivo." +TWO_FACTOR_SECRET_DESC = "Importa queste informazioni nella tua app Google Authenticator (o un altro programma per l'autenticazione a due fattori) utilizzando il codice QR fornito qui sotto o inserendo il codice manualmente.\n" +TWO_FACTOR_BACKUP_CODES_DESC = "Se non riesci a ricevere i codici tramite Google Authenticator (o un altro programma per l'autenticazione a due fattori), puoi utilizzare i codici di backup per accedere. Dopo che hai utilizzato un codice di backup per accedere, diventerà inattivo.\n" TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "Non puoi modificare questa impostazione prima del test." TITLE_TEST_CODE = "Test di verifica a 2 fattori" LABEL_CODE = "Codice" diff --git a/plugins/two-factor-auth/langs/nl.ini b/plugins/two-factor-auth/langs/nl_NL.ini similarity index 100% rename from plugins/two-factor-auth/langs/nl.ini rename to plugins/two-factor-auth/langs/nl_NL.ini diff --git a/plugins/two-factor-auth/langs/pl.ini b/plugins/two-factor-auth/langs/pl.ini deleted file mode 100644 index 2e00f7683..000000000 --- a/plugins/two-factor-auth/langs/pl.ini +++ /dev/null @@ -1,20 +0,0 @@ -[PLUGIN_2FA] -LEGEND_TWO_FACTOR_AUTH = "2FA (TOTP)" -LABEL_ENABLE_TWO_FACTOR = "Włącz weryfikację 2-stopniową" -LABEL_TWO_FACTOR_USER = "Użytkownik" -LABEL_TWO_FACTOR_STATUS = "Status" -LABEL_TWO_FACTOR_SECRET = "Twój sekretny klucz" -LABEL_TWO_FACTOR_BACKUP_CODES = "Kody zapasowe" -BUTTON_CREATE = "Utwórz sekretny klucz" -BUTTON_ACTIVATE = "Aktywuj" -LINK_TEST = "Testuj" -BUTTON_SHOW_SECRET = "Pokaż Twój sekretny klucz" -BUTTON_HIDE_SECRET = "Ukryj klucz" -TWO_FACTOR_SECRET_CONFIGURED_DESC = "Skonfigurowano" -TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Nieskonfigurowano" -TWO_FACTOR_SECRET_DESC = "Zaimportuj tę infomację do aplikacji Google Authenticator (lub innego klienta TOTP) używając kodu QR poniżej lub wpisz sekretny klucz ręcznie." -TWO_FACTOR_BACKUP_CODES_DESC = "Jeśli nie możesz uzyskać kodów poprzez aplikację Google Authenticator (lub innego klienta TOTP), możesz użyć kodów zapasowych aby się zalogować. Po użyciu kodu zapasowego do zalogowania, stanie się on nieaktywny." -TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "Nie możesz zmienić tego ustawienia przed testem." -TITLE_TEST_CODE = "Test weryfikacji 2-stopniowej" -LABEL_CODE = "Kod" -LABEL_TWO_FACTOR_CODE = "Kod weryfikacyjny" diff --git a/plugins/two-factor-auth/langs/sv.ini b/plugins/two-factor-auth/langs/sv-SE.ini similarity index 100% rename from plugins/two-factor-auth/langs/sv.ini rename to plugins/two-factor-auth/langs/sv-SE.ini diff --git a/plugins/two-factor-auth/langs/uk.ini b/plugins/two-factor-auth/langs/uk.ini deleted file mode 100644 index 5f09cfb09..000000000 --- a/plugins/two-factor-auth/langs/uk.ini +++ /dev/null @@ -1,20 +0,0 @@ -[PLUGIN_2FA] -LEGEND_TWO_FACTOR_AUTH = "2-етапна перевірка (TOTP)" -LABEL_ENABLE_TWO_FACTOR = "Увімкнути 2-етапну перевірку" -LABEL_TWO_FACTOR_USER = "Ім'я користувача" -LABEL_TWO_FACTOR_STATUS = "Статус" -LABEL_TWO_FACTOR_SECRET = "Ключ" -LABEL_TWO_FACTOR_BACKUP_CODES = "Резервні коди" -BUTTON_CREATE = "Create a secret" -BUTTON_ACTIVATE = "Activate" -LINK_TEST = "Тестувати" -BUTTON_SHOW_SECRET = "Показати ключ" -BUTTON_HIDE_SECRET = "Приховати ключ" -TWO_FACTOR_SECRET_CONFIGURED_DESC = "Налаштовано" -TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "Не налаштовано" -TWO_FACTOR_SECRET_DESC = "Імпортуйте цю інформацію у свій клієнт Google Authenticator (або інший клієнт TOTP), використовуючи наданий нижче QR-код або ввівши код вручну" -TWO_FACTOR_BACKUP_CODES_DESC = "Якщо ви не можете отримати код через Google Authenticator (або інший клієнт TOTP), ви можете скористатися резервними кодами для входу. Після того, як ви використаєте резервний код для входу, він стане неактивним. Закреслюйте його" -TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "Ви не можете змінити це налаштування перед тестуванням." -TITLE_TEST_CODE = "Тест 2-етапної перевірки" -LABEL_CODE = "Код" -LABEL_TWO_FACTOR_CODE = "Код підтвердження" diff --git a/plugins/two-factor-auth/langs/zh.ini b/plugins/two-factor-auth/langs/zh_CN.ini similarity index 92% rename from plugins/two-factor-auth/langs/zh.ini rename to plugins/two-factor-auth/langs/zh_CN.ini index 87c530e92..56091d914 100644 --- a/plugins/two-factor-auth/langs/zh.ini +++ b/plugins/two-factor-auth/langs/zh_CN.ini @@ -12,8 +12,8 @@ BUTTON_SHOW_SECRET = "显示密钥" BUTTON_HIDE_SECRET = "隐藏密钥" TWO_FACTOR_SECRET_CONFIGURED_DESC = "已设置" TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC = "未设置" -TWO_FACTOR_SECRET_DESC = "将下面的信息导入 Google Authenticator (或其他 TOTP 客户端)。 扫描下面的二维码或手动输入密钥。" -TWO_FACTOR_BACKUP_CODES_DESC = "如果你无法从验证器获取验证码,你可以使用备用代码登录。 当你使用过某一个备用代码后,它将会失效。" +TWO_FACTOR_SECRET_DESC = "将下面的信息导入 Google Authenticator (或其他 TOTP 客户端)。 扫描下面的二维码或手动输入密钥。\n" +TWO_FACTOR_BACKUP_CODES_DESC = "如果你无法从验证器获取验证码,你可以使用备用代码登录。 当你使用过某一个备用代码后,它将会失效。\n" TWO_FACTOR_SECRET_TEST_BEFORE_DESC = "完成测试前你无法更改此设置。" TITLE_TEST_CODE = "两步验证测试" LABEL_CODE = "代码" diff --git a/plugins/two-factor-auth/templates/TwoFactorAuthSettings.html b/plugins/two-factor-auth/templates/TwoFactorAuthSettings.html index 95569afd0..df5a40476 100644 --- a/plugins/two-factor-auth/templates/TwoFactorAuthSettings.html +++ b/plugins/two-factor-auth/templates/TwoFactorAuthSettings.html @@ -47,7 +47,7 @@

-

+				

 			
 		
 		
diff --git a/plugins/video-on-login-screen/LICENSE b/plugins/video-on-login-screen/LICENSE deleted file mode 100755 index 44b915a0c..000000000 --- a/plugins/video-on-login-screen/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2023 SnappyMail Team - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/video-on-login-screen/README b/plugins/video-on-login-screen/README deleted file mode 100755 index ec8c5bbdb..000000000 --- a/plugins/video-on-login-screen/README +++ /dev/null @@ -1 +0,0 @@ -Fullscreen background video on login screen. \ No newline at end of file diff --git a/plugins/video-on-login-screen/VERSION b/plugins/video-on-login-screen/VERSION deleted file mode 100755 index b123147e2..000000000 --- a/plugins/video-on-login-screen/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.1 \ No newline at end of file diff --git a/plugins/video-on-login-screen/index.php b/plugins/video-on-login-screen/index.php deleted file mode 100755 index 26f29b953..000000000 --- a/plugins/video-on-login-screen/index.php +++ /dev/null @@ -1,44 +0,0 @@ -addJs('js/video-on-login.js'); - $this->addHook('main.content-security-policy', 'ContentSecurityPolicy'); - } - - /** - * @return array - */ - protected function configMapping() : array - { - return array( - \RainLoop\Plugins\Property::NewInstance('mp4_file')->SetLabel('Url to a mp4 file') - ->SetPlaceholder('http://') - ->SetAllowedInJs(true) - ->SetDefaultValue(''), - \RainLoop\Plugins\Property::NewInstance('playback_rate')->SetLabel('Playback rate') - ->SetAllowedInJs(true) - ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) - ->SetDefaultValue(array('100%', '25%', '50%', '75%', '125%', '150%', '200%')), - ); - } - - public function ContentSecurityPolicy(\SnappyMail\HTTP\CSP $CSP) - { - $vSource = $this->Config()->Get('plugin', 'mp4_file', 'self'); - $CSP->add('media-src', $vSource); - } -} diff --git a/plugins/video-on-login-screen/js/video-on-login.js b/plugins/video-on-login-screen/js/video-on-login.js deleted file mode 100755 index d5d497a62..000000000 --- a/plugins/video-on-login-screen/js/video-on-login.js +++ /dev/null @@ -1,107 +0,0 @@ -(rl => { - - rl && addEventListener('rl-view-model', e => { - const id = e.detail.viewModelTemplateID; - if (e.detail && ('AdminLogin' === id || 'Login' === id)) { - let - nId = null, - script; - - let - iRate = 1, - sRate = window.rl.pluginSettingsGet('video-on-login-screen', 'playback_rate') - ; - - switch (sRate) - { - case '25%': - iRate = 0.25; - break; - case '50%': - iRate = 0.5; - break; - case '75%': - iRate = 0.75; - break; - case '125%': - iRate = 1.25; - break; - case '150%': - iRate = 1.5; - break; - case '200%': - iRate = 2; - break; - } - const - mode = 'Login' === id ? 'user' : 'admin', - - doc = document, - loginContainer = doc.querySelectorAll('#V-Login #V-AdminLogin'), - container = doc.querySelector('#rl-content'), - - ShowVideo = () => { - if (loginContainer) { - var stEl = doc.createElement('style'); - stEl.innerHTML = - ` - #video-el { - z-index: -1; - overflow: hidden; - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; - height: 100vh; - width: 100%; - object-fit: cover; - } - ` - var ref = doc.querySelector('script'); - ref.parentNode.insertBefore(stEl, ref); - - const oEl = doc.createElement('div'); - oEl.className = 'video-div'; - const vEl = doc.createElement('video'); - vEl.setAttribute('loop', true); - vEl.setAttribute('playsinline', ''); - vEl.setAttribute('muted', ''); - vEl.setAttribute('autoplay', ''); - vEl.muted = true; - vEl.setAttribute('playbackRate', iRate); - vEl.setAttribute('id', 'video-el'); - oEl.appendChild(vEl); - const sEl = doc.createElement('source'); - sEl.setAttribute('src', rl.pluginSettingsGet('video-on-login-screen', 'mp4_file')); - sEl.setAttribute('type', 'video/mp4'); - vEl.appendChild(sEl); - - container.before(oEl); - - } - }, - - DestroyVideo = () => { - const vEl = doc.querySelector('#video-el'); - if (vEl) { - vEl.parentElement.removeChild(vEl); - } - }; - - window.ShowVideo = ShowVideo; - - window.DestroyVideo = DestroyVideo; - - ShowVideo(); - - addEventListener(`sm-${mode}-login-response`, e => { - if (!e.detail.error) { - DestroyVideo(); - } - }); - } - }); - -})(window.rl); diff --git a/plugins/view-ics/LICENSE b/plugins/view-ics/LICENSE deleted file mode 100644 index 9e5e56cdd..000000000 --- a/plugins/view-ics/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 SnappyMail - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/view-ics/ical.js b/plugins/view-ics/ical.js deleted file mode 100644 index 9813ebe7c..000000000 --- a/plugins/view-ics/ical.js +++ /dev/null @@ -1,869 +0,0 @@ -// https://www.rfc-editor.org/rfc/rfc5545 - -(rl => { - - const - paramRegEx = /;([a-zA-Z0-9-]+)=([^";:,]*|"[^"]*")/g, - // eslint-disable-next-line max-len - dateRegEx = /(?[0-9]{4})(?[0-9]{2})(?[0-9]{2})T(?[0-9]{2})(?[0-9]{2})(?[0-9]{2})(?Z?)/, - parseDate = (str, tz) => { - let parts = dateRegEx.exec(str)?.groups, - options = {dateStyle: 'long', timeStyle: 'short'}, - date = (parts ? new Date( - parseInt(parts.year, 10), - parseInt(parts.month, 10) - 1, - parseInt(parts.day, 10), - parseInt(parts.hour, 10), - parseInt(parts.minute, 10), - parseInt(parts.second, 10) - ) : new Date(str)); - tz && (options.timeZone = windowsVTIMEZONEs[tz] || tz); - try { - return date.format(options); - } catch (e) { - console.error(e); - if (options.timeZone) { - options.timeZone = undefined; - return date.format(options); - } - } - }; - - class Property extends String - { - constructor(name, value, params) { - super(value); - this.name = name; -// this.value = value; - this.params = {}; - if (params) { - for (const param of params.matchAll(paramRegEx)) { - if (param[2]) { - this.params[param[1]] = param[2].replace(/^"|"$/); - } - } - } - } -/* - includes(...params) { - return this.value.includes(...params); - } - replace(...params) { - return this.value.replace(...params); - } - toString() { - return this.value; - } -*/ - static fromString(data) { - // Parse component property 'name *(";" param ) ":" value' - const match = data.match(/^([a-zA-Z0-9-]+)((?:;[a-zA-Z0-9-]+=(?:[^";:,]*|"[^"]*"))*):(.+)$/); - return match && new Property(match[1], match[3], match[2]); - } - } - - rl.ICS = { - - parseDate: parseDate, - - parseEvent(text) { - let VEVENT, - VALARM, - multiple = ['ATTACH','ATTENDEE','CATEGORIES','COMMENT','CONTACT','EXDATE', - 'EXRULE','RSTATUS','RELATED','RESOURCES','RDATE','RRULE'], - lines = text.split(/\r?\n/), - i = lines.length; - while (i--) { - let line = lines[i], prop; - if (VEVENT) { - while (line.startsWith(' ') && i--) { - line = lines[i] + line.slice(1); - } - if (line.startsWith('END:VALARM')) { - // Start parsing Alarm Component - VALARM = {}; - continue; - } else if (line.startsWith('BEGIN:VALARM')) { - // End parsing Alarm Component - VEVENT.VALARM || (VEVENT.VALARM = []); - VEVENT.VALARM.push(VALARM); - VALARM = null; - continue; - } else if (line.startsWith('BEGIN:VEVENT')) { - // End parsing - break; - } - prop = Property.fromString(line); - if (prop) { - if (VALARM) { - VALARM[prop.name] = prop; - } else if (multiple.includes(prop.name) || 'X-' == prop.name.slice(0,2)) { - VEVENT[prop.name] || (VEVENT[prop.name] = []); - VEVENT[prop.name].push(prop); - } else { - if ('DTSTART' === prop.name || 'DTEND' === prop.name) { - prop = parseDate(prop, prop.params.TZID); - } - VEVENT[prop.name] = prop; - } - } - } else if (line.startsWith('END:VEVENT')) { - // Start parsing Event Component - VEVENT = {}; - } - } -// METHOD:REPLY || METHOD:REQUEST - if (VEVENT) { - VEVENT.rawText = text; - VEVENT.isCancelled = () => VEVENT.STATUS?.includes('CANCELLED'); - VEVENT.isConfirmed = () => VEVENT.STATUS?.includes('CONFIRMED'); - VEVENT.shouldReply = () => VEVENT.METHOD?.includes('REPLY'); - console.dir({ - VEVENT, - isCancelled: VEVENT.isCancelled(), - shouldReply: VEVENT.shouldReply() - }); - } - - return VEVENT; - } - }; - - // Microsoft Windows timezones - // Subset from https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/windowsZones.json - const windowsVTIMEZONEs = { - // Windows : [IANA...] - "Afghanistan Standard Time": [ - "Asia/Kabul" - ], - "Alaskan Standard Time": [ - "America/Anchorage"/*, - "America/Juneau", - "America/Metlakatla", - "America/Nome", - "America/Sitka", - "America/Yakutat"*/ - ], - "Aleutian Standard Time": [ - "America/Adak" - ], - "Altai Standard Time": [ - "Asia/Barnaul" - ], - "Arab Standard Time": [ - "Asia/Aden"/*, - "Asia/Bahrain", - "Asia/Kuwait", - "Asia/Qatar", - "Asia/Riyadh" - */], - "Arabian Standard Time": [ - "Asia/Dubai"/*, - "Asia/Muscat", - "Etc/GMT-4" - */], - "Arabic Standard Time": [ - "Asia/Baghdad" - ], - "Argentina Standard Time": [ - "America/Argentina/La_Rioja"/*, - "America/Argentina/Rio_Gallegos", - "America/Argentina/Salta", - "America/Argentina/San_Juan", - "America/Argentina/San_Luis", - "America/Argentina/Tucuman", - "America/Argentina/Ushuaia", - "America/Buenos_Aires", - "America/Catamarca", - "America/Cordoba", - "America/Jujuy", - "America/Mendoza" - */], - "Astrakhan Standard Time": [ - "Europe/Astrakhan"/*, - "Europe/Ulyanovsk" - */], - "Atlantic Standard Time": [ - "America/Glace_Bay"/*, - "America/Goose_Bay", - "America/Halifax", - "America/Moncton", - "America/Thule", - "Atlantic/Bermuda" - */], - "AUS Central Standard Time": [ - "Australia/Darwin" - ], - "Aus Central W. Standard Time": [ - "Australia/Eucla" - ], - "AUS Eastern Standard Time": [ - "Australia/Melbourne"/*, - "Australia/Sydney" - */], - "Azerbaijan Standard Time": [ - "Asia/Baku" - ], - "Azores Standard Time": [ - "America/Scoresbysund"/*, - "Atlantic/Azores" - */], - "Bahia Standard Time": [ - "America/Bahia" - ], - "Bangladesh Standard Time": [ - "Asia/Dhaka"/*, - "Asia/Thimphu" - */], - "Belarus Standard Time": [ - "Europe/Minsk" - ], - "Bougainville Standard Time": [ - "Pacific/Bougainville" - ], - "Canada Central Standard Time": [ - "America/Regina"/*, - "America/Swift_Current" - */], - "Cape Verde Standard Time": [ - "Atlantic/Cape_Verde"/*, - "Etc/GMT+1" - */], - "Caucasus Standard Time": [ - "Asia/Yerevan" - ], - "Cen. Australia Standard Time": [ - "Australia/Adelaide"/*, - "Australia/Broken_Hill" - */], - "Central America Standard Time": [ - "America/Belize"/*, - "America/Costa_Rica", - "America/El_Salvador", - "America/Guatemala", - "America/Managua", - "America/Tegucigalpa", - "Pacific/Galapagos", - "Etc/GMT+6" - */], - "Central Asia Standard Time": [ - "Asia/Almaty"/*, - "Asia/Bishkek", - "Asia/Qostanay", - "Asia/Urumqi", - "Indian/Chagos", - "Antarctica/Vostok", - "Etc/GMT-6" - */], - "Central Brazilian Standard Time": [ - "America/Campo_Grande"/*, - "America/Cuiaba" - */], - "Central Europe Standard Time": [ - "Europe/Belgrade"/*, - "Europe/Bratislava", - "Europe/Budapest", - "Europe/Ljubljana", - "Europe/Podgorica", - "Europe/Prague", - "Europe/Tirane" - */], - "Central European Standard Time": [ - "Europe/Sarajevo"/*, - "Europe/Skopje", - "Europe/Warsaw", - "Europe/Zagreb" - */], - "Central Pacific Standard Time": [ - "Pacific/Efate"/*, - "Pacific/Guadalcanal", - "Pacific/Noumea", - "Pacific/Ponape Pacific/Kosrae", - "Antarctica/Macquarie", - "Etc/GMT-11" - */], - "Central Standard Time": [ - "America/Chicago"/*, - "America/Indiana/Knox", - "America/Indiana/Tell_City", - "America/Matamoros", - "America/Menominee", - "America/North_Dakota/Beulah", - "America/North_Dakota/Center", - "America/North_Dakota/New_Salem", - "America/Rainy_River", - "America/Rankin_Inlet", - "America/Resolute", - "America/Winnipeg", - "CST6CDT" - */], - "Central Standard Time (Mexico)": [ - "America/Bahia_Banderas"/*, - "America/Merida", - "America/Mexico_City", - "America/Monterrey" - */], - "Chatham Islands Standard Time": [ - "Pacific/Chatham" - ], - "China Standard Time": [ - "Asia/Hong_Kong"/*, - "Asia/Macau", - "Asia/Shanghai" - */], - "Cuba Standard Time": [ - "America/Havana" - ], - "Dateline Standard Time": [ - "Etc/GMT+12" - ], - "E. Africa Standard Time": [ - "Africa/Addis_Ababa"/*, - "Africa/Asmera", - "Africa/Dar_es_Salaam", - "Africa/Djibouti", - "Africa/Juba", - "Africa/Kampala", - "Africa/Mogadishu", - "Africa/Nairobi", - "Indian/Antananarivo", - "Indian/Comoro", - "Indian/Mayotte", - "Antarctica/Syowa", - "Etc/GMT-3" - */], - "E. Australia Standard Time": [ - "Australia/Brisbane"/*, - "Australia/Lindeman" - */], - "E. Europe Standard Time": [ - "Europe/Chisinau" - ], - "E. South America Standard Time": [ - "America/Sao_Paulo" - ], - "Easter Island Standard Time": [ - "Pacific/Easter" - ], - "Eastern Standard Time": [ - "America/Detroit"/*, - "America/Indiana/Petersburg", - "America/Indiana/Vincennes", - "America/Indiana/Winamac", - "America/Iqaluit", - "America/Kentucky/Monticello", - "America/Louisville", - "America/Montreal", - "America/Nassau", - "America/New_York", - "America/Nipigon", - "America/Pangnirtung", - "America/Thunder_Bay", - "America/Toronto", - "EST5EDT" - */], - "Eastern Standard Time (Mexico)": [ - "America/Cancun" - ], - "Egypt Standard Time": [ - "Africa/Cairo" - ], - "Ekaterinburg Standard Time": [ - "Asia/Yekaterinburg" - ], - "Fiji Standard Time": [ - "Pacific/Fiji" - ], - "FLE Standard Time": [ - "Europe/Helsinki"/*, - "Europe/Kiev", - "Europe/Mariehamn", - "Europe/Riga", - "Europe/Sofia", - "Europe/Tallinn", - "Europe/Uzhgorod", - "Europe/Vilnius", - "Europe/Zaporozhye" - */], - "Georgian Standard Time": [ - "Asia/Tbilisi" - ], - "GMT Standard Time": [ - "Atlantic/Canary"/*, - "Atlantic/Faeroe", - "Atlantic/Madeira", - "Europe/Dublin", - "Europe/Guernsey", - "Europe/Isle_of_Man", - "Europe/Jersey", - "Europe/Lisbon", - "Europe/London" - */], - "Greenland Standard Time": [ - "America/Godthab" - ], - "Greenwich Standard Time": [ - "Africa/Abidjan"/*, - "Africa/Accra", - "Africa/Bamako", - "Africa/Banjul", - "Africa/Bissau", - "Africa/Conakry", - "Africa/Dakar", - "Africa/Freetown", - "Africa/Lome", - "Africa/Monrovia", - "Africa/Nouakchott", - "Africa/Ouagadougou", - "Atlantic/Reykjavik", - "Atlantic/St_Helena" - */], - "GTB Standard Time": [ - "Asia/Nicosia"/*, - "Asia/Famagusta", - "Europe/Athens", - "Europe/Bucharest" - */], - "Haiti Standard Time": [ - "America/Port-au-Prince" - ], - "Hawaiian Standard Time": [ - "Pacific/Honolulu"/*, - "Pacific/Johnston", - "Pacific/Rarotonga", - "Pacific/Tahiti", - "Etc/GMT+10" - */], - "India Standard Time": [ - "Asia/Calcutta" - ], - "Iran Standard Time": [ - "Asia/Tehran" - ], - "Israel Standard Time": [ - "Asia/Jerusalem" - ], - "Jordan Standard Time": [ - "Asia/Amman" - ], - "Kaliningrad Standard Time": [ - "Europe/Kaliningrad" - ], - "Korea Standard Time": [ - "Asia/Seoul" - ], - "Libya Standard Time": [ - "Africa/Tripoli" - ], - "Line Islands Standard Time": [ - "Pacific/Kiritimati"/*, - "Etc/GMT-14" - */], - "Lord Howe Standard Time": [ - "Australia/Lord_Howe" - ], - "Magadan Standard Time": [ - "Asia/Magadan" - ], - "Magallanes Standard Time": [ - "America/Punta_Arenas" - ], - "Marquesas Standard Time": [ - "Pacific/Marquesas" - ], - "Mauritius Standard Time": [ - "Indian/Mauritius"/*, - "Indian/Mahe", - "Indian/Reunion" - */], - "Middle East Standard Time": [ - "Asia/Beirut" - ], - "Montevideo Standard Time": [ - "America/Montevideo" - ], - "Morocco Standard Time": [ - "Africa/Casablanca"/*, - "Africa/El_Aaiun" - */], - "Mountain Standard Time": [ - "America/Boise"/*, - "America/Cambridge_Bay", - "America/Denver", - "America/Edmonton", - "America/Inuvik", - "America/Ojinaga", - "America/Yellowknife", - "MST7MDT" - */], - "Mountain Standard Time (Mexico)": [ - "America/Chihuahua"/*, - "America/Mazatlan" - */], - "Myanmar Standard Time": [ - "Asia/Rangoon"/*, - "Indian/Cocos" - */], - "N. Central Asia Standard Time": [ - "Asia/Novosibirsk" - ], - "Namibia Standard Time": [ - "Africa/Windhoek" - ], - "Nepal Standard Time": [ - "Asia/Katmandu" - ], - "New Zealand Standard Time": [ - "Pacific/Auckland"/*, - "Antarctica/McMurdo" - */], - "Newfoundland Standard Time": [ - "America/St_Johns" - ], - "Norfolk Standard Time": [ - "Pacific/Norfolk" - ], - "North Asia East Standard Time": [ - "Asia/Irkutsk" - ], - "North Asia Standard Time": [ - "Asia/Krasnoyarsk"/*, - "Asia/Novokuznetsk" - */], - "North Korea Standard Time": [ - "Asia/Pyongyang" - ], - "Omsk Standard Time": [ - "Asia/Omsk" - ], - "Pacific SA Standard Time": [ - "America/Santiago" - ], - "Pacific Standard Time": [ - "America/Los_Angeles"/*, - "America/Dawson", - "America/Vancouver", - "America/Whitehorse", - "PST8PDT" - */], - "Pacific Standard Time (Mexico)": [ - "America/Tijuana"/*, - "America/Santa_Isabel" - */], - "Pakistan Standard Time": [ - "Asia/Karachi" - ], - "Paraguay Standard Time": [ - "America/Asuncion" - ], - "Qyzylorda Standard Time": [ - "Asia/Qyzylorda" - ], - "Romance Standard Time": [ - "Europe/Paris"/*, - "Europe/Brussels", - "Europe/Copenhagen", - "Europe/Madrid", - "Africa/Ceuta" - */], - "Russia Time Zone 3": [ - "Europe/Samara" - ], - "Russia Time Zone 10": [ - "Asia/Srednekolymsk" - ], - "Russia Time Zone 11": [ - "Asia/Kamchatka"/*, - "Asia/Anadyr" - */], - "Russian Standard Time": [ - "Europe/Moscow"/*, - "Europe/Kirov", - "Europe/Simferopol" - */], - "SA Eastern Standard Time": [ - "America/Belem"/*, - "America/Cayenne", - "America/Fortaleza", - "America/Maceio", - "America/Paramaribo", - "America/Recife", - "America/Santarem", - "Atlantic/Stanley", - "Antarctica/Palmer", - "Antarctica/Rothera", - "Etc/GMT+3" - */], - "SA Pacific Standard Time": [ - "America/Bogota"/*, - "America/Cayman", - "America/Coral_Harbour", - "America/Eirunepe", - "America/Guayaquil", - "America/Jamaica", - "America/Lima", - "America/Panama", - "America/Rio_Branco", - "Etc/GMT+5" - */], - "SA Western Standard Time": [ - "America/Anguilla"/*, - "America/Antigua", - "America/Aruba", - "America/Barbados", - "America/Blanc-Sablon", - "America/Boa_Vista", - "America/Curacao", - "America/Dominica", - "America/Grenada", - "America/Guadeloupe", - "America/Guyana", - "America/Kralendijk", - "America/La_Paz", - "America/Lower_Princes", - "America/Manaus", - "America/Marigot", - "America/Martinique", - "America/Montserrat", - "America/Port_of_Spain", - "America/Porto_Velho", - "America/Puerto_Rico", - "America/Santo_Domingo", - "America/St_Barthelemy", - "America/St_Kitts", - "America/St_Lucia", - "America/St_Thomas", - "America/St_Vincent", - "America/Tortola", - "Etc/GMT+4" - */], - "Saint Pierre Standard Time": [ - "America/Miquelon" - ], - "Sakhalin Standard Time": [ - "Asia/Sakhalin" - ], - "Samoa Standard Time": [ - "Pacific/Apia" - ], - "Sao Tome Standard Time": [ - "Africa/Sao_Tome" - ], - "Saratov Standard Time": [ - "Europe/Saratov" - ], - "SE Asia Standard Time": [ - "Asia/Bangkok"/*, - "Asia/Jakarta", - "Asia/Phnom_Penh", - "Asia/Pontianak", - "Asia/Saigon", - "Asia/Vientiane", - "Indian/Christmas", - "Antarctica/Davis", - "Etc/GMT-7" - */], - "Singapore Standard Time": [ - "Asia/Singapore"/*, - "Asia/Brunei", - "Asia/Kuala_Lumpur", - "Asia/Kuching", - "Asia/Makassar", - "Asia/Manila", - "Antarctica/Casey", - "Etc/GMT-8" - */], - "South Africa Standard Time": [ - "Africa/Johannesburg"/*, - "Africa/Blantyre", - "Africa/Bujumbura", - "Africa/Gaborone", - "Africa/Harare", - "Africa/Kigali", - "Africa/Lubumbashi", - "Africa/Lusaka", - "Africa/Maputo", - "Africa/Maseru", - "Africa/Mbabane", - "Etc/GMT-2" - */], - "Sri Lanka Standard Time": [ - "Asia/Colombo" - ], - "Sudan Standard Time": [ - "Africa/Khartoum" - ], - "Syria Standard Time": [ - "Asia/Damascus" - ], - "Taipei Standard Time": [ - "Asia/Taipei" - ], - "Tasmania Standard Time": [ - "Australia/Currie"/*, - "Australia/Hobart" - */], - "Tocantins Standard Time": [ - "America/Araguaina" - ], - "Tokyo Standard Time": [ - "Asia/Tokyo"/*, - "Asia/Dili", - "Asia/Jayapura", - "Pacific/Palau", - "Etc/GMT-9" - */], - "Tomsk Standard Time": [ - "Asia/Tomsk" - ], - "Tonga Standard Time": [ - "Pacific/Tongatapu" - ], - "Transbaikal Standard Time": [ - "Asia/Chita" - ], - "Turkey Standard Time": [ - "Europe/Istanbul" - ], - "Turks And Caicos Standard Time": [ - "America/Grand_Turk" - ], - "Ulaanbaatar Standard Time": [ - "Asia/Ulaanbaatar"/*, - "Asia/Choibalsan" - */], - "US Eastern Standard Time": [ - "America/Indianapolis"/*, - "America/Indiana/Marengo", - "America/Indiana/Vevay" - */], - "US Mountain Standard Time": [ - "America/Phoenix"/*, - "America/Creston", - "America/Dawson_Creek", - "America/Fort_Nelson", - "America/Hermosillo", - "Etc/GMT+7" - */], - "UTC": [ - "Etc/GMT"/*, - "America/Danmarkshavn", - "Etc/UTC" - */], - "UTC-02": [ - "Etc/GMT+2"/*, - "America/Noronha", - "Atlantic/South_Georgia" - */], - "UTC-08": [ - "Etc/GMT+8"/*, - "Pacific/Pitcairn" - */], - "UTC-09": [ - "Etc/GMT+9"/*, - "Pacific/Gambier" - */], - "UTC-11": [ - "Etc/GMT+11"/*, - "Pacific/Midway", - "Pacific/Niue", - "Pacific/Pago_Pago" - */], - "UTC+12": [ - "Etc/GMT-12"/*, - "Pacific/Funafuti", - "Pacific/Kwajalein", - "Pacific/Majuro", - "Pacific/Nauru", - "Pacific/Tarawa", - "Pacific/Wake", - "Pacific/Wallis" - */], - "UTC+13": [ - "Etc/GMT-13"/*, - "Pacific/Enderbury", - "Pacific/Fakaofo" - */], - "Venezuela Standard Time": [ - "America/Caracas" - ], - "Vladivostok Standard Time": [ - "Asia/Vladivostok"/*, - "Asia/Ust-Nera" - */], - "Volgograd Standard Time": [ - "Europe/Volgograd" - ], - "W. Australia Standard Time": [ - "Australia/Perth" - ], - "W. Central Africa Standard Time": [ - "Africa/Algiers"/*, - "Africa/Bangui", - "Africa/Brazzaville", - "Africa/Douala", - "Africa/Kinshasa", - "Africa/Lagos", - "Africa/Libreville", - "Africa/Luanda", - "Africa/Malabo", - "Africa/Ndjamena", - "Africa/Niamey", - "Africa/Porto-Novo", - "Africa/Tunis", - "Etc/GMT-1" - */], - "W. Europe Standard Time": [ - "Europe/Amsterdam"/*, - "Europe/Andorra", - "Europe/Berlin", - "Europe/Busingen", - "Europe/Gibraltar", - "Europe/Luxembourg", - "Europe/Malta", - "Europe/Monaco", - "Europe/Oslo", - "Europe/Rome", - "Europe/San_Marino", - "Europe/Stockholm", - "Europe/Vaduz", - "Europe/Vatican", - "Europe/Vienna", - "Europe/Zurich", - "Arctic/Longyearbyen" - */], - "W. Mongolia Standard Time": [ - "Asia/Hovd" - ], - "West Asia Standard Time": [ - "Asia/Aqtau"/*, - "Asia/Aqtobe", - "Asia/Ashgabat", - "Asia/Atyrau", - "Asia/Dushanbe", - "Asia/Oral", - "Asia/Samarkand", - "Asia/Tashkent", - "Indian/Kerguelen", - "Indian/Maldives", - "Antarctica/Mawson", - "Etc/GMT-5" - */], - "West Bank Standard Time": [ - "Asia/Gaza"/*, - "Asia/Hebron" - */], - "West Pacific Standard Time": [ - "Pacific/Guam"/*, - "Pacific/Port_Moresby", - "Pacific/Saipan", - "Pacific/Truk", - "Antarctica/DumontDUrville", - "Etc/GMT-10" - */], - "Yakutsk Standard Time": [ - "Asia/Khandyga"/*, - "Asia/Yakutsk" - */], - }; -})(window.rl); diff --git a/plugins/view-ics/index.php b/plugins/view-ics/index.php deleted file mode 100644 index f12253bc7..000000000 --- a/plugins/view-ics/index.php +++ /dev/null @@ -1,19 +0,0 @@ -UseLangs(true); - $this->addJs('ical.js'); - $this->addJs('message.js'); - } -} diff --git a/plugins/view-ics/message.js b/plugins/view-ics/message.js deleted file mode 100644 index 551cccff9..000000000 --- a/plugins/view-ics/message.js +++ /dev/null @@ -1,85 +0,0 @@ -(rl => { - const templateId = 'MailMessageView'; - - addEventListener('rl-view-model.create', e => { - if (templateId === e.detail.viewModelTemplateID) { - - const - template = document.getElementById(templateId), - view = e.detail, - attachmentsPlace = template.content.querySelector('.attachmentsPlace'); - - attachmentsPlace.after(Element.fromHTML(` -
- - - - - - - - - -
Organizer
Start
End
-
`)); - - view.viewICS = ko.observable(null); - - view.saveICS = () => { - let VEVENT = view.VEVENT(); - if (VEVENT) { - if (rl.nextcloud && VEVENT.rawText) { - rl.nextcloud.selectCalendar() - .then(href => href && rl.nextcloud.calendarPut(href, VEVENT)); - } else { - // TODO - } - } - } - - /** - * TODO - */ - view.message.subscribe(msg => { - view.viewICS(null); - if (msg) { - // JSON-LD after parsing HTML - // See http://schema.org/ - msg.linkedData.subscribe(data => { - if (!view.viewICS()) { - data.forEach(item => { - if (item["ical:summary"]) { - let VEVENT = { - SUMMARY: item["ical:summary"], - DTSTART: rl.ICS.parseDate(item["ical:dtstart"]), -// DTEND: rl.ICS.parseDate(item["ical:dtend"]), -// TRANSP: item["ical:transp"], -// LOCATION: item["ical:location"], - ATTENDEE: [] - } - view.viewICS(VEVENT); - return; - } - }); - } - }); - // ICS attachment -// let ics = msg.attachments.find(attachment => 'application/ics' == attachment.mimeType); - let ics = msg.attachments.find(attachment => 'text/calendar' == attachment.mimeType); - if (ics && ics.download) { - // fetch it and parse the VEVENT - rl.fetch(ics.linkDownload()) - .then(response => (response.status < 400) ? response.text() : Promise.reject(new Error({ response }))) - .then(text => { - let VEVENT = rl.ICS.parseEvent(text); - if (VEVENT) { - view.viewICS(VEVENT); - } - }); - } - } - }); - } - }); - -})(window.rl); diff --git a/plugins/view-ics/style.css b/plugins/view-ics/style.css deleted file mode 100644 index b3a4e5c8c..000000000 --- a/plugins/view-ics/style.css +++ /dev/null @@ -1,44 +0,0 @@ - -/** - * .SML-@type where @type is the value of the JSON-LD "@type": - * See http://schema.org/ - */ - -.SML-FlightReservation { -} - - .SML-Airline { - } - - .SML-Airport { - } - - .SML-Flight { - } - -.SML-FoodEstablishmentReservation { -} - - .SML-FoodEstablishment { - } - -.SML-ParcelDelivery { -} - - .SML-Order { - } - - .SML-Organization { - } - - .SML-Product { - } - - .SML-PostalAddress { - } - -.SML-Person { -} - -.SML-PromotionCard { -} diff --git a/plugins/white-list/index.php b/plugins/white-list/index.php index 2b91b8bcc..efad99ea8 100644 --- a/plugins/white-list/index.php +++ b/plugins/white-list/index.php @@ -4,31 +4,35 @@ class WhiteListPlugin extends \RainLoop\Plugins\AbstractPlugin { const NAME = 'Whitelist', - VERSION = '2.2', - RELEASE = '2024-03-04', + VERSION = '2.1', + RELEASE = '2021-04-21', REQUIRED = '2.5.0', CATEGORY = 'Login', DESCRIPTION = 'Simple login whitelist (with wildcard and exceptions functionality).'; public function Init() : void { - $this->addHook('login.credentials.step-1', 'FilterLoginCredentials'); + $this->addHook('login.credentials', 'FilterLoginCredentials'); } /** + * @param string $sEmail + * @param string $sLogin + * @param string $sPassword + * * @throws \RainLoop\Exceptions\ClientException */ - public function FilterLoginCredentials(string &$sEmail) + public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword) { $sWhiteList = \trim($this->Config()->Get('plugin', 'white_list', '')); - if (\strlen($sWhiteList) && !\RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sWhiteList)) { + if (0 < strlen($sWhiteList) && !\RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sWhiteList)) + { $sExceptions = \trim($this->Config()->Get('plugin', 'exceptions', '')); - if (!\strlen($sExceptions) || \RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sExceptions)) { + if (0 === \strlen($sExceptions) || !\RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sExceptions)) + { throw new \RainLoop\Exceptions\ClientException( - $this->Config()->Get('plugin', 'auth_error', false) - ? \RainLoop\Notifications::AuthError - : \RainLoop\Notifications::AccountNotAllowed - ); + $this->Config()->Get('plugin', 'auth_error', true) ? + \RainLoop\Notifications::AuthError : \RainLoop\Notifications::AccountNotAllowed); } } } @@ -42,7 +46,7 @@ class WhiteListPlugin extends \RainLoop\Plugins\AbstractPlugin \RainLoop\Plugins\Property::NewInstance('auth_error')->SetLabel('Auth Error') ->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL) ->SetDescription('Throw an authentication error instead of an access error.') - ->SetDefaultValue(false), + ->SetDefaultValue(true), \RainLoop\Plugins\Property::NewInstance('white_list')->SetLabel('White List') ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) ->SetDescription('Emails white list, space as delimiter, wildcard supported.') diff --git a/plugins/wysiwyg-example/example.js b/plugins/wysiwyg-example/example.js deleted file mode 100644 index a26fe5158..000000000 --- a/plugins/wysiwyg-example/example.js +++ /dev/null @@ -1,82 +0,0 @@ -(rl => { - class Example - { - constructor(owner, editor) { - this.mode = 'wysiwyg'; - this.owner = owner; - this.editor = editor; -console.dir({editor}); - } - - setMode(mode) { - console.log(`WYSIWYG-Example.setMode(${mode})`); - this.mode = mode; - } - - on(type, fn) { - console.log(`WYSIWYG-Example.on(${type}, ${fn})`); - } - - execCommand(cmd, cfg) { - console.log(`WYSIWYG-Example.execCommand(${cmd}, ${cfg})`); -/* - execCommand('insertSignature', { - clearCache: true - })); - - execCommand('insertSignature', { - isHtml: html, - insertBefore: insertBefore, - signature: signature - })); -*/ - } - - getData() { - console.log(`WYSIWYG-Example.getData()`); - return this.editor.innerHTML; - } - - setData(html) { - console.log(`WYSIWYG-Example.setData(${html})`); - this.editor.innerHTML = html; - } - - getPlainData() { - console.log(`WYSIWYG-Example.getPlainData()`); - return this.editor.innerText; - } - - setPlainData(text) { - console.log(`WYSIWYG-Example.setPlainData(${text})`); - return this.editor.textContent = text; - } - - blur() { - console.log(`WYSIWYG-Example.blur()`); - this.editor.blur(); - } - - focus() { - console.log(`WYSIWYG-Example.focus()`); - } - } - - if (rl) { - const path = rl.settings.app('webVersionPath'), - script = document.createElement('script'); - script.src = path + 'static/wysiwyg-example/example.min.js'; - document.head.append(script); - - /** - * owner = HtmlEditor - * container = HTMLElement - * onReady = callback(SMQuill) - */ - rl.registerWYSIWYG('Example', (owner, container, onReady) => { - const editor = new Example(owner, container); - onReady(editor); - }); - } - -})(window.rl); diff --git a/plugins/wysiwyg-example/static/example.min.js b/plugins/wysiwyg-example/static/example.min.js deleted file mode 100644 index 8d1c8b69c..000000000 --- a/plugins/wysiwyg-example/static/example.min.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/public_html/translate.php b/public_html/translate.php deleted file mode 100644 index 30f6613ea..000000000 --- a/public_html/translate.php +++ /dev/null @@ -1,197 +0,0 @@ - $values) { - if (is_array($values)) { - foreach ($values as $key => $value) { - $data[$section][$key] = preg_replace('/\\R/', "\n", trim($value)); - } - } else if ('LANG_DIR' === $section) { - $data[$section] = $values; - } - } - return str_replace(' ', "\t", json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); -} - -if ('POST' === $_SERVER['REQUEST_METHOD']) { - try { - $file = tempnam(sys_get_temp_dir(), ''); - $zip = new ZipArchive(); - if (!$zip->open($file, ZIPARCHIVE::CREATE)) { - exit("Failed to create zip"); - } - if (!$lang) { - $lang = (empty($_POST['lang']) || !preg_match('/^[a-z]{2}(-[A-Z]{2})?$/D',$_POST['lang'])) - ? 'new' : $_POST['lang']; - } - $zip->addFromString("{$lang}/admin.json", toJSON($_POST['admin'])); - $zip->addFromString("{$lang}/user.json", toJSON($_POST['user'])); - $zip->close(); - header('Content-Type: application/zip'); - header('Content-disposition: attachment; filename="snappymail-'.$lang.'.zip"'); - header('Content-Length: ' . filesize($file)); - readfile($file); - } catch (\Throwable $e) { - echo $e->getMessage(); - } - unlink($file); - exit; -} - -// /home/rainloop/public_html/snappymail/v/0.0.0/static/js -$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true; -require 'demo/index.php'; - -$root = APP_VERSION_ROOT_PATH . 'app/localization'; - -$en = [ - 'user' => '', - 'admin' => '', -// 'static' => '', -]; -foreach ($en as $name => $data) { - $en[$name] = json_decode(file_get_contents("{$root}/en/{$name}.json"), true); -} - -$languages = ['']; -foreach (glob("{$root}/*", GLOB_ONLYDIR) as $dir) { - $name = basename($dir); - if ('en' !== $name) { - $languages[$name] = ""; - } -} -ksort($languages); - -$lang_names = json_decode(file_get_contents("{$root}/langs.json"), true)['LANGS_NAMES_EN']; - -$other_langs = []; -foreach ($lang_names as $key => $name) { - if ('en' !== $key && !isset($languages[$key])) { - $other_langs[$key] = ""; - } -} - -//print_r($languages); - -echo ' - - - - Translate - - -

Translate:

-
- Show untranslated only - - - - - - -'; -foreach ($en as $name => $sections) { - echo ''; - $data = $sections; - if ($lang && is_readable("{$root}/{$lang}/{$name}.json")) { - $data = json_decode(file_get_contents("{$root}/{$lang}/{$name}.json"), true); - } - foreach ($sections as $section => $values) { - if (is_array($values)) { - echo ''; - foreach ($values as $key => $value) { - echo ''; -// echo ''; - echo ''; - echo ''; - echo ''; - } - } else if ('LANG_DIR' === $section) { - echo ''; - echo ''; - echo ''; - echo ''; - } - } - echo ''; -} -echo '
en'.($lang ? "{$lang_names[$lang]} ({$lang})" : '').'
'.$name.'
'.$section.'
'.$section.'/'.$key.''.htmlspecialchars($value).'
Text direction
'; -echo '
'; - -/* - -
- -
- -
-
-
- -
- -
-
+
- -
-
-

-
-
- + +   + +
+

@@ -27,16 +31,4 @@ - - -
- -    - -
- -
- - -
diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html index e31f81108..9bc993922 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html @@ -66,6 +66,13 @@ value: capaUserBackground } }">
+
diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsLogin.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsLogin.html index 0add30ff6..020befb3a 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsLogin.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsLogin.html @@ -1,8 +1,15 @@ -
+
- +
@@ -10,6 +17,7 @@ name: 'Checkbox', params: { value: determineUserDomain, label: 'TAB_LOGIN/LABEL_DETERMINE_USER_DOMAIN' } }">
+
-
+ diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPackages.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPackages.html index b52152d44..41e06a9c7 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPackages.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPackages.html @@ -1,5 +1,5 @@
- +
@@ -15,14 +15,11 @@

- -
-
@@ -31,7 +28,7 @@
-
+
diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html index 130d710dc..0e952f2af 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html @@ -1,36 +1,33 @@ - - + + - + - + - + - - + + - +
- + - - - - - + + diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html index d96bf34bf..32f3e8dc4 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/AdminSettingsSecurity.html @@ -1,38 +1,20 @@
-
-
-
-
-
-
-
@@ -65,15 +47,38 @@ -

 	
-
+
+
+
+
+
+ () +
+
+
+
+
diff --git a/snappymail/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html b/snappymail/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html index b78891e18..991093c9d 100644 --- a/snappymail/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html +++ b/snappymail/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html @@ -8,193 +8,100 @@ ()
-
-
-
+
- - + +
-
-
+

-
-
+

- - - + +
-
+

- -
-
- -
- +

-
- (user@example.com → user) -
-
- (USER@example.com → user@example.com) - -

SSL/TLS

-
-
- -

- - ⓘ -

- -
-
- -
-
- -

-
- - -
- -
- - -
-
- - -
+ (user@domain.com → user)
- - + +