Newer
Older
#!/bin/bash
#
# _____ _ _
# | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# | __| _| -_| -_| . | . | | . | . | | -_|
# |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___|
#
# Freedom in the Cloud
#
# etesync server
# https://github.com/victor-rds/docker-etesync/blob/master/Dockerfile_debian.template
#
# License
# =======
#
# Copyright (C) 2018 Bob Mottram <bob@freedombone.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
VARIANTS='full full-vim'
IN_DEFAULT_INSTALL=0
INSTALLED_ON_DEFAULT_DOMAIN=0
SHOW_ON_ABOUT=1
# whether to show the domain name in the web UI
SHOW_DOMAIN_IN_WEBADMIN=1
NOT_ON_API=0
ETESYNC_ONION_PORT=9860
ETESYNC_REPO="https://github.com/etesync/server-skeleton"
ETESYNC_COMMIT='8f50a69b39bef7f421590e3de26b822df0ceaf6e'
ETESYNC_PORT_INTERNAL=8292
# These parameters are used by the FreedomBox mobile app and web UI
ETESYNC_SHORT_DESCRIPTION='End-to-end encrypted sync of calendar and contacts between devices'
ETESYNC_DESCRIPTION='Secure, end-to-end encrypted and journaled personal information cloud synchronization for Android and the desktop, supporting contacts and calendars'
ETESYNC_MOBILE_APP_URL='https://f-droid.org/en/packages/com.etesync.syncadapter/'
etesync_variables=(ONION_ONLY
ETESYNC_DOMAIN_NAME
ETESYNC_CODE
DDNS_PROVIDER
MY_EMAIL_ADDRESS
MY_USERNAME)
function logging_on_etesync {
echo -n ''
}
function logging_off_etesync {
echo -n ''
}
function remove_user_etesync {
remove_username="$1"
echo "from django.contrib.auth.models import User; u = User.objects.get(username='$remove_username'); u.delete();" | python3 manage.py shell
"${PROJECT_NAME}-pass" -u "$remove_username" --rmapp etesync
}
function add_user_etesync {
new_username="$1"
new_user_password="$2"
echo "from django.contrib.auth.models import User; u = User.objects.create_user('$new_username', '${new_username}@$(hostname)', '$new_user_password'); u.save();" | python3 manage.py shell
"${PROJECT_NAME}-pass" -u "$new_username" -a etesync -p "$new_user_password"
echo '0'
}
function install_interactive_etesync {
if [ ! "$ONION_ONLY" ]; then
ONION_ONLY='no'
fi
if [[ "$ONION_ONLY" != "no" ]]; then
ETESYNC_DOMAIN_NAME='etesync.local'
write_config_param "ETESYNC_DOMAIN_NAME" "$ETESYNC_DOMAIN_NAME"
else
interactive_site_details "etesync" "ETESYNC_DOMAIN_NAME" "ETESYNC_CODE"
fi
APP_INSTALLED=1
}
function change_password_etesync {
curr_username="$1"
new_user_password="$2"
echo "from django.contrib.auth.models import User; u = User.objects.get(username='$curr_username'); u.set_password('$new_user_password'); u.save();" | python3 manage.py shell
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"${PROJECT_NAME}-pass" -u "$curr_username" -a etesync -p "$new_user_password"
}
function reconfigure_etesync {
# This is used if you need to switch identity. Dump old keys and generate new ones
echo -n ''
}
function configure_interactive_etesync {
W=(1 $"Option 1"
2 $"Option 2")
while true
do
# shellcheck disable=SC2068
selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"etesync" --menu $"Choose an operation, or ESC for main menu:" 14 70 3 "${W[@]}" 3>&2 2>&1 1>&3)
if [ ! "$selection" ]; then
break
fi
case $selection in
1) # call some function for option 1
;;
2) # call some function for option 2
;;
esac
done
}
function upgrade_etesync {
CURR_ETESYNC_COMMIT=$(get_completion_param "etesync commit")
if [[ "$CURR_ETESYNC_COMMIT" == "$ETESYNC_COMMIT" ]]; then
return
fi
if grep -q "etesync domain" "$COMPLETION_FILE"; then
ETESYNC_DOMAIN_NAME=$(get_completion_param "etesync domain")
fi
# update to the next commit
set_repo_commit "${ETESYNC_PATH}" "etesync commit" "$ETESYNC_COMMIT" "$ETESYNC_REPO"
cd "${ETESYNC_PATH}" || exit 368252
chown -R www-data:www-data "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
systemctl restart etesync
}
function backup_local_etesync {
ETESYNC_DOMAIN_NAME='etesync'
if grep -q "etesync domain" "$COMPLETION_FILE"; then
ETESYNC_DOMAIN_NAME=$(get_completion_param "etesync domain")
fi
suspend_site "${ETESYNC_DOMAIN_NAME}"
systemctl stop etesync
source_directory="${ETESYNC_DATA_PATH}"
dest_directory=etesyncdata
backup_directory_to_usb "$source_directory" $dest_directory
dest_directory=etesync
backup_directory_to_usb "$source_directory" $dest_directory
source_directory="/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
dest_directory=etesyncstatic
backup_directory_to_usb "$source_directory" $dest_directory
restart_site
systemctl start etesync
}
function restore_local_etesync {
if ! grep -q "etesync domain" "$COMPLETION_FILE"; then
return
fi
ETESYNC_DOMAIN_NAME=$(get_completion_param "etesync domain")
if [ ! "$ETESYNC_DOMAIN_NAME" ]; then
return
fi
suspend_site "${ETESYNC_DOMAIN_NAME}"
systemctl stop etesync
temp_restore_dir=/root/tempetesyncdata
etesync_dir="${ETESYNC_DATA_PATH}"
restore_directory_from_usb $temp_restore_dir etesync
if [ -d $temp_restore_dir ]; then
if [ -d "$temp_restore_dir$etesync_dir" ]; then
cp -rp "$temp_restore_dir$etesync_dir"/* "$etesync_dir"/
else
if [ ! -d "$etesync_dir" ]; then
mkdir "$etesync_dir"
fi
cp -rp "$temp_restore_dir"/* "$etesync_dir"/
fi
chown -R etesync:etesync "$etesync_dir"
rm -rf $temp_restore_dir
fi
restore_directory_from_usb $temp_restore_dir etesync
if [ -d $temp_restore_dir ]; then
if [ -d "$temp_restore_dir$etesync_dir" ]; then
cp -rp "$temp_restore_dir$etesync_dir"/* "$etesync_dir"/
else
if [ ! -d "$etesync_dir" ]; then
mkdir "$etesync_dir"
fi
cp -rp "$temp_restore_dir"/* "$etesync_dir"/
fi
chown -R etesync:etesync "$etesync_dir"
rm -rf $temp_restore_dir
fi
temp_restore_dir=/root/tempetesyncstatic
etesync_dir="/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
restore_directory_from_usb $temp_restore_dir etesync
if [ -d $temp_restore_dir ]; then
if [ -d "$temp_restore_dir$etesync_dir" ]; then
cp -rp "$temp_restore_dir$etesync_dir"/* "$etesync_dir"/
else
if [ ! -d "$etesync_dir" ]; then
mkdir "$etesync_dir"
fi
cp -rp "$temp_restore_dir"/* "$etesync_dir"/
fi
chown -R www-data:www-data "$etesync_dir"
rm -rf $temp_restore_dir
fi
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
systemctl start etesync
restart_site
}
function backup_remote_etesync {
echo -n ''
}
function restore_remote_etesync {
echo -n ''
}
function remove_etesync {
nginx_dissite "$ETESYNC_DOMAIN_NAME"
remove_certs "$ETESYNC_DOMAIN_NAME"
if [ -f /etc/systemd/system/etesync.service ]; then
systemctl stop etesync
systemctl disable etesync
rm /etc/systemd/system/etesync.service
fi
userdel -r etesync
if [ -d "/var/www/$ETESYNC_DOMAIN_NAME" ]; then
rm -rf "/var/www/$ETESYNC_DOMAIN_NAME"
fi
if [ -f "/etc/nginx/sites-available/$ETESYNC_DOMAIN_NAME" ]; then
rm "/etc/nginx/sites-available/$ETESYNC_DOMAIN_NAME"
fi
remove_onion_service etesync "${ETESYNC_ONION_PORT}"
if grep -q "etesync" /etc/crontab; then
sed -i "/etesync/d" /etc/crontab
fi
remove_app etesync
remove_completion_param install_etesync
sed -i '/etesync/d' "$COMPLETION_FILE"
remove_ddns_domain "$ETESYNC_DOMAIN_NAME"
}
function install_etesync {
if [ ! "$ETESYNC_DOMAIN_NAME" ]; then
echo $'No domain name was given'
exit 3568356
fi
$INSTALL_PACKAGES coreutils \
curl file gcc git libevent-2.0-5 \
libevent-dev libffi-dev libffi6 \
libgnutls28-dev libjpeg62-turbo \
libjpeg62-turbo-dev libldap-2.4-2 \
libldap2-dev libsasl2-dev \
libsqlite3-dev libssl-dev \
libssl1.1 libtool libxml2 \
libxml2-dev libxslt1-dev libxslt1.1 \
make python3 python3-dev \
python3-pip python3-psycopg2 \
python3-virtualenv sqlite unzip \
ETESYNC_ADMIN_PASSWORD=
if [ -f "$IMAGE_PASSWORD_FILE" ]; then
ETESYNC_ADMIN_PASSWORD="$(printf "%s" "$(cat "$IMAGE_PASSWORD_FILE")")"
else
if [ ! "$ETESYNC_ADMIN_PASSWORD" ]; then
ETESYNC_ADMIN_PASSWORD="$(create_password "${MINIMUM_PASSWORD_LENGTH}")"
fi
fi
if [ ! "$ETESYNC_ADMIN_PASSWORD" ]; then
return
fi
if [ -d "/var/www/$ETESYNC_DOMAIN_NAME/htdocs" ]; then
rm -rf "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
fi
if [ -d "${ETESYNC_PATH}" ]; then
rm -rf "${ETESYNC_PATH}"
fi
mkdir "/var/www/$ETESYNC_DOMAIN_NAME"
if [ -d /repos/etesync ]; then
mkdir -p "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
cp -r -p /repos/etesync/. "${ETESYNC_PATH}"
cd "${ETESYNC_PATH}" || exit 36487365
git pull
else
mkdir -p "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
echo $'Unable to clone etesync repo'
exit 87525
fi
echo $'requirements.txt not found'
exit 56385638
fi
set_completion_param "etesync commit" "$ETESYNC_COMMIT"
chmod g+w "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
chown -R www-data:www-data "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
add_ddns_domain "$ETESYNC_DOMAIN_NAME"
ETESYNC_ONION_HOSTNAME=$(add_onion_service etesync 80 "${ETESYNC_ONION_PORT}")
sed -i "s|ALLOWED_HOSTS =.*|ALLOWED_HOSTS = [ 'localhost', '${ETESYNC_DOMAIN_NAME}', '${ETESYNC_ONION_HOSTNAME}' ]|g" "${ETESYNC_PATH}/etesync_server/settings.py"
sed -i "s|STATIC_ROOT =.*|STATIC_ROOT = os.environ.get('DJANGO_STATICS','/var/www/$ETESYNC_DOMAIN_NAME/htdocs/')|g" "${ETESYNC_PATH}/etesync_server/settings.py"
increment_app_install_progress
if [ ! -d "${ETESYNC_DATA_PATH}" ]; then
mkdir "${ETESYNC_DATA_PATH}"
etesync_nginx_site=/etc/nginx/sites-available/$ETESYNC_DOMAIN_NAME
if [[ "$ONION_ONLY" == "no" ]]; then
nginx_http_redirect "$ETESYNC_DOMAIN_NAME" "index index.html"
{ echo 'server {';
echo ' listen 443 ssl;';
echo ' #listen [::]:443 ssl;';
echo " server_name $ETESYNC_DOMAIN_NAME;";
echo '';
echo ' access_log /dev/null;';
echo ' error_log /dev/null;';
echo '';
echo ' charset utf-8;';
echo '';
echo ' client_max_body_size 75M;';
echo ' location / {';
echo " proxy_pass http://localhost:${ETESYNC_PORT_INTERNAL};";
echo ' location /static {';
echo " alias /var/www/$ETESYNC_DOMAIN_NAME/htdocs;";
echo ' }';
echo ' # Security'; } >> "$etesync_nginx_site"
nginx_ssl "$ETESYNC_DOMAIN_NAME"
nginx_security_options "$ETESYNC_DOMAIN_NAME"
{ echo ' add_header Strict-Transport-Security max-age=15768000;';
echo '}'; } >> "$etesync_nginx_site"
else
echo -n '' > "$etesync_nginx_site"
fi
{ echo 'server {';
echo " listen 127.0.0.1:$ETESYNC_ONION_PORT default_server;";
echo " server_name $ETESYNC_ONION_HOSTNAME;";
echo ' access_log /dev/null;';
echo ' error_log /dev/null;';
echo '';
echo ' client_max_body_size 75M;';
echo ' location / {';
echo " proxy_pass http://localhost:${ETESYNC_PORT_INTERNAL};";
echo ' location /static {';
echo " alias /var/www/$ETESYNC_DOMAIN_NAME/htdocs;";
echo ' }';
groupadd -r etesync
useradd -d "$ETESYNC_PATH" -r -M -s /bin/sh -g etesync etesync
{ echo '[Unit]';
echo 'Description=etesync';
echo 'After=syslog.target';
echo 'After=network.target';
echo "Documentation=$ETESYNC_REPO";
echo '';
echo '[Service]';
echo 'Type=simple';
echo 'User=etesync';
echo 'Group=etesync';
echo "WorkingDirectory=${ETESYNC_PATH}";
echo "ExecStart=/usr/bin/python3 ${ETESYNC_PATH}/manage.py runserver localhost:${ETESYNC_PORT_INTERNAL}";
echo "Environment=ENV DATA_PATH=${ETESYNC_DATA_PATH}";
echo "Environment=DJANGO_STATICS=/var/www/$ETESYNC_DOMAIN_NAME/htdocs";
echo "Environment=DJANGO_PORT=${ETESYNC_PORT_INTERNAL}";
echo 'Environment=SERVER="standalone"';
echo 'Restart=always';
echo 'StandardError=syslog';
echo '';
echo '[Install]';
echo 'WantedBy=multi-user.target'; } > "/etc/systemd/system/etesync.service"
systemctl enable etesync
nginx_ensite "$ETESYNC_DOMAIN_NAME"
systemctl restart nginx
chown -R www-data:www-data "/var/www/$ETESYNC_DOMAIN_NAME/htdocs"
echo "from django.contrib.auth.models import User; User.objects.create_superuser('$MY_USERNAME', '$MY_EMAIL_ADDRESS', '$ETESYNC_ADMIN_PASSWORD')" | python3 manage.py shell
"${PROJECT_NAME}-pass" -u "$MY_USERNAME" -a etesync -p "$ETESYNC_ADMIN_PASSWORD"
set_completion_param "etesync domain" "$ETESYNC_DOMAIN_NAME"
APP_INSTALLED=1
}
# NOTE: deliberately there is no "exit 0"