Compare commits

..

No commits in common. "master" and "v1.12.1" have entirely different histories.

4102 changed files with 339076 additions and 319082 deletions

View file

@ -1,4 +0,0 @@
last 1 version
> 30%
not IE 11
not IE_Mob 11

6
.cmds
View file

@ -6,7 +6,7 @@ yarn upgrade xxx@1.2.3
# transifex
tx pull -a
# dependencies
# dependencies
yarn outdated
yarn upgrade-interactive --exact --latest
@ -15,5 +15,5 @@ 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
gpg --detach-sign --armor --openpgp -u 87DA4591 x
for ff in `ls *.zip`; do gpg --detach-sign --armor --openpgp -u 87DA4591 $ff; done

View file

@ -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"]

View file

@ -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

0
.docker/dev/mail/setup.sh → .docker/mail/setup.sh Normal file → Executable file
View file

View file

@ -1,3 +1,4 @@
server {
listen 80 default;
listen 443 ssl;

0
.docker/dev/nginx/ssl.sh → .docker/nginx/ssl.sh Executable file → Normal file
View file

6
.docker/node/Dockerfile Normal file
View file

@ -0,0 +1,6 @@
FROM node:9.11.2-alpine
RUN apk add --no-cache git
RUN yarn global add gulp@3.9.1
CMD ["node", "--version"]

27
.docker/php/Dockerfile Normal file
View file

@ -0,0 +1,27 @@
FROM php:7.1-fpm
RUN apt-get update
RUN apt-get install -y \
git unzip wget zip curl mlocate \
libmcrypt-dev 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
RUN docker-php-ext-configure intl && \
docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ && \
docker-php-ext-install opcache pdo_mysql mcrypt zip intl gd
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"]

8
.docker/php/rainloop.ini Normal file
View file

@ -0,0 +1,8 @@
date.timezone = UTC
upload_max_filesize = 1G
post_max_size = 1G
# log_errors = On
# display_errors = On
# error_reporting = E_ALL
# error_log = /dev/stderr

View file

@ -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"]

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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");
}

View file

@ -1,3 +0,0 @@
<?php
define('APP_DATA_FOLDER_PATH', '/var/lib/snappymail/');
?>

View file

@ -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

View file

@ -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>

View file

@ -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"

View file

@ -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

View file

@ -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

5
.docker/tx/Dockerfile Normal file
View file

@ -0,0 +1,5 @@
FROM python:3.6-alpine
RUN pip install transifex-client
CMD ["tx", "--version"]

View file

@ -1,2 +0,0 @@
/.git
/node_modules

View file

@ -1,2 +0,0 @@
[*.php]
indent_style = tab

View file

