Compare commits
No commits in common. "master" and "v1.10.5.192" have entirely different histories.
master
...
v1.10.5.19
|
|
@ -1,4 +0,0 @@
|
|||
last 1 version
|
||||
> 30%
|
||||
not IE 11
|
||||
not IE_Mob 11
|
||||
17
.cmds
|
|
@ -1,19 +1,12 @@
|
|||
|
||||
# yarn
|
||||
yarn install
|
||||
yarn upgrade xxx@1.2.3
|
||||
|
||||
# transifex
|
||||
tx pull -a
|
||||
|
||||
# dependencies
|
||||
yarn outdated
|
||||
yarn upgrade-interactive --exact --latest
|
||||
# dependencies checker
|
||||
npm-check --skip-unused --save-exact
|
||||
|
||||
# dependencies locker
|
||||
npm shrinkwrap --dev
|
||||
|
||||
# webpack
|
||||
webpack --color --watch
|
||||
|
||||
#
|
||||
gpg --import x
|
||||
gpg --detach-sign --armor --openpgp -u 87DA4591 --passphrase ?? x
|
||||
for ff in `ls ./build/dist/releases/**/**/*.zip | xargs`; do gpg --detach-sign --no-tty --yes --armor --openpgp -u 87DA4591 --passphrase ?? $ff; done
|
||||
|
|
|
|||
|
|
@ -1,233 +0,0 @@
|
|||
#! /bin/sh
|
||||
|
||||
##
|
||||
# Wrapper for various setup scripts included in the docker-mailserver
|
||||
#
|
||||
|
||||
INFO=$(docker ps \
|
||||
--no-trunc \
|
||||
--format="{{.Image}}\t{{.Names}}\t{{.Command}}" | \
|
||||
grep "/bin/sh -c 'supervisord -c /etc/supervisor/supervisord.conf'")
|
||||
|
||||
IMAGE_NAME=$(echo $INFO | awk '{print $1}')
|
||||
CONTAINER_NAME=$(echo $INFO | awk '{print $2}')
|
||||
CONFIG_PATH="$(pwd)/config"
|
||||
|
||||
if [ -z "$IMAGE_NAME" ]; then
|
||||
IMAGE_NAME=tvial/docker-mailserver:latest
|
||||
fi
|
||||
|
||||
_inspect() {
|
||||
if _docker_image_exists "$IMAGE_NAME"; then
|
||||
echo "Image: $IMAGE_NAME"
|
||||
else
|
||||
echo "Image: '$IMAGE_NAME' can’t be found."
|
||||
fi
|
||||
if [ -n "$CONTAINER_NAME" ]; then
|
||||
echo "Container: $CONTAINER_NAME"
|
||||
else
|
||||
echo "Container: Not running, please start docker-mailserver."
|
||||
fi
|
||||
}
|
||||
|
||||
_usage() {
|
||||
echo "Usage: $0 [-i IMAGE_NAME] [-c CONTAINER_NAME] <subcommand> <subcommand> [args]
|
||||
|
||||
OPTIONS:
|
||||
|
||||
-i IMAGE_NAME The name of the docker-mailserver image, by default
|
||||
'tvial/docker-mailserver:latest'.
|
||||
-c CONTAINER_NAME The name of the running container.
|
||||
|
||||
-p PATH config folder path (default: $(pwd)/config)
|
||||
|
||||
SUBCOMMANDS:
|
||||
|
||||
email:
|
||||
|
||||
$0 email add <email> [<password>]
|
||||
$0 email update <email> [<password>]
|
||||
$0 email del <email>
|
||||
$0 email restrict <add|del|list> <send|receive> [<email>]
|
||||
$0 email list
|
||||
|
||||
alias:
|
||||
$0 alias add <email> <recipient>
|
||||
$0 alias del <email> <recipient>
|
||||
$0 alias list
|
||||
|
||||
config:
|
||||
|
||||
$0 config dkim
|
||||
$0 config ssl
|
||||
|
||||
debug:
|
||||
|
||||
$0 debug fetchmail
|
||||
$0 debug fail2ban [<unban> <ip-address>]
|
||||
$0 debug show-mail-logs
|
||||
$0 debug inspect
|
||||
$0 debug login <commands>
|
||||
"
|
||||
exit 1
|
||||
}
|
||||
|
||||
_docker_image_exists() {
|
||||
if docker history -q "$1" >/dev/null 2>&1; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_docker_image() {
|
||||
if ! _docker_image_exists "$IMAGE_NAME"; then
|
||||
echo "Image '$IMAGE_NAME' not found. Pulling ..."
|
||||
docker pull "$IMAGE_NAME"
|
||||
fi
|
||||
docker run \
|
||||
--rm \
|
||||
-v "$CONFIG_PATH":/tmp/docker-mailserver \
|
||||
-ti "$IMAGE_NAME" $@
|
||||
}
|
||||
|
||||
_docker_container() {
|
||||
if [ -n "$CONTAINER_NAME" ]; then
|
||||
docker exec -ti "$CONTAINER_NAME" $@
|
||||
else
|
||||
echo "The docker-mailserver is not running!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
while getopts ":c:i:p:" OPT; do
|
||||
case $OPT in
|
||||
c)
|
||||
CONTAINER_NAME="$OPTARG"
|
||||
;;
|
||||
i)
|
||||
IMAGE_NAME="$OPTARG"
|
||||
;;
|
||||
p)
|
||||
case "$OPTARG" in
|
||||
/*)
|
||||
CONFIG_PATH="$OPTARG"
|
||||
;;
|
||||
*)
|
||||
CONFIG_PATH="$(pwd)/$OPTARG"
|
||||
;;
|
||||
esac
|
||||
if [ ! -d "$CONFIG_PATH" ]; then
|
||||
echo "Directory doesn't exist"
|
||||
_usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
case $1 in
|
||||
|
||||
email)
|
||||
shift
|
||||
case $1 in
|
||||
add)
|
||||
shift
|
||||
_docker_image addmailuser $@
|
||||
;;
|
||||
update)
|
||||
shift
|
||||
_docker_image updatemailuser $@
|
||||
;;
|
||||
del)
|
||||
shift
|
||||
_docker_image delmailuser $@
|
||||
;;
|
||||
restrict)
|
||||
shift
|
||||
_docker_container restrict-access $@
|
||||
;;
|
||||
list)
|
||||
_docker_image listmailuser
|
||||
;;
|
||||
*)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
alias)
|
||||
shift
|
||||
case $1 in
|
||||
add)
|
||||
shift
|
||||
_docker_image addalias $@
|
||||
;;
|
||||
del)
|
||||
shift
|
||||
_docker_image delalias $@
|
||||
;;
|
||||
list)
|
||||
shift
|
||||
_docker_image listalias $@
|
||||
;;
|
||||
*)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
config)
|
||||
shift
|
||||
case $1 in
|
||||
dkim)
|
||||
_docker_image generate-dkim-config
|
||||
;;
|
||||
ssl)
|
||||
_docker_image generate-ssl-certificate
|
||||
;;
|
||||
*)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
debug)
|
||||
shift
|
||||
case $1 in
|
||||
fetchmail)
|
||||
_docker_image debug-fetchmail
|
||||
;;
|
||||
fail2ban)
|
||||
shift
|
||||
_docker_container fail2ban $@
|
||||
;;
|
||||
show-mail-logs)
|
||||
_docker_container cat /var/log/mail/mail.log
|
||||
;;
|
||||
inspect)
|
||||
_inspect
|
||||
;;
|
||||
login)
|
||||
shift
|
||||
if [ -z "$1" ]; then
|
||||
_docker_container /bin/bash
|
||||
else
|
||||
_docker_container /bin/bash -c "$@"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
*)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
server {
|
||||
listen 80 default;
|
||||
listen 443 ssl;
|
||||
server_name localhost _;
|
||||
root /var/www;
|
||||
|
||||
index index.php index.html;
|
||||
|
||||
autoindex on;
|
||||
charset utf-8;
|
||||
client_max_body_size 500m;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/localhost.cert;
|
||||
ssl_certificate_key /etc/nginx/ssl/localhost.key;
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
|
||||
gzip_vary on;
|
||||
|
||||
access_log /var/log/nginx/default.access.log;
|
||||
error_log /var/log/nginx/default.error.log;
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location ~* favicon\.(ico|png)$ { access_log off; log_not_found off; }
|
||||
location = /browserconfig.xml { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
location = /humans.txt { access_log off; log_not_found off; }
|
||||
location = /apple-touch-icon.png { access_log off; log_not_found off; }
|
||||
location = /apple-touch-icon-precomposed.png { access_log off; log_not_found off; }
|
||||
location ~ /\.ht { deny all; return 404; }
|
||||
location ~ /\.git { deny all; return 404; }
|
||||
location ~ /\.svn { deny all; return 404; }
|
||||
|
||||
location ~* ^.+\.(?:jpe?g|gif|bmp|ico|png|css|js|swf)$ {
|
||||
expires 30d;
|
||||
access_log off;
|
||||
add_header Pragma public;
|
||||
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
|
||||
}
|
||||
|
||||
location ~ \.php(/|$) {
|
||||
include fastcgi_params;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param HTTPS off;
|
||||
fastcgi_pass php:9000;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SERVER_NAME=localhost
|
||||
SUBJECT="/C=RU/ST=RND/L=Taganrog/O=Umbrella Web/CN=${SERVER_NAME}"
|
||||
|
||||
mkdir -p ./ssl
|
||||
|
||||
if [ -f ./ssl/${SERVER_NAME}.cert ]; then
|
||||
rm -rf ./ssl/${SERVER_NAME}.cert
|
||||
fi
|
||||
|
||||
if [ -f ./ssl/${SERVER_NAME}.key ]; then
|
||||
rm -rf ./ssl/${SERVER_NAME}.key
|
||||
fi
|
||||
|
||||
# Generating ROOT pem files
|
||||
openssl req -x509 -new -nodes -newkey rsa:2048 -keyout ./ssl/server_rootCA.key -sha256 -days 1024 -out ./ssl/server_rootCA.pem -subj "${SUBJECT}" 2> /dev/null
|
||||
|
||||
# Generating v3.ext file
|
||||
cat <<EOF > ./ssl/v3.ext
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = ${SERVER_NAME}
|
||||
DNS.2 = www.${SERVER_NAME}
|
||||
EOF
|
||||
|
||||
echo " - Generating SSL key file"
|
||||
openssl req -new -newkey rsa:2048 -sha256 -nodes -newkey rsa:2048 -keyout ./ssl/${SERVER_NAME}.key -subj "${SUBJECT}" -out ./ssl/server_rootCA.csr 2> /dev/null
|
||||
|
||||
echo " - Generating SSL certificate file"
|
||||
openssl x509 -req -in ./ssl/server_rootCA.csr -CA ./ssl/server_rootCA.pem -CAkey ./ssl/server_rootCA.key -CAcreateserial -out ./ssl/${SERVER_NAME}.cert -days 3650 -sha256 -extfile ./ssl/v3.ext 2> /dev/null
|
||||
|
||||
# echo " - Adding certificate into local keychain"
|
||||
# sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" ./ssl/server_rootCA.pem 2> /dev/null
|
||||
|
||||
echo " - Runing garbage collector"
|
||||
rm -rf ./ssl/server_rootCA.csr ./ssl/server_rootCA.key ./ssl/server_rootCA.pem ./ssl/v3.ext ./.srl
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
FROM php:7.4-fpm
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
RUN apt-get install -y \
|
||||
git unzip wget zip curl mlocate \
|
||||
libicu-dev libpcre3-dev libicu-dev \
|
||||
build-essential chrpath libssl-dev \
|
||||
libxft-dev libfreetype6 libfreetype6-dev \
|
||||
libpng-dev libjpeg62-turbo-dev \
|
||||
libfontconfig1 libfontconfig1-dev libzip-dev libldap2-dev
|
||||
|
||||
RUN pecl install xxtea-1.0.11 && \
|
||||
docker-php-ext-enable xxtea
|
||||
|
||||
RUN docker-php-ext-configure intl && \
|
||||
docker-php-ext-configure ldap && \
|
||||
docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ && \
|
||||
docker-php-ext-install opcache pdo_mysql zip intl gd ldap
|
||||
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
RUN curl --location --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar && chmod +x /usr/local/bin/phpunit
|
||||
|
||||
RUN apt-get -y autoremove && apt-get clean
|
||||
|
||||
RUN sed -i '/^;catch_workers_output/ccatch_workers_output = yes' '/usr/local/etc/php-fpm.d/www.conf'
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
CMD ["php-fpm"]
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
date.timezone = UTC
|
||||
upload_max_filesize = 24M
|
||||
post_max_size = 25M
|
||||
|
||||
# log_errors = On
|
||||
# display_errors = On
|
||||
# error_reporting = E_ALL
|
||||
# error_log = /dev/stderr
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
# 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
|
||||
|
||||
LABEL org.label-schema.description="SnappyMail webmail client image using nginx, php-fpm on Alpine"
|
||||
|
||||
# Install dependencies such as nginx
|
||||
RUN apk add --no-cache ca-certificates nginx supervisor bash
|
||||
|
||||
# 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
|
||||
|
||||
# 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;
|
||||
|
||||
USER root
|
||||
WORKDIR /snappymail
|
||||
VOLUME /var/lib/snappymail
|
||||
EXPOSE 8888
|
||||
EXPOSE 9000
|
||||
ENTRYPOINT []
|
||||
CMD ["/entrypoint.sh"]
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
#!/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}
|
||||
|
||||
# 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>/$UPLOAD_MAX_SIZE/g" /usr/local/etc/php-fpm.d/php-fpm.conf /etc/nginx/nginx.conf
|
||||
sed -i "s/<MEMORY_LIMIT>/$MEMORY_LIMIT/g" /usr/local/etc/php-fpm.d/php-fpm.conf
|
||||
|
||||
# Secure cookies
|
||||
if [ "${SECURE_COOKIES}" = 'true' ]; then
|
||||
echo "[INFO] Secure cookies activated"
|
||||
{
|
||||
echo 'session.cookie_httponly = On';
|
||||
echo 'session.cookie_secure = On';
|
||||
echo 'session.use_only_cookies = On';
|
||||
} > /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
|
||||
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
|
||||
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
|
||||
# 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
|
||||
|
||||
(
|
||||
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
|
||||
|
||||
wget -T 1 -qO- 'http://127.0.0.1:8888/' > /dev/null
|
||||
echo "[INFO] Snappymail ready at http://localhost:8888/"
|
||||
) &
|
||||
|
||||
# RUN !
|
||||
exec /usr/bin/supervisord -c /supervisor.conf --pidfile /run/supervisord.pid
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log off;
|
||||
error_log /dev/stderr error;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 15;
|
||||
keepalive_disable msie6;
|
||||
keepalive_requests 100;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
server_tokens off;
|
||||
|
||||
fastcgi_temp_path /tmp/fastcgi 1 2;
|
||||
client_body_temp_path /tmp/client_body 1 2;
|
||||
proxy_temp_path /tmp/proxy 1 2;
|
||||
uwsgi_temp_path /tmp/uwsgi 1 2;
|
||||
scgi_temp_path /tmp/scgi 1 2;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 512;
|
||||
gzip_buffers 4 8k;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
gzip_disable "msie6";
|
||||
gzip_types
|
||||
text/css
|
||||
text/javascript
|
||||
text/xml
|
||||
text/plain
|
||||
text/x-component
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
application/vnd.ms-fontobject
|
||||
font/truetype
|
||||
font/opentype
|
||||
image/svg+xml;
|
||||
|
||||
server {
|
||||
listen 8888;
|
||||
listen [::]:8888;
|
||||
#listen [::]:8888 ipv6only=off;
|
||||
root /snappymail;
|
||||
index index.php;
|
||||
charset utf-8;
|
||||
|
||||
client_max_body_size <UPLOAD_MAX_SIZE>;
|
||||
|
||||
location ^~ /data {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ index.php;
|
||||
}
|
||||
|
||||
# Assets cache control
|
||||
# --------------------------------------
|
||||
location ~* \.(?:html|xml|json)$ {
|
||||
expires -1;
|
||||
}
|
||||
|
||||
location ~* \.(?:css|js)$ {
|
||||
expires 7d;
|
||||
add_header Pragma public;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
location ~* \.(?:gif|jpe?g|png|ico|otf|eot|svg|ttf|woff|woff2)$ {
|
||||
expires 30d;
|
||||
log_not_found off;
|
||||
add_header Pragma public;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# PHP Backend
|
||||
# --------------------------------------
|
||||
location ~* \.php$ {
|
||||
try_files $uri =404;
|
||||
include fastcgi_params;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param HTTP_PROXY "";
|
||||
fastcgi_index index.php;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_intercept_errors on;
|
||||
fastcgi_request_buffering off;
|
||||
fastcgi_param REMOTE_ADDR $http_x_real_ip;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
$stdIn = STDIN;
|
||||
$stdOut = STDOUT;
|
||||
|
||||
fwrite($stdOut, "READY\n");
|
||||
|
||||
while(true) {
|
||||
if (false == $line = trim(fgets($stdIn))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$match = null;
|
||||
if (preg_match('/eventname:(.*?) /', $line, $match)) {
|
||||
if (in_array($match[1], ['PROCESS_STATE_EXITED', 'PROCESS_STATE_STOPPED', 'PROCESS_STATE_FATAL'])) {
|
||||
exec('kill -15 '.file_get_contents('/run/supervisord.pid'));
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($stdOut, "RESULT 2\nOK");
|
||||
|
||||
sleep(1);
|
||||
fwrite($stdOut, "READY\n");
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<?php
|
||||
define('APP_DATA_FOLDER_PATH', '/var/lib/snappymail/');
|
||||
?>
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
[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
|
||||
numprocs=1
|
||||
autostart=true
|
||||
autorestart=false
|
||||
startsecs=0
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:php-fpm]
|
||||
command=php-fpm -F
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
user=root
|
||||
numprocs=1
|
||||
autostart=true
|
||||
autorestart=false
|
||||
startsecs=0
|
||||
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
|
||||
numprocs=1
|
||||
events=PROCESS_STATE_EXITED,PROCESS_STATE_STOPPED,PROCESS_STATE_FATAL
|
||||
autostart=true
|
||||
autorestart=unexpected
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
[global]
|
||||
daemonize = no
|
||||
error_log = /dev/stderr
|
||||
log_buffering = no
|
||||
|
||||
[default]
|
||||
listen = 9000
|
||||
user = www-data
|
||||
listen.owner = www-data
|
||||
listen.group = www-data
|
||||
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[log_errors] = On
|
||||
php_admin_value[expose_php] = Off
|
||||
php_admin_value[display_errors] = Off
|
||||
php_admin_value[date.timezone] = UTC
|
||||
php_admin_value[post_max_size] = <UPLOAD_MAX_SIZE>
|
||||
php_admin_value[upload_max_filesize] = <UPLOAD_MAX_SIZE>
|
||||
php_admin_value[memory_limit] = <MEMORY_LIMIT>
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
/.git
|
||||
/node_modules
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[*.php]
|
||||
indent_style = tab
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
*.*
|
||||
!/dev/**/*.js
|
||||
!/tasks/**/*.js
|
||||
!/*.js
|
||||
346
.eslintrc.js
|
|
@ -1,64 +1,282 @@
|
|||
module.exports = {
|
||||
parser: 'babel-eslint',
|
||||
// extends: ['eslint:recommended', 'plugin:prettier/recommended'],
|
||||
extends: ['eslint:recommended'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 11,
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
node: true,
|
||||
browser: true,
|
||||
es2020: true
|
||||
},
|
||||
globals: {
|
||||
// SnappyMail
|
||||
'rainloopI18N': "readonly",
|
||||
'rainloopTEMPLATES': "readonly",
|
||||
'rl': "readonly",
|
||||
'shortcuts': "readonly",
|
||||
// '__APP_BOOT': "readonly",
|
||||
// deb/boot.js
|
||||
'progressJs': "readonly",
|
||||
// others
|
||||
'openpgp': "readonly",
|
||||
'CKEDITOR': "readonly",
|
||||
'Squire': "readonly",
|
||||
'SquireUI': "readonly",
|
||||
// node_modules/knockout but dev/External/ko.js is used
|
||||
'ko': "readonly",
|
||||
// vendors/routes/
|
||||
'hasher': "readonly",
|
||||
'Crossroads': "readonly",
|
||||
// vendors/jua
|
||||
'Jua': "readonly",
|
||||
// vendors/bootstrap/bootstrap.native.js
|
||||
'BSN': "readonly",
|
||||
// Mailvelope
|
||||
'mailvelope': "readonly",
|
||||
// Punycode
|
||||
'IDN': "readonly",
|
||||
// Turndown
|
||||
'TurndownService': "readonly",
|
||||
// Marked
|
||||
'marked': "readonly"
|
||||
},
|
||||
// http://eslint.org/docs/rules/
|
||||
rules: {
|
||||
'no-cond-assign': 0,
|
||||
// plugins
|
||||
'no-mixed-spaces-and-tabs': 'off',
|
||||
'max-len': [
|
||||
'error',
|
||||
120,
|
||||
2,
|
||||
{
|
||||
ignoreComments: true,
|
||||
ignoreUrls: true,
|
||||
ignoreTrailingComments: true,
|
||||
ignorePattern: '(^\\s*(const|let|var)\\s.+=\\s*require\\s*\\(|^import\\s.+\\sfrom\\s.+;$)'
|
||||
}
|
||||
],
|
||||
'no-constant-condition': ["error", { "checkLoops": false }]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
'extends': 'eslint:recommended',
|
||||
'ecmaFeatures': {
|
||||
'modules': true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 6,
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'env': {
|
||||
'node': true,
|
||||
'commonjs': true,
|
||||
'es6': true
|
||||
},
|
||||
'globals': {
|
||||
'RL_COMMUNITY': true,
|
||||
'RL_ES6': true
|
||||
},
|
||||
// http://eslint.org/docs/rules/
|
||||
'rules': {
|
||||
|
||||
// errors
|
||||
'no-cond-assign': [2, 'always'],
|
||||
'no-console': 2,
|
||||
'no-constant-condition': 2,
|
||||
'no-control-regex': 2,
|
||||
'no-debugger': 2,
|
||||
'no-dupe-args': 2,
|
||||
'no-dupe-keys': 2,
|
||||
'no-duplicate-case': 2,
|
||||
'no-empty': 2,
|
||||
'no-empty-character-class': 2,
|
||||
'no-ex-assign': 2,
|
||||
'no-extra-boolean-cast': 2,
|
||||
// 'no-extra-parens': 2,
|
||||
'no-extra-semi': 2,
|
||||
'no-func-assign': 2,
|
||||
'no-inner-declarations': 2,
|
||||
'no-invalid-regexp': 2,
|
||||
'no-irregular-whitespace': 2,
|
||||
'no-negated-in-lhs': 2,
|
||||
'no-obj-calls': 2,
|
||||
'no-prototype-builtins': 2,
|
||||
'no-regex-spaces': 2,
|
||||
'no-sparse-arrays': 2,
|
||||
'no-unexpected-multiline': 2,
|
||||
'no-unreachable': 2,
|
||||
'no-unsafe-finally': 2,
|
||||
'use-isnan': 2,
|
||||
// 'valid-jsdoc': [2, {
|
||||
// 'requireParamDescription': false,
|
||||
// 'requireReturnDescription': false
|
||||
// }],
|
||||
'valid-typeof': 2,
|
||||
|
||||
// best practices
|
||||
'accessor-pairs': 2,
|
||||
'array-callback-return': 2,
|
||||
'block-scoped-var': 2,
|
||||
// 'complexity': 2,
|
||||
'consistent-return': 2,
|
||||
'curly': 2,
|
||||
'default-case': 2,
|
||||
'dot-location': [2, 'property'],
|
||||
'dot-notation': 2,
|
||||
'eqeqeq': 2,
|
||||
'guard-for-in': 2,
|
||||
'no-alert': 2,
|
||||
'no-caller': 2,
|
||||
'no-case-declarations': 2,
|
||||
'no-div-regex': 2,
|
||||
'no-else-return': 2,
|
||||
'no-empty-function': 2,
|
||||
'no-empty-pattern': 2,
|
||||
'no-eq-null': 2,
|
||||
'no-eval': 2,
|
||||
'no-extend-native': 2,
|
||||
'no-extra-bind': 2,
|
||||
'no-extra-label': 2,
|
||||
'no-fallthrough': 2,
|
||||
'no-floating-decimal': 2,
|
||||
'no-implicit-coercion': [2, {'allow': ['!!', '+']}],
|
||||
'no-implicit-globals': 2,
|
||||
'no-implied-eval': 2,
|
||||
'no-invalid-this': 2,
|
||||
'no-iterator': 2,
|
||||
'no-labels': 2,
|
||||
'no-lone-blocks': 2,
|
||||
'no-loop-func': 2,
|
||||
// 'no-magic-numbers': [2, {
|
||||
// 'ignore': [-1, 0, 1, 2, 10, 100],
|
||||
// 'ignoreArrayIndexes': true
|
||||
// }],
|
||||
'no-multi-spaces': 2,
|
||||
'no-multi-str': 2,
|
||||
'no-native-reassign': 2,
|
||||
'no-new': 2,
|
||||
'no-new-func': 2,
|
||||
'no-new-wrappers': 2,
|
||||
'no-octal': 2,
|
||||
'no-octal-escape': 2,
|
||||
// 'no-param-reassign': 2,
|
||||
'no-proto': 2,
|
||||
'no-redeclare': 2,
|
||||
'no-return-assign': 2,
|
||||
'no-script-url': 2,
|
||||
'no-self-assign': 2,
|
||||
'no-self-compare': 2,
|
||||
'no-sequences': 2,
|
||||
'no-throw-literal': 2,
|
||||
'no-unmodified-loop-condition': 2,
|
||||
'no-unused-expressions': 2,
|
||||
'no-unused-labels': 2,
|
||||
'no-useless-call': 2,
|
||||
'no-useless-concat': 2,
|
||||
'no-useless-escape': 2,
|
||||
'no-void': 2,
|
||||
'no-warning-comments': 2,
|
||||
'no-with': 2,
|
||||
'radix': 2,
|
||||
// 'vars-on-top': 2,
|
||||
'wrap-iife': 2,
|
||||
'yoda': [2, 'always'],
|
||||
|
||||
// strict mode
|
||||
'strict': 2,
|
||||
|
||||
// variables
|
||||
'init-declarations': 2,
|
||||
'no-catch-shadow': 2,
|
||||
'no-delete-var': 2,
|
||||
'no-label-var': 2,
|
||||
'no-restricted-globals': 2,
|
||||
'no-shadow': 2,
|
||||
'no-shadow-restricted-names': 2,
|
||||
'no-undef': 2,
|
||||
'no-undef-init': 2,
|
||||
'no-undefined': 2,
|
||||
'no-unused-vars': 2,
|
||||
'no-use-before-define': 2,
|
||||
|
||||
// node.js and commonjs
|
||||
'callback-return': 2,
|
||||
// 'global-require': 2,
|
||||
'handle-callback-err': 2,
|
||||
// 'no-mixed-requires': 2,
|
||||
'no-new-require': 2,
|
||||
'no-path-concat': 2,
|
||||
'no-process-env': 2,
|
||||
'no-process-exit': 2,
|
||||
'no-restricted-modules': 2,
|
||||
// 'no-sync': 2,
|
||||
|
||||
// stylistic issues
|
||||
'array-bracket-spacing': 2,
|
||||
'block-spacing': [2, 'never'],
|
||||
// 'brace-style': [2, 'allman'],
|
||||
'camelcase': 2,
|
||||
'comma-dangle': [2, 'never'],
|
||||
'comma-spacing': 2,
|
||||
'comma-style': 2,
|
||||
'computed-property-spacing': 2,
|
||||
'consistent-this': [2, 'self'],
|
||||
'eol-last': 2,
|
||||
'func-names': [2, 'never'],
|
||||
// 'func-style': 2,
|
||||
'id-blacklist': [2, 'x'],
|
||||
'id-length': [2, {'min': 1, 'max': 50}],
|
||||
'id-match': 2,
|
||||
'indent': [2, 'tab', {
|
||||
'SwitchCase': 1,
|
||||
'VariableDeclarator': {
|
||||
'var': 1,
|
||||
'let': 1,
|
||||
'const': 1
|
||||
}
|
||||
}],
|
||||
'jsx-quotes': 2,
|
||||
'key-spacing': 2,
|
||||
'keyword-spacing': 2,
|
||||
'linebreak-style': [2, 'unix'],
|
||||
// 'lines-around-comment': 2,
|
||||
'max-depth': [2, 10],
|
||||
'max-len': [2, 200],
|
||||
// 'max-lines': 2,
|
||||
'max-nested-callbacks': [2, 5],
|
||||
// 'max-params': 2,
|
||||
// 'max-statements': [2, {'max': 10}, {'ignoreTopLevelFunctions': true}],
|
||||
'max-statements-per-line': 2,
|
||||
'new-cap': 2,
|
||||
'new-parens': 2,
|
||||
// 'newline-after-var': 2,
|
||||
// 'newline-before-return': 2,
|
||||
// 'newline-per-chained-call': 2,
|
||||
'no-array-constructor': 2,
|
||||
'no-bitwise': 2,
|
||||
'no-continue': 2,
|
||||
// 'no-inline-comments': 2,
|
||||
// 'no-lonely-if': 2,
|
||||
// 'no-mixed-operators': 2,
|
||||
'no-mixed-spaces-and-tabs': 2,
|
||||
'no-multiple-empty-lines': [2, {
|
||||
"max": 1,
|
||||
"maxEOF": 1,
|
||||
"maxBOF": 1
|
||||
}],
|
||||
// 'no-negated-condition': 2,
|
||||
// 'no-nested-ternary': 2,
|
||||
'no-new-object': 2,
|
||||
'no-plusplus': [2, {
|
||||
'allowForLoopAfterthoughts': true
|
||||
}],
|
||||
'no-restricted-syntax': 2,
|
||||
'no-spaced-func': 2,
|
||||
'no-ternary': 0,
|
||||
'no-trailing-spaces': 2, // disallow trailing whitespace at the end of lines
|
||||
// 'no-underscore-dangle': 2, // disallow dangling underscores in identifiers
|
||||
'no-unneeded-ternary': 2, // disallow ternary operators when simpler alternatives exist
|
||||
'no-whitespace-before-property': 2,
|
||||
// 'object-curly-newline': 2,
|
||||
'object-curly-spacing': [2, 'never'],
|
||||
'object-property-newline': [2, {'allowMultiplePropertiesPerLine': true}],
|
||||
// 'one-var': [2, {
|
||||
// 'var': 'always',
|
||||
// 'let': 'always',
|
||||
// 'const': 'always'
|
||||
// }],
|
||||
'one-var-declaration-per-line': [2, 'always'],
|
||||
'operator-assignment': 2,
|
||||
'operator-linebreak': [2, 'after'],
|
||||
// 'padded-blocks': [2, 'never'],
|
||||
// 'quote-props': [2, 'as-needed'],
|
||||
'quotes': [2, 'single'],
|
||||
'require-jsdoc': 2,
|
||||
'semi': [2, 'always'],
|
||||
'semi-spacing': 2,
|
||||
// 'sort-vars': 2,
|
||||
'space-before-blocks': 2,
|
||||
'space-before-function-paren': [2, 'never'],
|
||||
'space-in-parens': 2,
|
||||
'space-infix-ops': 2,
|
||||
'space-unary-ops': 2,
|
||||
'spaced-comment': 2,
|
||||
'unicode-bom': [2, 'never'],
|
||||
'wrap-regex': 2,
|
||||
|
||||
// es6
|
||||
'arrow-body-style': [2, 'as-needed'],
|
||||
'arrow-parens': 2,
|
||||
'arrow-spacing': 2,
|
||||
'constructor-super': 2,
|
||||
'generator-star-spacing': 2,
|
||||
'no-class-assign': 2,
|
||||
'no-confusing-arrow': [2, {'allowParens': true}],
|
||||
'no-const-assign': 2,
|
||||
'no-dupe-class-members': 2,
|
||||
'no-duplicate-imports': 2,
|
||||
'no-new-symbol': 2,
|
||||
'no-restricted-imports': 2,
|
||||
'no-this-before-super': 2,
|
||||
'no-useless-computed-key': 2,
|
||||
'no-useless-constructor': 2,
|
||||
'no-useless-rename': 2,
|
||||
'no-var': 2,
|
||||
// 'object-shorthand': 2,
|
||||
'prefer-arrow-callback': 2,
|
||||
'prefer-const': 2,
|
||||
// 'prefer-reflect': 2,
|
||||
|
||||
'prefer-rest-params': 2,
|
||||
'prefer-spread': 2,
|
||||
|
||||
// 'prefer-template': 2,
|
||||
'require-yield': 2,
|
||||
'rest-spread-spacing': 2,
|
||||
'sort-imports': 0, // off
|
||||
'template-curly-spacing': 2,
|
||||
'yield-star-spacing': 2
|
||||
}
|
||||
};
|
||||
|
|
|
|||
25
.flowconfig
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
[ignore]
|
||||
.*/node_modules/.*
|
||||
.*/vendors/.*
|
||||
.*/rainloop/.*
|
||||
.*/plugins/.*
|
||||
.*/build/.*
|
||||
.*/asserts/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
./dev/
|
||||
|
||||
[options]
|
||||
strip_root=true
|
||||
module.system=haste
|
||||
|
||||
esproposal.class_static_fields=enable
|
||||
esproposal.class_instance_fields=enable
|
||||
esproposal.decorators=ignore
|
||||
|
||||
experimental.strict_type_args=true
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
2
.github/FUNDING.yml
vendored
|
|
@ -1,2 +0,0 @@
|
|||
github: the-djmaze
|
||||
custom: ["https://www.paypal.me/thedjmaze", "https://snappymail.eu"]
|
||||
2
.github/ISSUE_TEMPLATE.md
vendored
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
**SnappyMail version, browser, browser version:**
|
||||
**RainLoop version, browser, OS:**
|
||||
|
||||
**Expected behavior and actual behavior:**
|
||||
|
||||
|
|
|
|||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Please complete the following information:**
|
||||
- Browser: [e.g. chromium 100, firefox 100, safari 14, mobile]
|
||||
- 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)
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
93
.github/workflows/docker-pr.yml
vendored
|
|
@ -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
|
||||
117
.github/workflows/docker.yml
vendored
|
|
@ -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
|
||||
42
.gitignore
vendored
|
|
@ -1,32 +1,24 @@
|
|||
*.bak
|
||||
*.old
|
||||
/.idea
|
||||
/.vscode
|
||||
/api.php
|
||||
/*.log
|
||||
/snappymail/v/0.0.0/static/*
|
||||
/error.log
|
||||
/nbproject
|
||||
/npm-debug.log
|
||||
/rainloop.sublime-project
|
||||
/rainloop.sublime-workspace
|
||||
/rainloop/v/0.0.0/static/*
|
||||
/rainloop/v/0.0.0/app/localization/moment/*
|
||||
!/rainloop/v/0.0.0/app/localization/moment/.gitempty
|
||||
/tests/e2e/configuration.js
|
||||
/tests/e2e/output/*
|
||||
!/tests/e2e/output/.gitempty
|
||||
/vendors/.*
|
||||
/node_modules
|
||||
/build/local
|
||||
/build/dist
|
||||
/build/tmp
|
||||
/build/docker
|
||||
/.docker/dev/.cache
|
||||
/.docker/dev/mail/config
|
||||
/.docker/dev/nginx/ssl/*
|
||||
!/.docker/dev/nginx/ssl/.gitempty
|
||||
/.docker/release/snappymail-*.zip
|
||||
/dist
|
||||
/data
|
||||
.DS_Store
|
||||
/tests/fix.php
|
||||
/MULTIPLY
|
||||
/include.php
|
||||
/issues
|
||||
.idea/
|
||||
.env
|
||||
/test
|
||||
/public_html
|
||||
/vendors/knockout/spec
|
||||
/vendors/openpgp-5
|
||||
!/vendors/openpgp-5/dist
|
||||
/vendors/squire2
|
||||
!/vendors/squire2/dist
|
||||
/vendors/vanillaqr.js/
|
||||
/integrations/nextcloud/rainloop
|
||||
/integrations/owncloud/rainloop
|
||||
/include.php
|
||||
7
.gitmodules
vendored
|
|
@ -1,7 +0,0 @@
|
|||
[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
|
||||
51
.htaccess
|
|
@ -1,51 +0,0 @@
|
|||
<FilesMatch "index\.php">
|
||||
AcceptPathInfo On
|
||||
</FilesMatch>
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
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]
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresByType text/css A15768000
|
||||
ExpiresByType text/html A15768000
|
||||
ExpiresByType application/javascript A15768000
|
||||
ExpiresByType image/gif A15768000
|
||||
ExpiresByType image/jpeg A15768000
|
||||
ExpiresByType image/png A15768000
|
||||
ExpiresByType image/svg+xml A15768000
|
||||
ExpiresByType image/webp A15768000
|
||||
ExpiresByType image/vnd.microsoft.icon A15768000
|
||||
ExpiresByType font/woff A15768000
|
||||
ExpiresByType font/woff2 A15768000
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
# Header set Cache-Control "public, max-age=31536000"
|
||||
# Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; style-src 'self' 'unsafe-inline'"
|
||||
# Header set Referrer-Policy "no-referrer"
|
||||
# Header set Strict-Transport-Security "max-age=31536000"
|
||||
Header set imagetoolbar "no"
|
||||
# Header set X-Content-Type-Options "nosniff"
|
||||
# Header set X-XSS-Protection "1; mode=block"
|
||||
Header set Service-Worker-Allowed "/"
|
||||
|
||||
# Google FLoC
|
||||
# Header set Permissions-Policy "interest-cohort=()"
|
||||
</IfModule>
|
||||
|
||||
#<IfModule mod_brotli.c>
|
||||
# AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/javascript
|
||||
#</IfModule>
|
||||
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/css text/html text/plain text/xml application/xml text/javascript application/javascript
|
||||
AddOutputFilterByType DEFLATE font/opentype font/otf font/ttf font/woff
|
||||
</IfModule>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
*.*
|
||||
!/dev/**/*.js
|
||||
!/tasks/**/*.js
|
||||
!/*.js
|
||||
26
.prettierrc
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"printWidth": 120,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"useTabs": true,
|
||||
"bracketSpacing": true,
|
||||
"trailingComma": "none",
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"quoteProps": "preserve",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.js",
|
||||
"options": {
|
||||
"parser": "babel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.jsx",
|
||||
"options": {
|
||||
"parser": "babel"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
16
.scrutinizer.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
filter:
|
||||
path:
|
||||
- 'rainloop-webmail/rainloop/v/0.0.0/app/libraries/MailSo/*'
|
||||
- 'rainloop-webmail/rainloop/v/0.0.0/app/libraries/RainLoop/*'
|
||||
- 'dev/*'
|
||||
- '/*.js'
|
||||
excluded_paths:
|
||||
- '*.min.js'
|
||||
- '*/min/*'
|
||||
- '*.min.css'
|
||||
- 'vendors/*'
|
||||
- 'build/*'
|
||||
- 'data/*'
|
||||
checks:
|
||||
javascript: true
|
||||
php: true
|
||||
13
.travis.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
language: php
|
||||
php:
|
||||
- '5.3'
|
||||
- '5.4'
|
||||
- '5.5'
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
#before_script:
|
||||
# - sudo apt-get install -y build-essential libssl-dev
|
||||
# - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
|
||||
# - nvm install 4.4.5
|
||||
# - nvm use 4.4.5
|
||||
# - npm install -g eslint babel-eslint
|
||||
14
.tx/config
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
type = YAML
|
||||
minimum_perc = 60
|
||||
|
||||
[rainloop-webmail.rainloop-webmail]
|
||||
file_filter = rainloop/v/0.0.0/app/localization/webmail/<lang>.yml
|
||||
source_file = rainloop/v/0.0.0/app/localization/webmail/_source.en.yml
|
||||
source_lang = en
|
||||
|
||||
[rainloop-webmail.rainloop-admin]
|
||||
file_filter = rainloop/v/0.0.0/app/localization/admin/<lang>.yml
|
||||
source_file = rainloop/v/0.0.0/app/localization/admin/_source.en.yml
|
||||
source_lang = en
|
||||
2422
CHANGELOG.md
|
|
@ -1,130 +0,0 @@
|
|||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[support@snappymail.eu](support@snappymail.eu).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
|
||||
|
|
@ -1,47 +1,21 @@
|
|||
**Thanks for contributing to SnappyMail Webmail!**
|
||||
|
||||
1. Fork the repo, do work in a feature branch.
|
||||
2. Issue a pull request.
|
||||
|
||||
---
|
||||
|
||||
**Getting started**
|
||||
|
||||
1. Install PHP
|
||||
2. Install node.js - `https://nodejs.org/download/`
|
||||
3. Install yarn - `https://yarnpkg.com/en/docs/install`
|
||||
4. Install gulp - `npm install gulp -g`
|
||||
5. Fork snappymail from https://github.com/the-djmaze/snappymail
|
||||
6. Clone snappymail - `git clone git@github.com:USERNAME/snappymail.git snappymail`
|
||||
7. `cd snappymail`
|
||||
8. Install all dependencies - `yarn install`
|
||||
9. Run gulp - `gulp`
|
||||
|
||||
---
|
||||
|
||||
**Debugging JavaScript**
|
||||
|
||||
1. Edit data/\_data_/\_default_/configs/application.ini
|
||||
2. Set 'use_app_debug_js' (and optionally 'use_app_debug_css') to 'On'
|
||||
|
||||
---
|
||||
|
||||
**Editing HTML Template Files**
|
||||
|
||||
1. Edit data/\_data_/\_default_/configs/application.ini
|
||||
2. Set `[cache] system_data` to Off
|
||||
|
||||
**Release**
|
||||
|
||||
1. Install gzip
|
||||
2. Install brotli
|
||||
3. php release.php
|
||||
|
||||
Options:
|
||||
* `php release.php --aur` = Build Arch Linux package
|
||||
* `php release.php --docker` = Build Docker instance
|
||||
* `php release.php --plugins` = Build plugins
|
||||
|
||||
---
|
||||
|
||||
If you have any questions, open an issue or email support@snappymail.eu.
|
||||
**Thanks for contributing to RainLoop Webmail!**
|
||||
|
||||
1. Sign the CLA (individual or corporate) at <http://www.rainloop.net/contribute/>.
|
||||
2. Fork the repo, do work in a feature branch.
|
||||
3. Issue a pull request.
|
||||
|
||||
---
|
||||
|
||||
**Getting started**
|
||||
|
||||
1. Install node.js - `https://nodejs.org/download/`
|
||||
2. Install gulp - `npm install gulp -g`
|
||||
3. Fork rainloop - `https://github.com/RainLoop/rainloop-webmail/issues/new#fork-destination-box`
|
||||
4. Clone rainloop - `git clone git@github.com:USERNAME/rainloop-webmail.git rainloop`
|
||||
5. `cd rainloop`
|
||||
6. Install gulp add gulp plugins into project directory - `npm install`
|
||||
7. Run gulp - `gulp`
|
||||
|
||||
---
|
||||
|
||||
If you have any questions, open an issue or email support@rainloop.net.
|
||||
|
|
|
|||
2
LICENSE
|
|
@ -658,4 +658,4 @@ specific requirements.
|
|||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<http://www.gnu.org/licenses/>.
|
||||
76
Makefile
|
|
@ -1,76 +0,0 @@
|
|||
#!make
|
||||
|
||||
rebuild: _down
|
||||
docker compose build --no-cache
|
||||
|
||||
up: _up status
|
||||
_up:
|
||||
docker compose up -d
|
||||
|
||||
stop: _stop status
|
||||
_stop:
|
||||
docker compose stop
|
||||
|
||||
down: _down status
|
||||
_down:
|
||||
docker compose down
|
||||
|
||||
restart: _stop _up status
|
||||
|
||||
status:
|
||||
@docker compose ps
|
||||
|
||||
tx:
|
||||
@docker compose run --no-deps --rm tx tx pull -a -s -f -d
|
||||
|
||||
console-node:
|
||||
@docker compose run --no-deps --rm node sh
|
||||
console-tx:
|
||||
@docker compose run --no-deps --rm tx sh
|
||||
console-php:
|
||||
@docker compose exec php sh
|
||||
console: console-node
|
||||
|
||||
logs:
|
||||
@docker compose logs --tail=100 -f
|
||||
logs-db:
|
||||
@docker compose logs --tail=100 -f db
|
||||
logs-php:
|
||||
@docker compose logs --tail=100 -f php
|
||||
logs-node:
|
||||
@docker compose logs --tail=100 -f node
|
||||
logs-nginx:
|
||||
@docker compose logs --tail=100 -f nginx
|
||||
logs-mail:
|
||||
@docker compose logs --tail=100 -f mail
|
||||
logs-tx:
|
||||
@docker compose logs --tail=100 -f tx
|
||||
|
||||
rl-lint:
|
||||
@docker compose run --no-deps --rm node gulp lint
|
||||
rl-dev:
|
||||
@docker compose run --no-deps --rm node npm run watch-js
|
||||
rl-compile:
|
||||
@docker compose run --no-deps --rm node gulp build
|
||||
rl-compile-with-source:
|
||||
@docker compose run --no-deps --rm node gulp build --source
|
||||
rl-watch-css:
|
||||
@docker compose run --no-deps --rm node npm run watch-css
|
||||
rl-watch-js:
|
||||
@docker compose run --no-deps --rm node npm run watch-js
|
||||
|
||||
rl-build:
|
||||
@docker compose run --no-deps --rm node gulp all
|
||||
|
||||
yarn-install:
|
||||
@docker compose run --no-deps --rm node yarn install
|
||||
yarn-outdated:
|
||||
@docker compose run --no-deps --rm node yarn outdated
|
||||
yarn-upgrade:
|
||||
@docker compose run --no-deps --rm node yarn upgrade-interactive --exact --latest
|
||||
|
||||
gpg:
|
||||
docker run -it --rm -w=/var/www \
|
||||
-v $(shell pwd)/.docker/.cache/.gnupg:/root/.gnupg \
|
||||
-v $(shell pwd):/var/www \
|
||||
ubuntu:16.04 bash
|
||||
227
README.md
|
|
@ -1,226 +1,23 @@
|
|||
<div align="center">
|
||||
<a href="https://github.com/the-djmaze/snappymail">
|
||||
<img src="https://snappymail.eu/static/img/logo-256x256-white.png">
|
||||
</a>
|
||||
<br>
|
||||
<h1>SnappyMail</h1>
|
||||
<br>
|
||||
RainLoop Webmail [](https://travis-ci.org/RainLoop/rainloop-webmail) [](https://david-dm.org/RainLoop/rainloop-webmail?type=dev)
|
||||
==================
|
||||
|
||||
[](https://github.com/the-djmaze/snappymail/actions/workflows/docker.yml)
|
||||
[](https://hub.docker.com/r/djmaze/snappymail/tags)
|
||||
Simple, modern & fast web-based email client.
|
||||
|
||||
<p>
|
||||
Simple, modern, lightweight & fast web-based email client.
|
||||
</p>
|
||||
<p>
|
||||
The drastically upgraded & secured fork of <a href="https://github.com/RainLoop/rainloop-webmail">RainLoop Webmail Community edition</a>.
|
||||
</p>
|
||||
<p>
|
||||
We thank the RainLoop Team for making a great PHP 5 product that was good in the past.
|
||||
</p>
|
||||
<p>
|
||||
Up to date system requirements, snappy performance, simple installation and upgrade, no database required
|
||||
- all these make SnappyMail a good choice.
|
||||
</p>
|
||||
<h2></h2>
|
||||
<br>
|
||||
</div>
|
||||
Modest system requirements, decent performance, simple installation and upgrade, no database required - all these make RainLoop Webmail a perfect choice for your email solution.
|
||||
|
||||
For more information about the product, check [snappymail.eu](https://snappymail.eu/).
|
||||
For more information about the product, check [rainloop.net](http://www.rainloop.net/).
|
||||
|
||||
Information about installing the product, check the [wiki page](https://github.com/the-djmaze/snappymail/wiki/Installation-instructions).
|
||||
Information about installing the product, check the [documentation page](http://www.rainloop.net/docs/installation/).
|
||||
|
||||
And don't forget to read the whole [Wiki](https://github.com/the-djmaze/snappymail/wiki).
|
||||
## Attention
|
||||
|
||||
This is **NOT** a stable version of RainLoop Webmail.
|
||||
It's not recommended to use in production environment.
|
||||
|
||||
## License
|
||||
|
||||
**SnappyMail** is released under
|
||||
**RainLoop Webmail (Community edition)** is released under
|
||||
**GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL)**.
|
||||
http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
Copyright (c) 2020 - 2024 SnappyMail
|
||||
Copyright (c) 2013 - 2022 RainLoop
|
||||
|
||||
## Modifications
|
||||
|
||||
This fork of RainLoop has the following changes:
|
||||
|
||||
* Privacy/GDPR friendly (no: Social, Gravatar, Facebook, Google, Twitter, DropBox, X-Mailer)
|
||||
* Admin uses password_hash/password_verify
|
||||
* Auth failed attempts written to syslog
|
||||
* Added Fail2ban instructions
|
||||
* ES2020
|
||||
* PHP 7.4+ required
|
||||
* PHP mbstring extension required
|
||||
* PHP replaced pclZip with PharData and ZipArchive
|
||||
* Dark mode
|
||||
* Added option to remove background/font colors from messages for real "dark mode"
|
||||
* Removed BackwardCapability (class \RainLoop\Account)
|
||||
* Removed ChangePassword (re-implemented as plugin)
|
||||
* Removed POP3 support
|
||||
* Removed background video support
|
||||
* Removed Sentry (Application Monitoring and Error Tracking Software)
|
||||
* Removed Spyc yaml
|
||||
* Removed OwnCloud
|
||||
* Replaced gulp-uglify with gulp-terser
|
||||
* CRLF => LF line endings
|
||||
* Embed boot.js and boot.css into index.html
|
||||
* Removal of old JavaScript code (things are native these days)
|
||||
* Added modified [Squire](https://github.com/the-djmaze/Squire/tree/snappymail) HTML editor as replacement for CKEditor
|
||||
* Updated [Sabre/VObject](https://github.com/sabre-io/vobject)
|
||||
* Split Admin specific JavaScript code from User code
|
||||
* Split Sieve specific JavaScript code from User code
|
||||
* JSON reviver
|
||||
* Better memory garbage collection management
|
||||
* Added serviceworker for Notifications
|
||||
* Added advanced Sieve scripts editor
|
||||
* Slimmed down language files
|
||||
* Replaced webpack with rollup
|
||||
* No user-agent detection (use device width)
|
||||
* Added support to load plugins as .phar
|
||||
* Replaced old Sabre library
|
||||
* AddressBook Contacts support MySQL/MariaDB utf8mb4
|
||||
* Added [Fetch Metadata Request Headers](https://www.w3.org/TR/fetch-metadata/) checks
|
||||
* Reduced excessive DOM size
|
||||
* Support [Kolab groupware](https://kolab.org/)
|
||||
* Support many more [IMAP RFC's](https://snappymail.eu/comparison#IMAP)
|
||||
* Support Sodium and OpenSSL for encryption
|
||||
* Much better PGP support
|
||||
|
||||
|
||||
### Supported browsers
|
||||
|
||||
This fork uses downsized/simplified versions of scripts and has no support for Internet Explorer nor Edge Legacy.
|
||||
Supported are:
|
||||
|
||||
* Chrome 80+
|
||||
* Edge 80+
|
||||
* Firefox 78+
|
||||
* Opera 67+
|
||||
* Safari 13.1+
|
||||
|
||||
|
||||
### Removal of old JavaScript
|
||||
|
||||
The result is faster and smaller download code (good for mobile networks).
|
||||
|
||||
* Added dev/prototype.js for some additional features
|
||||
* Modified Jua.js to be without jQuery
|
||||
* Replaced Autolinker with simple https/email detection
|
||||
* Replaced momentToNode with proper HTML5 `<time>`
|
||||
* Replaced resize listeners with ResizeObserver
|
||||
* Replaced bootstrap.js with native drop-in replacement
|
||||
* Replaced dev/Common/ClientStorageDriver/* with Web Storage Objects polyfill
|
||||
* Replaced *Ajax with *Fetch classes because we use the Fetch API, not jQuery.ajax
|
||||
* Replaced [knockoutjs](https://github.com/knockout/knockout) 3.4 with a modified 3.5.1
|
||||
* Replaced knockout-sortable with native HTML5 drag&drop
|
||||
* Replaced simplestatemanager with CSS @media
|
||||
* Replaced inputosaurus with own code
|
||||
* Replaced keymaster with own shortcuts handler
|
||||
* Replaced OpenPGP.js v2 with OpenPGP.js v5
|
||||
* Removed ifvisible.js
|
||||
* Removed pikaday
|
||||
* Removed underscore
|
||||
* Removed polyfills
|
||||
* Removed Modernizr
|
||||
* Removed nanoscroll
|
||||
* Removed lightgallery
|
||||
* Removed jQuery
|
||||
* Removed jquery-ui
|
||||
* Removed jquery-scrollstop
|
||||
* Removed jquery-mousewheel
|
||||
* Removed matchmedia-polyfill
|
||||
* Removed momentjs (use Intl)
|
||||
* Removed opentip (use CSS)
|
||||
* Removed non-community (aka Prem/Premium/License) code
|
||||
* Removed ProgressJS
|
||||
|
||||
|
||||
RainLoop 1.17 vs SnappyMail
|
||||
|
||||
|js/* |RainLoop |Snappy |
|
||||
|--------------- |--------: |--------: |
|
||||
|admin.js |2.170.153 | 84.925 |
|
||||
|app.js |4.207.787 | 447.263 |
|
||||
|boot.js | 868.735 | 4.343 |
|
||||
|libs.js | 658.812 | 233.728 |
|
||||
|sieve.js | 0 | 91.418 |
|
||||
|polyfills.js | 334.608 | 0 |
|
||||
|serviceworker.js | 0 | 285 |
|
||||
|TOTAL |8.240.095 | 861.962 |
|
||||
|
||||
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|
||||
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|
||||
|admin.min.js | 256.831 | 41.719 | 73.606 | 14.022 | 60.877 | 12.567 |
|
||||
|app.min.js | 515.367 | 202.101 |139.456 | 68.505 |110.485 | 58.481 |
|
||||
|boot.min.js | 84.659 | 2.231 | 26.998 | 1.271 | 23.643 | 1.067 |
|
||||
|libs.min.js | 584.772 | 110.646 |180.901 | 39.518 |155.182 | 35.207 |
|
||||
|sieve.min.js | 0 | 45.504 | 0 | 11.131 | 0 | 9.917 |
|
||||
|polyfills.min.js | 32.837 | 0 | 11.406 | 0 | 10.175 | 0 |
|
||||
|TOTAL user |1.217.635 | 314.978 |358.761 |109.294 |299.485 | 94.755 |
|
||||
|TOTAL user+sieve |1.217.635 | 360.482 |358.761 |120.425 |299.485 |104.672 |
|
||||
|TOTAL admin | 959.099 | 154.596 |292.911 | 54.811 |249.877 | 48.841 |
|
||||
|
||||
For a user it is around 66% smaller and faster than traditional RainLoop.
|
||||
|
||||
### CSS changes
|
||||
|
||||
* Solve jQuery removed "features" with native css code
|
||||
* Themes work in mobile mode
|
||||
* Bugfix invalid/conflicting css rules
|
||||
* Use flexbox
|
||||
* Use border-box
|
||||
* Split app.css to have separate admin.css
|
||||
* Remove oldschool 'float'
|
||||
* Remove unused css
|
||||
* Removed html.no-css
|
||||
* Removed dev/Styles/Cmd.less
|
||||
* Removed dev/Styles/Scroll.less
|
||||
* Removed Internet Explorer from normalize.css
|
||||
* Removed node_modules/opentip/css/opentip.css
|
||||
* Removed node_modules/pikaday/css/pikaday.css
|
||||
* Removed unused vendors/bootstrap/less/*
|
||||
* Removed vendors/jquery-nanoscroller/nanoscroller.css
|
||||
* Removed vendors/jquery-letterfx/jquery-letterfx.min.css
|
||||
* Removed vendors/Progress.js/minified/progressjs.min.css
|
||||
* Removed gulp-autoprefixer
|
||||
|
||||
|
||||
|css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli |
|
||||
|------------ |-------: |------: |------: |------: |--------: |
|
||||
|app.css | 340.331 | 85.073 | 46.946 | 17.792 | 15.210 |
|
||||
|app.min.css | 274.947 | 68.272 | 39.647 | 15.615 | 13.636 |
|
||||
|boot.css | | 1.326 | | 664 | 545 |
|
||||
|boot.min.css | | 1.071 | | 590 | 474 |
|
||||
|admin.css | | 30.880 | | 7.045 | 6.127 |
|
||||
|admin.min.css | | 24.959 | | 6.368 | 5.615 |
|
||||
|
||||
### PGP
|
||||
RainLoop uses the old OpenPGP.js v2
|
||||
SnappyMail v2.12 uses OpenPGP.js v5, GnuPG and Mailvelope.
|
||||
SnappyMail is able to use and generate ECDSA and EDDSA keys, where RainLoop does not.
|
||||
|
||||
Since SnappyMail tries to achieve the best mobile experience, it forked OpenPGP.js to strip it down.
|
||||
* remove all unused Node.js
|
||||
* remove all old browsers support
|
||||
See https://github.com/the-djmaze/openpgpjs for development
|
||||
|
||||
|OpenPGP |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|
||||
|--------------- |--------: |--------: |------: |-------: |--------: |--------: |
|
||||
|openpgp.min.js | 330.742 | 546.165 |102.388 | 169.207 | 84.241 | 138.688 |
|
||||
|openpgp.worker | 1.499 | | 824 | | 695 | |
|
||||
|
||||
|
||||
### Squire vs CKEditor
|
||||
The [Squire](https://github.com/neilj/Squire) implementation is not 100% compatible yet, but it shows the massive overhead of CKEditor.
|
||||
|
||||
Still TODO:
|
||||
|
||||
* support for tables (really needed?!?)
|
||||
|
||||
| | normal | min | gzip | min gzip |
|
||||
|-------- |-------: |-------: |------: |--------: |
|
||||
|squire | 122.321 | 41.906 | 31.867 | 14.330 |
|
||||
|ckeditor | ? | 520.035 | ? | 155.916 |
|
||||
|
||||
CKEditor including the 7 asset requests (css,language,plugins,icons) is 633.46 KB / 180.47 KB (gzip).
|
||||
Copyright (c) 2016 Rainloop Team
|
||||
|
|
|
|||
40
SECURITY.md
|
|
@ -1,40 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Currently due to the fast development only the latest version receives security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| -------- | --------- |
|
||||
| 2.34.x | ✔ |
|
||||
| < 2.34.0 | ❌ |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security issues or vulnerabilities as an encrypted email to [security@snappymail.eu](mailto:security@snappymail.eu).
|
||||
Your report should be detailed enough with clear steps to reproduce and classify the found vulnerability.
|
||||
|
||||
You can find the PGP public key below and on the major public keyservers like [keys.openpgp.org](https://keys.openpgp.org).
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Type: 255-bit EdDSA
|
||||
Comment: Fingerprint: 445D265124E6072671E64D0733F868A7E35E8277
|
||||
|
||||
mDMEYiE2QRYJKwYBBAHaRw8BAQdAqMrQUm6DddWcQNo0VEjNIu3Q6CfP3nokVv2Y
|
||||
rNQ1avq0LFNuYXBweU1haWwgU2VjdXJpdHkgPHNlY3VyaXR5QHNuYXBweW1haWwu
|
||||
ZXU+iJQEExYKADwWIQREXSZRJOYHJnHmTQcz+Gin416CdwUCYiE2QQIbAwULCQgH
|
||||
AgMiAgEGFQoJCAsCBBYCAwECHgcCF4AACgkQM/hop+NegnfSGgD9GEHpOrvWpBGY
|
||||
dYfvVd/+Lv5d+dFBcPyki9zu9zHfhwkBAL343EF6ZR0XwMlOQu9wu0hT9KBz4g55
|
||||
6D41i0PrEaoBuDgEYiE2QRIKKwYBBAGXVQEFAQEHQMMr9gcVcJ3aiup/tpl8ZXxy
|
||||
aJiJRGkPyNwGI5vxHMpZAwEIB4h4BBgWCgAgFiEERF0mUSTmByZx5k0HM/hop+Ne
|
||||
gncFAmIhNkECGwwACgkQM/hop+NegndVhgD/SVGSKbF4G2W024VpW2tm3zCT+ue+
|
||||
YMXQVq4SJt7UpWABAORudfJxsBqCRKtPlZMgGTJLjcOkyFJ9C2Fx7DeN0J4I
|
||||
=nSOi
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
|
||||
## Publishing and Credits
|
||||
|
||||
I will analyze and fix the reported issue as fast as possible.
|
||||
Together with the reporter, I plan the disclosure of the found and fixed vulnerability.
|
||||
Credits to the reporter are granted and can be included in all public communication if desired.
|
||||
1
_MULTIPLY
Normal file
|
|
@ -0,0 +1 @@
|
|||
Rename this file to "MULTIPLY" to enable multiple domain installation
|
||||
36
_include.php
|
|
@ -1,31 +1,21 @@
|
|||
<?php
|
||||
|
||||
// Name this file as "include.php" to enable it.
|
||||
|
||||
//header('Strict-Transport-Security: max-age=31536000');
|
||||
// Rename this file to "include.php" to enable it.
|
||||
|
||||
/**
|
||||
* Uncomment to enable multiple domain installation.
|
||||
* @return string
|
||||
*/
|
||||
//define('MULTIDOMAIN', 1);
|
||||
function __get_custom_data_full_path()
|
||||
{
|
||||
return '';
|
||||
return '/var/external-rainloop-data-folder/'; // custom data folder path
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncomment to disable APCU.
|
||||
* @return string
|
||||
*/
|
||||
//define('APP_USE_APCU_CACHE', false);
|
||||
|
||||
/**
|
||||
* Custom 'data' folder path
|
||||
*/
|
||||
//define('APP_DATA_FOLDER_PATH', dirname(__DIR__) . '/snappymail-data/');
|
||||
//define('APP_DATA_FOLDER_PATH', '/var/external-snappymail-data-folder/');
|
||||
|
||||
/**
|
||||
* Additional configuration file name
|
||||
*/
|
||||
//define('APP_CONFIGURATION_NAME', $_SERVER['HTTP_HOST'].'.ini');
|
||||
|
||||
/**
|
||||
* Also update extensions on upgrade
|
||||
*/
|
||||
//define('SNAPPYMAIL_UPDATE_PLUGINS', 1);
|
||||
function __get_additional_configuration_name()
|
||||
{
|
||||
return '';
|
||||
return defined('APP_SITE') && 0 < strlen(APP_SITE) ? APP_SITE.'.ini' : ''; // additional configuration file name
|
||||
}
|
||||
|
|
|
|||
BIN
asserts/android-icon.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
asserts/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 832 B |
BIN
asserts/browsers/chrome.gif
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
asserts/browsers/firefox.gif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
asserts/browsers/opera.gif
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
asserts/browsers/safari.gif
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
asserts/css/default-skin.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
38
asserts/css/default-skin.svg
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="264px" height="88px" viewBox="0 0 264 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.0 (7574) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>default-skin 2</title>
|
||||
<description>Created with Sketch.</description>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="default-skin" sketch:type="MSLayerGroup">
|
||||
<path d="M67.0018835,59.5 L67.0018835,63.268331 C60.6953142,64.1065038 57.8175182,69.0186795 57,73 C59.2189781,70.171167 62.5639273,67.9024591 67.0018835,67.9024591 L67.0018835,71.5 L73,65.5853951 L67.0018835,59.5 Z" id="Shape" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
|
||||
<g id="Group" transform="translate(13.000000, 15.000000)" fill="#FFFFFF" sketch:type="MSShapeGroup">
|
||||
<path d="M0,14 L0,9 L2,9 L2,12 L5,12 L5,14 L0,14 Z" id="Shape"></path>
|
||||
<path d="M0,0 L5,0 L5,2 L2,2 L2,5 L0,5 L0,0 Z" id="Shape"></path>
|
||||
<path d="M18,0 L18,5 L16,5 L16,2 L15.2629743,2 L13,2 L13,0 L18,0 Z" id="Shape"></path>
|
||||
<path d="M18,14 L13,14 L13,12 L16,12 L16,9 L18,9 L18,14 Z" id="Shape"></path>
|
||||
</g>
|
||||
<g id="Group-4" transform="translate(57.000000, 15.000000)" fill="#FFFFFF" sketch:type="MSShapeGroup">
|
||||
<path d="M0,14 L0,9 L2,9 L2,12 L5,12 L5,14 L0,14 Z" id="Shape" transform="translate(2.500000, 11.500000) rotate(-180.000000) translate(-2.500000, -11.500000) "></path>
|
||||
<path d="M0,0 L5,0 L5,2 L2,2 L2,5 L0,5 L0,0 Z" id="Shape" transform="translate(2.500000, 2.500000) rotate(-180.000000) translate(-2.500000, -2.500000) "></path>
|
||||
<path d="M18,0 L18,5 L16,5 L16,2 L15.2629743,2 L13,2 L13,0 L18,0 Z" id="Shape" transform="translate(15.500000, 2.500000) rotate(-180.000000) translate(-15.500000, -2.500000) "></path>
|
||||
<path d="M18,14 L13,14 L13,12 L16,12 L16,9 L18,9 L18,14 Z" id="Shape" transform="translate(15.500000, 11.500000) rotate(-180.000000) translate(-15.500000, -11.500000) "></path>
|
||||
</g>
|
||||
<path d="M21,65 L21,57 L23,57 L23,65 L31,65 L31,67 L23,67 L23,75 L21,75 L21,67 L13,67 L13,65 L21,65 Z" id="Rectangle-13" fill="#FFFFFF" sketch:type="MSShapeGroup" transform="translate(22.000000, 66.000000) rotate(-45.000000) translate(-22.000000, -66.000000) "></path>
|
||||
<path d="M111.784738,65.0291574 L110,63.5 L113,60 L103,60 L103,58 L113,58 L110,54.5 L111.784738,53.0320871 L117,59 L111.784738,65.0291574 Z" id="Shape-3" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M155.784738,65.0291574 L154,63.5 L157,60 L147,60 L147,58 L157,58 L154,54.5 L155.784738,53.0320871 L161,59 L155.784738,65.0291574 Z" id="Shape-4" fill="#FFFFFF" sketch:type="MSShapeGroup" transform="translate(154.000000, 59.000000) scale(-1, 1) translate(-154.000000, -59.000000) "></path>
|
||||
<g id="Group-2" transform="translate(147.000000, 16.000000)" sketch:type="MSShapeGroup">
|
||||
<rect id="Rectangle-11" fill="#FFFFFF" transform="translate(11.767767, 11.767767) scale(-1, 1) rotate(-45.000000) translate(-11.767767, -11.767767) " x="9.67157286" y="10.767767" width="4.59619409" height="2"></rect>
|
||||
<path d="M5.5,11 C8.53756612,11 11,8.53756612 11,5.5 C11,2.46243388 8.53756612,0 5.5,0 C2.46243388,0 0,2.46243388 0,5.5 C0,8.53756612 2.46243388,11 5.5,11 Z" id="Oval-1" stroke="#FFFFFF" stroke-width="1.5"></path>
|
||||
<rect id="Rectangle-12" fill="#FFFFFF" x="3" y="5" width="5" height="1"></rect>
|
||||
</g>
|
||||
<g id="Group-3" transform="translate(103.000000, 16.000000)" sketch:type="MSShapeGroup">
|
||||
<path d="M13.9571068,12.5428932 L12.5428932,13.9571068 L9.29289322,10.7071068 L10.7071068,9.29289322 L13.9571068,12.5428932 Z" id="Rectangle-11" fill="#FFFFFF"></path>
|
||||
<path d="M5.5,11 C8.53756612,11 11,8.53756612 11,5.5 C11,2.46243388 8.53756612,0 5.5,0 C2.46243388,0 0,2.46243388 0,5.5 C0,8.53756612 2.46243388,11 5.5,11 Z" id="Oval-1" stroke="#FFFFFF" stroke-width="1.5"></path>
|
||||
<rect id="Rectangle-17" fill="#FFFFFF" x="3" y="5" width="5" height="1"></rect>
|
||||
<rect id="Rectangle-16" fill="#FFFFFF" transform="translate(5.500000, 5.500000) rotate(-269.000000) translate(-5.500000, -5.500000) " x="3" y="5" width="5" height="1"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
BIN
asserts/css/flags.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
asserts/css/images/editor.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
asserts/css/images/empty-contact.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
asserts/css/images/grey.png
Normal file
|
After Width: | Height: | Size: 109 B |
BIN
asserts/css/images/icom-message-notification.png
Normal file
|
After Width: | Height: | Size: 832 B |
BIN
asserts/css/images/loading.gif
Normal file
|
After Width: | Height: | Size: 869 B |
BIN
asserts/css/images/rainloop-logo.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
asserts/css/images/sync.gif
Normal file
|
After Width: | Height: | Size: 847 B |
BIN
asserts/css/images/sync.png
Normal file
|
After Width: | Height: | Size: 356 B |
BIN
asserts/css/images/white.png
Normal file
|
After Width: | Height: | Size: 110 B |
BIN
asserts/css/img/loading.gif
Normal file
|
After Width: | Height: | Size: 869 B |
BIN
asserts/css/loading.gif
Normal file
|
After Width: | Height: | Size: 869 B |
BIN
asserts/css/preloader.gif
Normal file
|
After Width: | Height: | Size: 869 B |
BIN
asserts/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
asserts/favicon.png
Normal file
|
After Width: | Height: | Size: 832 B |
16
asserts/manifest.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "RainLoop Webmail",
|
||||
"short_name": "RainLoop",
|
||||
"description": "Simple, modern & fast web-based email client",
|
||||
"display": "standalone",
|
||||
"icons": [{
|
||||
"src": "apple-touch-icon.png",
|
||||
"sizes": "64x64",
|
||||
"type": "image/png"
|
||||
}, {
|
||||
"src": "android-icon.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}],
|
||||
"start_url": "../../../../"
|
||||
}
|
||||
BIN
asserts/sounds/new-mail.mp3
Normal file
BIN
asserts/sounds/new-mail.ogg
Normal file
|
|
@ -1,9 +0,0 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYg0atBYJKwYBBAHaRw8BAQdA2S2tvGavChACjtBastsKRThD3rsBW1LUZLmN
|
||||
Zbs4uaG0I1NuYXBweU1haWwgPHJlbGVhc2VzQHNuYXBweW1haWwuZXU+iJQEExYK
|
||||
ADwWIQQQFuRweRRVQvi6EzVIIIuhMpDz6wUCYg0atAIbAwULCQgHAgMiAgEGFQoJ
|
||||
CAsCBBYCAwECHgcCF4AACgkQSCCLoTKQ8+u9SAD/Q/IoAwjUkKDJBPq0RGwCFnl6
|
||||
FG/VHB97CvBSpGOxtIsBAMCwMhWlsaBHAEqbzxiN+cdlMYwV23+SWLUJ/XMFgukE
|
||||
=5ZwF
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
# Maintainer: George Rawlinson <george@rawlinson.net.nz>
|
||||
|
||||
pkgname=snappymail
|
||||
pkgver=2.7.2
|
||||
pkgrel=1
|
||||
pkgdesc="modern PHP webmail client"
|
||||
arch=('any')
|
||||
license=('AGPL3')
|
||||
url="https://github.com/the-djmaze/snappymail"
|
||||
depends=('php-fpm')
|
||||
makedepends=('php', 'nodejs' 'yarn' 'gulp', 'rollup')
|
||||
optdepends=('mariadb: storage backend for contacts'
|
||||
'php-pgsql: storage backend for contacts'
|
||||
'php-sqlite: storage backend for contacts')
|
||||
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz"
|
||||
"$pkgname.sysusers"
|
||||
"$pkgname.tmpfiles")
|
||||
b2sums=('a877041eaa74ca9824323b0ba80b3515205628825ed76fccff1511b2547c27419bae4733d24f8f36e6860c671cb609c4c5f31fa19529a92c628cb714570ff8ae'
|
||||
'e020b2d4bc694ca056f5c15b148c69553ab610b5e1789f52543aa65e098f8097a41709b5b0fc22a6a01088a9d3f14d623b1b6e9ae2570acd4f380f429301c003'
|
||||
'2536e11622895322cc752c6b651811b2122d3ae60099fe609609d7b45ba1ed00ea729c23f344405078698d161dbf9bcaffabf8eff14b740acdce3c681c513318')
|
||||
|
||||
prepare() {
|
||||
sed -i "s/\$sCustomDataPath = '';/\$sCustomDataPath = '\/var\/lib\/$pkgname';/" "$pkgname-$pkgver/$pkgname/v/0.0.0/include.php"
|
||||
|
||||
# create folder for build output
|
||||
mkdir -p build
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$pkgname-$pkgver"
|
||||
yarn install
|
||||
|
||||
# build snappymail
|
||||
php release.php --aur
|
||||
bsdtar -x \
|
||||
-C "$srcdir/build" \
|
||||
-f "build/dist/releases/webmail/$pkgver/$pkgname-$pkgver.zip"
|
||||
find . -type d -exec chmod 755 {} \;
|
||||
find . -type f -exec chmod 644 {} \;
|
||||
}
|
||||
|
||||
package() {
|
||||
# directories
|
||||
install -dm755 "$pkgdir/usr/share/snappymail" \
|
||||
"$pkgdir/var/lib/snappymail"
|
||||
|
||||
# application files
|
||||
cp -r "$srcdir/build/snappymail" "$pkgdir/usr/share/snappymail"
|
||||
install -Dm644 -t "$pkgdir/usr/share/snappymail" "$srcdir/build/index.php"
|
||||
|
||||
# data files
|
||||
cp -r "$srcdir/build/data" "$pkgdir/var/lib/snappymail"
|
||||
|
||||
# sysusers
|
||||
install -Dm644 "$srcdir/$pkgname.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgname.conf"
|
||||
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
u snappymail - "Snappymail User" /var/lib/snappymail
|
||||
|
|
@ -1 +0,0 @@
|
|||
Z /var/lib/snappymail - snappymail snappymail
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
echo "\x1b[33;1m === cPanel === \x1b[0m\n";
|
||||
|
||||
$cpanel_destination = "{$destPath}snappymail-{$package->version}-cpanel.tar";
|
||||
|
||||
@unlink($cpanel_destination);
|
||||
@unlink("{$cpanel_destination}.gz");
|
||||
|
||||
$cpanel_tar = new PharData($cpanel_destination);
|
||||
|
||||
$cpanel_tar->buildFromDirectory('./integrations/cpanel', "@integrations/cpanel/@");
|
||||
|
||||
$cpanel_path = '/usr/local/cpanel/base/3rdparty/snappymail/';
|
||||
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('snappymail/v'), RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$newFile = str_replace('\\', '/', $file);
|
||||
$cpanel_tar->addFile($file, "{$cpanel_path}{$newFile}");
|
||||
}
|
||||
}
|
||||
|
||||
$cpanel_tar->addFile('.htaccess', "{$cpanel_path}.htaccess");
|
||||
$cpanel_tar->addFile('README.md', "{$cpanel_path}README.md");
|
||||
$cpanel_tar->addFromString("{$cpanel_path}VERSION", $package->version);
|
||||
|
||||
$index = file_get_contents('index.php');
|
||||
$index = str_replace('0.0.0', $package->version, $index);
|
||||
$cpanel_tar->addFromString("{$cpanel_path}index.php", $index);
|
||||
|
||||
$data = file_get_contents('dev/serviceworker.js');
|
||||
$cpanel_tar->addFromString("{$cpanel_path}serviceworker.js", $data);
|
||||
|
||||
$cpanel_tar->compress(Phar::GZ);
|
||||
unlink($cpanel_destination);
|
||||
$cpanel_destination .= '.gz';
|
||||
|
||||
echo "{$cpanel_destination} created\n";
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
echo "\x1b[33;1m === Debian === \x1b[0m\n";
|
||||
|
||||
// Debian Repository
|
||||
define('DEB_SOURCE_DIR', __DIR__ . '/deb');
|
||||
define('DEB_DEST_DIR', DEB_SOURCE_DIR . "/snappymail_{$package->version}-1_all");
|
||||
is_dir(DEB_DEST_DIR) && passthru('rm -dfr '.escapeshellarg(DEB_DEST_DIR));
|
||||
|
||||
$dir = DEB_DEST_DIR . '/DEBIAN';
|
||||
$data = file_get_contents(DEB_SOURCE_DIR . '/DEBIAN/control');
|
||||
$data = str_replace('0.0.0', $package->version, $data);
|
||||
mkdir($dir, 0755, true);
|
||||
file_put_contents("{$dir}/control", $data);
|
||||
copy(DEB_SOURCE_DIR . '/DEBIAN/postinst', $dir . '/postinst');
|
||||
chmod($dir . '/postinst', 0755);
|
||||
|
||||
$dir = DEB_DEST_DIR . '/var/lib/snappymail';
|
||||
mkdir($dir, 0755, true);
|
||||
file_put_contents($dir . '/VERSION', $package->version);
|
||||
copy('data/README.md', "{$dir}/README.md");
|
||||
|
||||
$dir = DEB_DEST_DIR . '/usr/share/doc/snappymail';
|
||||
mkdir($dir, 0755, true);
|
||||
copy('CODE_OF_CONDUCT.md', "{$dir}/CODE_OF_CONDUCT.md");
|
||||
copy('CONTRIBUTING.md', "{$dir}/CONTRIBUTING.md");
|
||||
copy('README.md', "{$dir}/README.md");
|
||||
//copy('CODE_OF_CONDUCT.md', "{$dir}/CODE_OF_CONDUCT.md");
|
||||
//usr/share/doc/snappymail/README.Debian
|
||||
//usr/share/doc/snappymail/changelog.Debian.gz
|
||||
//usr/share/doc/snappymail/copyright
|
||||
|
||||
// Move files into package directory
|
||||
$dir = DEB_DEST_DIR . '/usr/share/snappymail';
|
||||
mkdir($dir, 0755, true);
|
||||
passthru('cp -r "' . dirname(__DIR__) . '/snappymail" "' . $dir . '"');
|
||||
|
||||
rename("{$dir}/snappymail/v/0.0.0", "{$dir}/snappymail/v/{$package->version}");
|
||||
|
||||
$data = file_get_contents('index.php');
|
||||
file_put_contents("{$dir}/index.php", str_replace('0.0.0', $package->version, $data));
|
||||
|
||||
$data = file_get_contents('_include.php');
|
||||
file_put_contents("{$dir}/include.php", preg_replace('@(external-snappymail-data-folder/\'\);)@', "\$1\ndefine('APP_DATA_FOLDER_PATH', '/var/lib/snappymail/');", $data));
|
||||
|
||||
passthru('dpkg --build ' . escapeshellarg(DEB_DEST_DIR));
|
||||
|
||||
$TARGET_DIR = __DIR__ . "/dist/releases/webmail/{$package->version}/";
|
||||
|
||||
passthru('mv '
|
||||
. escapeshellarg(DEB_DEST_DIR.'.deb') . ' '
|
||||
. escapeshellarg($TARGET_DIR . basename(DEB_DEST_DIR.'.deb'))
|
||||
);
|
||||
|
||||
passthru('rm -dfr '.escapeshellarg(DEB_DEST_DIR));
|
||||
|
||||
// https://github.com/the-djmaze/snappymail/issues/185#issuecomment-1059420588
|
||||
$cwd = getcwd();
|
||||
chdir($TARGET_DIR);
|
||||
passthru('dpkg-scanpackages . /dev/null > '.escapeshellarg($TARGET_DIR . 'Packages'));
|
||||
passthru('dpkg-scanpackages . /dev/null | gzip -9c > '.escapeshellarg($TARGET_DIR . 'Packages.gz'));
|
||||
$size = filesize($TARGET_DIR . 'Packages');
|
||||
$gz_size = filesize($TARGET_DIR . 'Packages.gz');
|
||||
$Release = 'Origin: SnappyMail Repository
|
||||
Label: SnappyMail
|
||||
Suite: stable
|
||||
Codename: stable
|
||||
Version: 1.0
|
||||
Architectures: all
|
||||
Components: main
|
||||
Description: SnappyMail repository
|
||||
Date: ' . gmdate('r') . '
|
||||
MD5Sum:
|
||||
' . hash_file('md5', $TARGET_DIR . 'Packages') . ' ' . $size . ' Packages
|
||||
' . hash_file('md5', $TARGET_DIR . 'Packages.gz') . ' ' . $gz_size . ' Packages.gz
|
||||
SHA1:
|
||||
' . hash_file('sha1', $TARGET_DIR . 'Packages') . ' ' . $size . ' Packages
|
||||
' . hash_file('sha1', $TARGET_DIR . 'Packages.gz') . ' ' . $gz_size . ' Packages.gz
|
||||
SHA256:
|
||||
' . hash_file('sha256', $TARGET_DIR . 'Packages') . ' ' . $size . ' Packages
|
||||
' . hash_file('sha256', $TARGET_DIR . 'Packages.gz') . ' ' . $gz_size . ' Packages.gz
|
||||
';
|
||||
file_put_contents($TARGET_DIR . 'Release', $Release);
|
||||
chdir($cwd);
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
Package: snappymail
|
||||
Version: 0.0.0
|
||||
Maintainer: SnappyMail <debian@snappymail.eu>
|
||||
Depends: nginx | apache2 | httpd, php-fpm | libapache2-mod-php, php-json, php-mbstring
|
||||
Recommends: php-intl, php-sodium, php-uuid
|
||||
Suggests: php-sqlite3 | php-mysql | php-pgsql, php-curl, php-exif, php-gnupg, php-gd | php-gmagick | php-imagick, php-openssl, php-zip
|
||||
Architecture: all
|
||||
Homepage: https://snappymail.eu
|
||||
Vcs-Browser: https://github.com/the-djmaze/snappymail
|
||||
Vcs-Git: https://github.com/the-djmaze/snappymail.git
|
||||
Description: SnappyMail is a PHP-based simple, modern, lightweight & fast web-based email client with no database requirements.
|
||||
It supports IMAP, SMTP and Sieve protocols, multiple accounts and identities, an admin panel for configuration.
|
||||
Plugins can be installed to further extend functionality.
|
||||
Emails are not stored locally, but are accessed through IMAP.
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
chown -R www-data:www-data /var/lib/snappymail
|
||||
chown -R root:root /usr/share/snappymail/
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
echo "\x1b[33;1m === Nextcloud === \x1b[0m\n";
|
||||
|
||||
$cert_dir = $_SERVER['HOME'].'/.nextcloud/certificates';
|
||||
|
||||
$nc_destination = "{$destPath}snappymail-{$package->version}-nextcloud.tar";
|
||||
|
||||
@unlink($nc_destination);
|
||||
@unlink("{$nc_destination}.gz");
|
||||
|
||||
$nc_tar = new PharData($nc_destination);
|
||||
$hashes = [];
|
||||
|
||||
file_put_contents(ROOT_DIR . '/integrations/nextcloud/snappymail/VERSION', $package->version);
|
||||
$file = ROOT_DIR . '/integrations/nextcloud/snappymail/appinfo/info.xml';
|
||||
file_put_contents($file, preg_replace('/<version>[^<]*</', "<version>{$package->version}<", file_get_contents($file)));
|
||||
|
||||
$nc_tar->buildFromDirectory('./integrations/nextcloud', "@integrations/nextcloud/snappymail/@");
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('integrations/nextcloud/snappymail'));
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$name = str_replace('\\', '/', $file);
|
||||
$name = str_replace('integrations/nextcloud/snappymail/', '', $name);
|
||||
$hashes[$name] = hash_file('sha512', $file);
|
||||
}
|
||||
}
|
||||
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('snappymail/v'), RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$newFile = str_replace('\\', '/', $file);
|
||||
$newName = str_replace('/.htaccess', '/_htaccess', $newFile);
|
||||
$nc_tar->addFile($file, "snappymail/app/{$newName}");
|
||||
$hashes["app/{$newFile}"] = hash_file('sha512', $file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
$nc_tar->addFile('data/.htaccess');
|
||||
$nc_tar->addFromString('data/VERSION', $package->version);
|
||||
$nc_tar->addFile('data/README.md');
|
||||
$nc_tar->addFile('_include.php', 'snappymail/app/_include.php');
|
||||
*/
|
||||
$nc_tar->addFile('.htaccess', 'snappymail/app/_htaccess');
|
||||
$hashes['app/.htaccess'] = hash_file('sha512', '.htaccess');
|
||||
|
||||
$index = file_get_contents('index.php');
|
||||
$index = str_replace('0.0.0', $package->version, $index);
|
||||
//$index = str_replace('snappymail/v/', '', $index);
|
||||
$nc_tar->addFromString('snappymail/app/index.php', $index);
|
||||
$hashes['app/index.php'] = hash('sha512', $index);
|
||||
|
||||
$nc_tar->addFile('README.md', 'snappymail/app/README.md');
|
||||
$hashes['app/README.md'] = hash_file('sha512', 'README.md');
|
||||
|
||||
$nc_tar->addFile('CHANGELOG.md', 'snappymail/CHANGELOG.md');
|
||||
$hashes['CHANGELOG.md'] = hash_file('sha512', 'CHANGELOG.md');
|
||||
|
||||
$data = file_get_contents('dev/serviceworker.js');
|
||||
$nc_tar->addFromString('snappymail/app/serviceworker.js', $data);
|
||||
$hashes['app/serviceworker.js'] = hash('sha512', $data);
|
||||
|
||||
spl_autoload_register(function($name){
|
||||
$file = __DIR__ . '/' . str_replace('\\', '/', $name) . '.php';
|
||||
require $file;
|
||||
});
|
||||
|
||||
ksort($hashes);
|
||||
$cert = file_get_contents($cert_dir.'/snappymail.crt');
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$rsa->loadKey(file_get_contents($cert_dir.'/snappymail.key'));
|
||||
$x509 = new \phpseclib\File\X509();
|
||||
$x509->loadX509($cert);
|
||||
$x509->setPrivateKey($rsa);
|
||||
$rsa->setSignatureMode(\phpseclib\Crypt\RSA::SIGNATURE_PSS);
|
||||
$rsa->setMGFHash('sha512');
|
||||
$rsa->setSaltLength(0);
|
||||
$signature = $rsa->sign(json_encode($hashes));
|
||||
$nc_tar->addFromString('snappymail/appinfo/signature.json', json_encode([
|
||||
'hashes' => $hashes,
|
||||
'signature' => base64_encode($signature),
|
||||
'certificate' => $cert
|
||||
], JSON_PRETTY_PRINT));
|
||||
|
||||
$nc_tar->compress(Phar::GZ);
|
||||
unlink($nc_destination);
|
||||
$nc_destination .= '.gz';
|
||||
|
||||
$signature = shell_exec("openssl dgst -sha512 -sign {$cert_dir}/snappymail.key {$nc_destination} | openssl base64");
|
||||
file_put_contents($nc_destination.'.sig', $signature);
|
||||
|
||||
echo "{$nc_destination} created\n";
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
<?php
|
||||
echo "\x1b[33;1m === ownCloud === \x1b[0m\n";
|
||||
|
||||
$cert_dir = false; // $_SERVER['HOME'].'/.owncloud/certificates';
|
||||
|
||||
$nc_destination = "{$destPath}snappymail-{$package->version}-owncloud.tar";
|
||||
|
||||
@unlink($nc_destination);
|
||||
@unlink("{$nc_destination}.gz");
|
||||
|
||||
$nc_tar = new PharData($nc_destination);
|
||||
$hashes = [];
|
||||
|
||||
file_put_contents(ROOT_DIR . '/integrations/owncloud/snappymail/VERSION', $package->version);
|
||||
$file = ROOT_DIR . '/integrations/owncloud/snappymail/appinfo/info.xml';
|
||||
file_put_contents($file, preg_replace('/<version>[^<]*</', "<version>{$package->version}<", file_get_contents($file)));
|
||||
|
||||
$nc_tar->buildFromDirectory('./integrations/owncloud', "@integrations/owncloud/snappymail/@");
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('integrations/owncloud/snappymail'));
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$name = str_replace('\\', '/', $file);
|
||||
$name = str_replace('integrations/owncloud/snappymail/', '', $name);
|
||||
$hashes[$name] = hash_file('sha512', $file);
|
||||
}
|
||||
}
|
||||
|
||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('snappymail/v'), RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
$newFile = str_replace('\\', '/', $file);
|
||||
// $newFile = str_replace("'snappymail/v/'.", '', $newFile);
|
||||
$nc_tar->addFile($file, "snappymail/app/{$newFile}");
|
||||
$hashes["app/{$newFile}"] = hash_file('sha512', $file);
|
||||
}
|
||||
}
|
||||
$nc_tar->delete("snappymail/app/snappymail/v/{$package->version}/app/.htaccess");
|
||||
$nc_tar->addFile("snappymail/v/{$package->version}/app/.htaccess", "snappymail/app/snappymail/v/{$package->version}/app/_htaccess");
|
||||
$nc_tar->delete("snappymail/app/snappymail/v/{$package->version}/static/.htaccess");
|
||||
$nc_tar->addFile("snappymail/v/{$package->version}/static/.htaccess", "snappymail/app/snappymail/v/{$package->version}/static/_htaccess");
|
||||
|
||||
/*
|
||||
$nc_tar->addFile('data/.htaccess');
|
||||
$nc_tar->addFromString('data/VERSION', $package->version);
|
||||
$nc_tar->addFile('data/README.md');
|
||||
$nc_tar->addFile('_include.php', 'snappymail/app/_include.php');
|
||||
*/
|
||||
$nc_tar->addFile('.htaccess', 'snappymail/app/_htaccess');
|
||||
$hashes['app/.htaccess'] = hash_file('sha512', '.htaccess');
|
||||
|
||||
$index = file_get_contents('index.php');
|
||||
$index = str_replace('0.0.0', $package->version, $index);
|
||||
//$index = str_replace('snappymail/v/', '', $index);
|
||||
$nc_tar->addFromString('snappymail/app/index.php', $index);
|
||||
$hashes['app/index.php'] = hash('sha512', $index);
|
||||
|
||||
$nc_tar->addFile('README.md', 'snappymail/app/README.md');
|
||||
$hashes['app/README.md'] = hash_file('sha512', 'README.md');
|
||||
|
||||
$nc_tar->addFile('CHANGELOG.md', 'snappymail/CHANGELOG.md');
|
||||
$hashes['CHANGELOG.md'] = hash_file('sha512', 'CHANGELOG.md');
|
||||
|
||||
$data = file_get_contents('dev/serviceworker.js');
|
||||
$nc_tar->addFromString('snappymail/app/serviceworker.js', $data);
|
||||
$hashes['app/serviceworker.js'] = hash('sha512', $data);
|
||||
|
||||
if ($cert_dir) {
|
||||
spl_autoload_register(function($name){
|
||||
$file = __DIR__ . '/' . str_replace('\\', '/', $name) . '.php';
|
||||
require $file;
|
||||
});
|
||||
|
||||
ksort($hashes);
|
||||
$cert = file_get_contents($cert_dir.'/snappymail.crt');
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$rsa->loadKey(file_get_contents($cert_dir.'/snappymail.key'));
|
||||
$x509 = new \phpseclib\File\X509();
|
||||
$x509->loadX509($cert);
|
||||
$x509->setPrivateKey($rsa);
|
||||
$rsa->setSignatureMode(\phpseclib\Crypt\RSA::SIGNATURE_PSS);
|
||||
$rsa->setMGFHash('sha512');
|
||||
$rsa->setSaltLength(0);
|
||||
$signature = $rsa->sign(json_encode($hashes));
|
||||
$nc_tar->addFromString('snappymail/appinfo/signature.json', json_encode([
|
||||
'hashes' => $hashes,
|
||||
'signature' => base64_encode($signature),
|
||||
'certificate' => $cert
|
||||
], JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
$nc_tar->compress(Phar::GZ);
|
||||
unlink($nc_destination);
|
||||
$nc_destination .= '.gz';
|
||||
|
||||
if ($cert_dir) {
|
||||
$signature = shell_exec("openssl dgst -sha512 -sign {$cert_dir}/snappymail.key {$nc_destination} | openssl base64");
|
||||
file_put_contents($nc_destination.'.sig', $signature);
|
||||
}
|
||||
|
||||
echo "{$nc_destination} created\n";
|
||||
28
build/owncloud/rainloop-app/INSTALL
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
************************************************************************
|
||||
*
|
||||
* ownCloud/Nextcloud - RainLoop Webmail package
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*
|
||||
************************************************************************
|
||||
|
||||
REQUIREMENTS:
|
||||
- ownCloud version 6 or higher
|
||||
or
|
||||
- Nextcloud version 10 or higher
|
||||
|
||||
|
||||
INSTALL:
|
||||
- Unpack the RainLoop Webmail application package in the apps directory of your ownCloud or Nextcloud instance
|
||||
- Make sure the rights are appropriately set
|
||||
|
||||
CONFIGURATION:
|
||||
- ownCloud:
|
||||
1) In the Apps > Enable 'RainLoop' plugin
|
||||
2) In the Settings > Personal > Type your email server login and password
|
||||
- Nextcloud:
|
||||
1) In the Apps > Enable 'RainLoop' plugin after checking 'Enable experimental apps'
|
||||
2) In the Settings > Personal > Type your email server login and password
|
||||
1
build/owncloud/rainloop-app/VERSION
Normal file
|
|
@ -0,0 +1 @@
|
|||
0.0
|
||||
19
build/owncloud/rainloop-app/admin.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\User::checkAdminUser();
|
||||
|
||||
OCP\Util::addScript('rainloop', 'admin');
|
||||
|
||||
$oTemplate = new OCP\Template('rainloop', 'admin-local');
|
||||
$oTemplate->assign('rainloop-admin-panel-link', OC_RainLoop_Helper::getAppUrl().'?admin');
|
||||
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
|
||||
return $oTemplate->fetchPage();
|
||||
36
build/owncloud/rainloop-app/ajax/admin.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\JSON::checkAdminUser();
|
||||
OCP\JSON::checkAppEnabled('rainloop');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$sUrl = '';
|
||||
$sPath = '';
|
||||
$bAutologin = false;
|
||||
|
||||
if (isset($_POST['appname']) && 'rainloop' === $_POST['appname'])
|
||||
{
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-autologin', isset($_POST['rainloop-autologin']) ?
|
||||
'1' === $_POST['rainloop-autologin'] : false);
|
||||
|
||||
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
OC_JSON::error(array('Message' => 'Invalid Argument(s)'));
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
OCP\JSON::success(array('Message' => 'Saved successfully'));
|
||||
return true;
|
||||
47
build/owncloud/rainloop-app/ajax/personal.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\JSON::checkLoggedIn();
|
||||
OCP\JSON::checkAppEnabled('rainloop');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$sEmail = '';
|
||||
$sLogin = '';
|
||||
|
||||
if (isset($_POST['appname'], $_POST['rainloop-password'], $_POST['rainloop-email']) && 'rainloop' === $_POST['appname'])
|
||||
{
|
||||
$sUser = OCP\User::getUser();
|
||||
|
||||
$sPostEmail = $_POST['rainloop-email'];
|
||||
|
||||
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-email', $sPostEmail);
|
||||
|
||||
$sPass = $_POST['rainloop-password'];
|
||||
if ('******' !== $sPass && '' !== $sPass)
|
||||
{
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-password',
|
||||
OC_RainLoop_Helper::encodePassword($sPass, md5($sPostEmail)));
|
||||
}
|
||||
|
||||
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
OC_JSON::error(array('Message' => 'Invalid argument(s)', 'Email' => $sEmail));
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
OCP\JSON::success(array('Message' => 'Saved successfully', 'Email' => $sEmail));
|
||||
return true;
|
||||
36
build/owncloud/rainloop-app/app.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
OCP\User::checkLoggedIn();
|
||||
|
||||
if (@file_exists(__DIR__.'/app/index.php'))
|
||||
{
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
OC_RainLoop_Helper::regRainLoopDataFunction();
|
||||
|
||||
if (isset($_GET['OwnCloudAuth']))
|
||||
{
|
||||
$sEmail = '';
|
||||
$sEncodedPassword = '';
|
||||
|
||||
$sUser = OCP\User::getUser();
|
||||
|
||||
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
|
||||
{
|
||||
$sEmail = $sUser;
|
||||
$sEncodedPassword = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-autologin-password', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
|
||||
$sEncodedPassword = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-password', '');
|
||||
}
|
||||
|
||||
$sDecodedPassword = OC_RainLoop_Helper::decodePassword($sEncodedPassword, md5($sEmail));
|
||||
|
||||
$_ENV['___rainloop_owncloud_email'] = $sEmail;
|
||||
$_ENV['___rainloop_owncloud_password'] = $sDecodedPassword;
|
||||
}
|
||||
|
||||
include __DIR__.'/app/index.php';
|
||||
}
|
||||
34
build/owncloud/rainloop-app/appinfo/app.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/owncloud
|
||||
*/
|
||||
|
||||
OC::$CLASSPATH['OC_RainLoop_Helper'] = OC_App::getAppPath('rainloop') . '/lib/RainLoopHelper.php';
|
||||
|
||||
OCP\App::registerAdmin('rainloop', 'admin');
|
||||
OCP\App::registerPersonal('rainloop', 'personal');
|
||||
|
||||
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
|
||||
{
|
||||
OCP\Util::connectHook('OC_User', 'post_login', 'OC_RainLoop_Helper', 'login');
|
||||
OCP\Util::connectHook('OC_User', 'post_setPassword', 'OC_RainLoop_Helper', 'changePassword');
|
||||
}
|
||||
|
||||
OCP\Util::connectHook('OC_User', 'logout', 'OC_RainLoop_Helper', 'logout');
|
||||
|
||||
OCP\Util::addScript('rainloop', 'rainloop');
|
||||
|
||||
OCP\App::addNavigationEntry(array(
|
||||
'id' => 'rainloop_index',
|
||||
'order' => 10,
|
||||
'href' => OCP\Util::linkToRoute('rainloop_index'),
|
||||
'icon' => OCP\Util::imagePath('rainloop', 'mail.png'),
|
||||
'name' => 'Email'
|
||||
));
|
||||
|
||||
20
build/owncloud/rainloop-app/appinfo/info.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||
<id>rainloop</id>
|
||||
<name>RainLoop</name>
|
||||
<summary>RainLoop Webmail</summary>
|
||||
<description>Simple, modern and fast web-based email client.</description>
|
||||
<version>0.0</version>
|
||||
<licence></licence>
|
||||
<author>RainLoop Team</author>
|
||||
<require>6.0</require>
|
||||
<ocsid>165254</ocsid>
|
||||
<dependencies>
|
||||
<php min-version="5.4" />
|
||||
<owncloud min-version="6" max-version="9.2" />
|
||||
<nextcloud min-version="10" />
|
||||
</dependencies>
|
||||
<category>tools</category>
|
||||
<website>http://www.rainloop.net/</website>
|
||||
<bugs>https://github.com/RainLoop/rainloop-webmail/issues</bugs>
|
||||
</info>
|
||||
13
build/owncloud/rainloop-app/appinfo/routes.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
$this->create('rainloop_index', '/')
|
||||
->actionInclude('rainloop/index.php');
|
||||
|
||||
$this->create('rainloop_app', '/app/')
|
||||
->actionInclude('rainloop/app.php');
|
||||
|
||||
$this->create('rainloop_ajax_personal', 'ajax/personal.php')
|
||||
->actionInclude('rainloop/ajax/personal.php');
|
||||
|
||||
$this->create('rainloop_ajax_admin', 'ajax/admin.php')
|
||||
->actionInclude('rainloop/ajax/admin.php');
|
||||
6
build/owncloud/rainloop-app/css/style.css
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
Empty style sheet!
|
||||
Only needed to give you the opportunity to theme the owncloud part
|
||||
of the rainloop app with the theming system integrated in ownCoud
|
||||
if the rainloop app is activated.
|
||||
*/
|
||||
BIN
build/owncloud/rainloop-app/img/logo-64x64.png
Executable file
|
After Width: | Height: | Size: 832 B |
BIN
build/owncloud/rainloop-app/img/mail.png
Executable file
|
After Width: | Height: | Size: 478 B |
27
build/owncloud/rainloop-app/index.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\User::checkLoggedIn();
|
||||
OCP\App::checkAppEnabled('rainloop');
|
||||
OCP\App::setActiveNavigationEntry('rainloop_index');
|
||||
|
||||
// Load the empty file ../css/style.css, that's needed to allow theming of
|
||||
// the ownCloud header and navigation if rainloop is the active app.
|
||||
OCP\Util::addStyle('rainloop', 'style');
|
||||
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
$sUrl = OC_RainLoop_Helper::normalizeUrl(OC_RainLoop_Helper::getAppUrl());
|
||||
|
||||
$oTemplate = new OCP\Template('rainloop', 'index', 'user');
|
||||
$oTemplate->assign('rainloop-iframe-url', OC_RainLoop_Helper::normalizeUrl($sUrl).'?OwnCloudAuth');
|
||||
|
||||
$oTemplate->printpage();
|
||||
13
build/owncloud/rainloop-app/js/admin.js
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
|
||||
});
|
||||
13
build/owncloud/rainloop-app/js/personal.js
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
|
||||
});
|
||||
76
build/owncloud/rainloop-app/js/rainloop.js
Executable file
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
function RainLoopFormHelper(sID, sAjaxFile, fCallback)
|
||||
{
|
||||
try
|
||||
{
|
||||
var
|
||||
oForm = $(sID),
|
||||
oSubmit = $('#rainloop-save-button', oForm),
|
||||
sSubmitValue = oSubmit.val(),
|
||||
oDesc = oForm.find('.rainloop-result-desc')
|
||||
;
|
||||
|
||||
oSubmit.click(function (oEvent) {
|
||||
|
||||
var oDefAjax = null;
|
||||
|
||||
oEvent.preventDefault();
|
||||
|
||||
oForm
|
||||
.addClass('rainloop-ajax')
|
||||
.removeClass('rainloop-error')
|
||||
.removeClass('rainloop-success')
|
||||
;
|
||||
|
||||
oDesc.text('');
|
||||
oSubmit.val('...');
|
||||
|
||||
oDefAjax = $.ajax({
|
||||
'type': 'POST',
|
||||
'async': true,
|
||||
'url': OC.filePath('rainloop', 'ajax', sAjaxFile),
|
||||
'data': oForm.serialize(),
|
||||
'dataType': 'json',
|
||||
'global': true
|
||||
});
|
||||
|
||||
oDefAjax.always(function (oData) {
|
||||
|
||||
var bResult = false;
|
||||
|
||||
oForm.removeClass('rainloop-ajax');
|
||||
oSubmit.val(sSubmitValue);
|
||||
|
||||
if (oData)
|
||||
{
|
||||
bResult = 'success' === oData['status'];
|
||||
if (oData['Message'])
|
||||
{
|
||||
oDesc.text(oData['Message']);
|
||||
}
|
||||
}
|
||||
|
||||
if (bResult)
|
||||
{
|
||||
oForm.addClass('rainloop-success');
|
||||
}
|
||||
else
|
||||
{
|
||||
oForm.addClass('rainloop-error');
|
||||
if ('' === oDesc.text())
|
||||
{
|
||||
oDesc.text('Error');
|
||||
}
|
||||
}
|
||||
|
||||
if (fCallback)
|
||||
{
|
||||
fCallback(bResult, oData);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
catch(e) {}
|
||||
}
|
||||
26
build/owncloud/rainloop-app/js/resize.js
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
$(function (window, document) {
|
||||
|
||||
var
|
||||
buffer = 5,
|
||||
ifr = document.getElementById('rliframe')
|
||||
;
|
||||
|
||||
|
||||
function pageY(elem) {
|
||||
return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
|
||||
}
|
||||
|
||||
function resizeIframe() {
|
||||
var height = document.documentElement.clientHeight;
|
||||
height -= pageY(ifr) + buffer;
|
||||
height = (height < 0) ? 0 : height;
|
||||
ifr.style.height = height + 'px';
|
||||
}
|
||||
|
||||
if (ifr)
|
||||
{
|
||||
ifr.onload = resizeIframe;
|
||||
window.onresize = resizeIframe;
|
||||
}
|
||||
|
||||
}(window, document));
|
||||
257
build/owncloud/rainloop-app/lib/RainLoopHelper.php
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
<?php
|
||||
|
||||
class OC_RainLoop_Helper
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getAppUrl()
|
||||
{
|
||||
if (class_exists('\\OCP\\Util'))
|
||||
{
|
||||
return OCP\Util::linkToRoute('rainloop_app');
|
||||
}
|
||||
|
||||
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': trim($_SERVER['REQUEST_URI']);
|
||||
$sRequestUri = preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
|
||||
$sRequestUri = $sRequestUri.'apps/rainloop/app/';
|
||||
|
||||
return '/'.ltrim($sRequestUri, '/\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPath
|
||||
* @param string $sEmail
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getSsoHash($sPath, $sEmail, $sPassword)
|
||||
{
|
||||
$SsoHash = '';
|
||||
|
||||
$sPath = rtrim(trim($sPath), '\\/').'/index.php';
|
||||
if (file_exists($sPath))
|
||||
{
|
||||
self::regRainLoopDataFunction();
|
||||
|
||||
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
|
||||
include $sPath;
|
||||
|
||||
if (class_exists('\\RainLoop\\Api'))
|
||||
{
|
||||
$SsoHash = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword);
|
||||
}
|
||||
}
|
||||
|
||||
return $SsoHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sUrl
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function normalizeUrl($sUrl)
|
||||
{
|
||||
$sUrl = rtrim(trim($sUrl), '/\\');
|
||||
if ('.php' !== strtolower(substr($sUrl, -4)))
|
||||
{
|
||||
$sUrl .= '/';
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
public static function encodePassword($sPassword, $sSalt)
|
||||
{
|
||||
if (function_exists('mcrypt_encrypt') && function_exists('mcrypt_create_iv') && function_exists('mcrypt_get_iv_size') &&
|
||||
defined('MCRYPT_RIJNDAEL_256') && defined('MCRYPT_MODE_ECB') && defined('MCRYPT_RAND'))
|
||||
{
|
||||
return @trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_encode($sPassword),
|
||||
MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
|
||||
}
|
||||
|
||||
return @trim(base64_encode($sPassword));
|
||||
}
|
||||
|
||||
public static function decodePassword($sPassword, $sSalt)
|
||||
{
|
||||
if (function_exists('mcrypt_encrypt') && function_exists('mcrypt_create_iv') && function_exists('mcrypt_get_iv_size') &&
|
||||
defined('MCRYPT_RIJNDAEL_256') && defined('MCRYPT_MODE_ECB') && defined('MCRYPT_RAND'))
|
||||
{
|
||||
return @base64_decode(trim(@mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_decode(trim($sPassword)),
|
||||
MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
|
||||
}
|
||||
|
||||
return @base64_decode(trim($sPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function login($aParams)
|
||||
{
|
||||
if (isset($aParams['uid'], $aParams['password']))
|
||||
{
|
||||
$sUser = $aParams['uid'];
|
||||
|
||||
$sEmail = $sUser;
|
||||
$sPassword = $aParams['password'];
|
||||
|
||||
return OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-autologin-password',
|
||||
self::encodePassword($sPassword, md5($sEmail)));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function logout()
|
||||
{
|
||||
OCP\Config::setUserValue(
|
||||
OCP\User::getUser(), 'rainloop', 'rainloop-autologin-password', '');
|
||||
|
||||
$sApiPath = __DIR__.'/../app/index.php';
|
||||
if (file_exists($sApiPath))
|
||||
{
|
||||
self::regRainLoopDataFunction();
|
||||
|
||||
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
|
||||
include $sApiPath;
|
||||
|
||||
if (class_exists('\\RainLoop\\Api'))
|
||||
{
|
||||
\RainLoop\Api::LogoutCurrentLogginedUser();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function changePassword($aParams)
|
||||
{
|
||||
if (isset($aParams['uid'], $aParams['password']))
|
||||
{
|
||||
$sUser = $aParams['uid'];
|
||||
|
||||
$sEmail = $sUser;
|
||||
$sPassword = $aParams['password'];
|
||||
|
||||
OCP\Util::writeLog('rainloop', 'rainloop|login: Setting new RainLoop password for '.$sEmail, OCP\Util::DEBUG);
|
||||
|
||||
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-autologin-password',
|
||||
self::encodePassword($sPassword, md5($sEmail)));
|
||||
|
||||
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-password',
|
||||
self::encodePassword($sPassword, md5($sEmail)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function regRainLoopDataFunction()
|
||||
{
|
||||
if (!@function_exists('__get_custom_data_full_path'))
|
||||
{
|
||||
$_ENV['RAINLOOP_OWNCLOUD'] = true;
|
||||
|
||||
function __get_custom_data_full_path()
|
||||
{
|
||||
$sData = __DIR__.'/../../data/';
|
||||
if (class_exists('OC_Config'))
|
||||
{
|
||||
$sData = rtrim(trim(OC_Config::getValue('datadirectory', '')), '\\/').'/';
|
||||
}
|
||||
else if (class_exists('OC'))
|
||||
{
|
||||
$sData = rtrim(trim(OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/').'/';
|
||||
}
|
||||
|
||||
return @is_dir($sData) ? $sData.'rainloop-storage' : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function mimeContentType($filename) {
|
||||
|
||||
$mime_types = array(
|
||||
|
||||
'woff' => 'application/font-woff',
|
||||
|
||||
'txt' => 'text/plain',
|
||||
'htm' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
'php' => 'text/html',
|
||||
'css' => 'text/css',
|
||||
'js' => 'application/javascript',
|
||||
'json' => 'application/json',
|
||||
'xml' => 'application/xml',
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'flv' => 'video/x-flv',
|
||||
|
||||
// images
|
||||
'png' => 'image/png',
|
||||
'jpe' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'bmp' => 'image/bmp',
|
||||
'ico' => 'image/vnd.microsoft.icon',
|
||||
'tiff' => 'image/tiff',
|
||||
'tif' => 'image/tiff',
|
||||
'svg' => 'image/svg+xml',
|
||||
'svgz' => 'image/svg+xml',
|
||||
|
||||
// archives
|
||||
'zip' => 'application/zip',
|
||||
'rar' => 'application/x-rar-compressed',
|
||||
'exe' => 'application/x-msdownload',
|
||||
'msi' => 'application/x-msdownload',
|
||||
'cab' => 'application/vnd.ms-cab-compressed',
|
||||
|
||||
// audio/video
|
||||
'mp3' => 'audio/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
|
||||
// adobe
|
||||
'pdf' => 'application/pdf',
|
||||
'psd' => 'image/vnd.adobe.photoshop',
|
||||
'ai' => 'application/postscript',
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
|
||||
// ms office
|
||||
'doc' => 'application/msword',
|
||||
'rtf' => 'application/rtf',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
|
||||
// open office
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
);
|
||||
|
||||
if (0 < strpos($filename, '.'))
|
||||
{
|
||||
$ext = strtolower(array_pop(explode('.',$filename)));
|
||||
if (array_key_exists($ext, $mime_types))
|
||||
{
|
||||
return $mime_types[$ext];
|
||||
}
|
||||
else if (function_exists('finfo_open'))
|
||||
{
|
||||
$finfo = finfo_open(FILEINFO_MIME);
|
||||
$mimetype = finfo_file($finfo, $filename);
|
||||
finfo_close($finfo);
|
||||
return $mimetype;
|
||||
}
|
||||
}
|
||||
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
34
build/owncloud/rainloop-app/personal.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2016 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\User::checkLoggedIn();
|
||||
OCP\App::checkAppEnabled('rainloop');
|
||||
|
||||
OCP\Util::addScript('rainloop', 'personal');
|
||||
|
||||
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
|
||||
{
|
||||
$oTemplate = new OCP\Template('rainloop', 'empty');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUser = OCP\User::getUser();
|
||||
|
||||
$oTemplate = new OCP\Template('rainloop', 'personal');
|
||||
|
||||
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
|
||||
$sPass = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-password', '');
|
||||
|
||||
$oTemplate->assign('rainloop-email', $sEmail);
|
||||
$oTemplate->assign('rainloop-password', 0 === strlen($sPass) && 0 === strlen($sEmail) ? '' : '******');
|
||||
}
|
||||
|
||||
return $oTemplate->fetchPage();
|
||||