@ -1,4 +0,0 @@
*.*
!/dev/**/*.js
!/tasks/**/*.js
!/*.js

View file

@ -1,64 +1,279 @@
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',
"parser": "babel-eslint",
'parserOptions': {
'ecmaVersion': 6,
'sourceType': 'module'
},
'env': {
'node': true,
'commonjs': true,
'es6': true
},
// 'plugins': ['compat'],
'globals': {
'RL_COMMUNITY': true,
'RL_ES6': true
},
// http://eslint.org/docs/rules/
'rules': {
// plugins
// 'compat/compat': 2,
// errors
'no-cond-assign': [2, 'always'],
'no-console': 0,
'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': 0,
'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': ['error', 'tab', {
'SwitchCase': 1,
'VariableDeclarator': 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
}
};

2
.github/FUNDING.yml vendored
View file

@ -1,2 +0,0 @@
github: the-djmaze
custom: ["https://www.paypal.me/thedjmaze", "https://snappymail.eu"]

View file

@ -1,5 +1,5 @@
**SnappyMail version, browser, browser version:**
**RainLoop version, browser, OS:**
**Expected behavior and actual behavior:**

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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

43
.gitignore vendored
View file

@ -1,32 +1,31 @@
*.bak
*.old
/.idea
/.vscode
/api.php
/*.log
/snappymail/v/0.0.0/static/*
/error.log
/nbproject
/npm-debug.log
/yarn-error.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
/.docker/.cache
/.docker/mail/config
/.docker/nginx/ssl/*
!/.docker/nginx/ssl/.gitempty
/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

7
.gitmodules vendored
View file

@ -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

View file

@ -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>

View file

@ -1,4 +0,0 @@
*.*
!/dev/**/*.js
!/tasks/**/*.js
!/*.js

View file

@ -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"
}
}
]
}

13
.travis.yml Normal file
View file

@ -0,0 +1,13 @@
language: php
php:
- '5.4'
- '5.5'
- '5.6'
# - '7.0'
# - '7.1'
#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

15
.tx/config Normal file
View file

@ -0,0 +1,15 @@
[main]
host = https://www.transifex.com
minimum_perc = 60
type = YAML
[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

File diff suppressed because it is too large Load diff

View file

@ -1,130 +1,74 @@
# 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.
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
Examples of behavior that contributes to creating a positive environment
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
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior include:
Examples of unacceptable behavior by participants 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
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/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
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
## Our 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.
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
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.
Project maintainers 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, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## 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.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## 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.
reported by contacting the project team at support@rainloop.net. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
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.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## 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.
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View file

@ -1,4 +1,4 @@
**Thanks for contributing to SnappyMail Webmail!**
**Thanks for contributing to RainLoop Webmail!**
1. Fork the repo, do work in a feature branch.
2. Issue a pull request.
@ -7,15 +7,14 @@
**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`
1. Install node.js - `https://nodejs.org/download/`
2. Install yarn - `https://yarnpkg.com/en/docs/install`
3. Install gulp - `npm install gulp -g`
4. Fork rainloop - `https://github.com/RainLoop/rainloop-webmail/issues/new#fork-destination-box`
5. Clone rainloop - `git clone git@github.com:USERNAME/rainloop-webmail.git rainloop`
6. `cd rainloop`
7. Install install all dependencies - `yarn install`
8. Run gulp - `gulp`
---
@ -29,19 +28,8 @@
**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
2. Set 'cache_system_data' to Off
---
If you have any questions, open an issue or email support@snappymail.eu.
If you have any questions, open an issue or email support@rainloop.net.

View file

@ -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/>.

View file

@ -1,76 +1,64 @@
#!make
rebuild: _down
docker compose build --no-cache
docker-compose build --no-cache
up: _up status
_up:
docker compose up -d
docker-compose up -d
stop: _stop status
_stop:
docker compose stop
docker-compose stop
down: _down status
_down:
docker compose down
docker-compose down
restart: _stop _up status
status:
@docker compose ps
@docker-compose ps
tx:
@docker compose run --no-deps --rm tx tx pull -a -s -f -d
@docker-compose run --no-deps --rm tx tx pull -a -s -f -d
console-node:
@docker compose run --no-deps --rm node sh
@docker-compose run --no-deps --rm node sh
console-tx:
@docker compose run --no-deps --rm tx sh
@docker-compose run --no-deps --rm tx sh
console-php:
@docker compose exec php sh
@docker-compose exec php sh
console: console-node
logs:
@docker compose logs --tail=100 -f
@docker-compose logs --tail=100 -f
logs-db:
@docker compose logs --tail=100 -f db
@docker-compose logs --tail=100 -f db
logs-php:
@docker compose logs --tail=100 -f php
@docker-compose logs --tail=100 -f php
logs-node:
@docker compose logs --tail=100 -f node
@docker-compose logs --tail=100 -f node
logs-nginx:
@docker compose logs --tail=100 -f nginx
@docker-compose logs --tail=100 -f nginx
logs-mail:
@docker compose logs --tail=100 -f mail
@docker-compose logs --tail=100 -f mail
logs-tx:
@docker compose logs --tail=100 -f tx
@docker-compose logs --tail=100 -f tx
rl-lint:
@docker compose run --no-deps --rm node gulp 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
@docker-compose run --no-deps --rm node gulp
rl-watch:
@docker-compose run --no-deps --rm node gulp watch
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
@docker-compose run --no-deps --rm node gulp all
rl-build-pro:
@docker-compose run --no-deps --rm node gulp all --pro
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
ubuntu:latest bash

217
README.md
View file

@ -1,226 +1,29 @@
<div align="center">
<a href="https://github.com/the-djmaze/snappymail">
<img src="https://snappymail.eu/static/img/logo-256x256-white.png">
<a href="https://github.com/RainLoop/rainloop-webmail">
<img width="200" heigth="200" src="https://www.rainloop.net/static/img/logo-256x256-tiny.png">
</a>
<br>
<h1>SnappyMail</h1>
<h1>RainLoop Webmail</h1>
<br>
[![github-actions](https://github.com/the-djmaze/snappymail/actions/workflows/docker.yml/badge.svg)](https://github.com/the-djmaze/snappymail/actions/workflows/docker.yml)
[![docker-image-size](https://img.shields.io/docker/image-size/djmaze/snappymail/latest)](https://hub.docker.com/r/djmaze/snappymail/tags)
<p>
Simple, modern, lightweight &amp; fast web-based email client.
Simple, modern &amp; fast web-based email client.
</p>
<p>
The drastically upgraded &amp; 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.
Modest system requirements, decent performance, simple installation and upgrade, no database required
- all these make RainLoop Webmail a perfect choice for your email solution.
</p>
<h2></h2>
<br>
</div>
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).
And don't forget to read the whole [Wiki](https://github.com/the-djmaze/snappymail/wiki).
Information about installing the product, check the [documentation page](http://www.rainloop.net/docs/installation/).
## 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) 2018 Rainloop Team

View file

@ -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
View file

@ -0,0 +1 @@
Name this file as "MULTIPLY" to enable multiple domain installation.

View file

@ -1,31 +1,21 @@
<?php
// Name this file as "include.php" to enable it.
//header('Strict-Transport-Security: max-age=31536000');
/**
* Uncomment to enable multiple domain installation.
*/
//define('MULTIDOMAIN', 1);
/**
* Uncomment to disable APCU.
*/
//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);
<?php
// Name this file as "include.php" to enable it.
/**
* @return string
*/
function __get_custom_data_full_path()
{
return '';
return '/var/external-rainloop-data-folder/'; // custom data folder path
}
/**
* @return string
*/
function __get_additional_configuration_name()
{
return '';
return defined('APP_SITE') && 0 < strlen(APP_SITE) ? APP_SITE.'.ini' : ''; // additional configuration file name
}

BIN
assets/android-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
assets/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
assets/browsers/chrome.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
assets/browsers/firefox.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
assets/browsers/opera.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
assets/browsers/safari.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
assets/css/default-skin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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
assets/css/flags.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/css/images/grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
assets/css/images/sync.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

BIN
assets/css/images/sync.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

BIN
assets/css/images/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

BIN
assets/css/img/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

BIN
assets/css/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

BIN
assets/css/preloader.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 866 B

After

Width:  |  Height:  |  Size: 866 B

Before After
Before After

BIN
assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

16
assets/manifest.json Normal file
View 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
assets/sounds/new-mail.mp3 Normal file

Binary file not shown.

BIN
assets/sounds/new-mail.ogg Normal file

Binary file not shown.

View 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-----

View file

@ -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"
}

View file

@ -1 +0,0 @@
u snappymail - "Snappymail User" /var/lib/snappymail

View file

@ -1 +0,0 @@
Z /var/lib/snappymail - snappymail snappymail

View file

@ -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";

View file

@ -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);

View file

@ -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.

View file

@ -1,3 +0,0 @@
#!/bin/sh
chown -R www-data:www-data /var/lib/snappymail
chown -R root:root /usr/share/snappymail/

View file

@ -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";

View file

@ -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";

View file

@ -0,0 +1,28 @@
************************************************************************
*
* ownCloud/Nextcloud - RainLoop Webmail package
*
* @author RainLoop Team
* @copyright 2018 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

View file

@ -0,0 +1 @@
0.0

View file

@ -0,0 +1,18 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author 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();

View file

@ -0,0 +1,35 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author 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;

View file

@ -0,0 +1,46 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author 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;

View 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';
}

View file

@ -0,0 +1,33 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author 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'
));

View 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="8" max-version="11" />
</dependencies>
<category>tools</category>
<website>https://www.rainloop.net/</website>
<bugs>https://github.com/RainLoop/rainloop-webmail/issues</bugs>
</info>

View 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');

View 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.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

View file

@ -0,0 +1,26 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author 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();

View file

@ -0,0 +1,12 @@
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
});

Some files were not shown because too many files have changed in this diff Show more