#!/bin/bash
# Copyright [2016-2019] Syncwerk GmbH
set -e

# Export variables
export PATH=/usr/local/sbin:/usr/local/bin:$PATH
export PYTHONPATH=/usr/share/python/syncwerk/restapi/lib/python2.7/site-packages
export CONFIG_DIR=/etc/syncwerk
export CCNET_CONF_DIR=${CONFIG_DIR}
export SYNCWERK_CONF_DIR=${CONFIG_DIR}
export SYNCWERK_CENTRAL_CONF_DIR=${CONFIG_DIR}
export RESTAPI_DIR=/usr/share/python/syncwerk/restapi
export DJANGO_SETTINGS_MODULE=restapi.settings
export RESTAPI_LOG_DIR=/var/log/syncwerk
export TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
export OBJECT_STORAGE_PATH="/var/lib/syncwerk"
export ZIPPING_COMMAND="pigz --fast"
export DIST="$(lsb_release -sc)"
export DISTID="$(lsb_release -si)"
export DEBIAN_FRONTEND=noninteractive
export LIBEVENT_ROOT="/usr/lib/syncwerk/libevent"

if [ -z "${SYNCWERK_HOSTNAME}" ] ; then
  export HOSTNAME="$(hostname -f)"
else
  export HOSTNAME="${SYNCWERK_HOSTNAME}"
fi


function setup-user {
id -u syncwerk > /dev/null || adduser --system --gecos "syncwerk" syncwerk --home /usr/share/syncwerk
}


function purge {
cat <<EOF

  USE WITH EXTREME CAUTION

  Proceeding WILL permanently DELETE data WITHOUT further NOTICE

  Purge Syncwerk Server on dedicated machine. Don't use on servers
  with other shared services. ALL databases, stored files and
  configurations will get permantly deleted. This script is only
  intended for development purposes where we need to quickly purge
  Syncwerk server installations and perform a fresh reinstallation.

  Hit return to proceed or CTRL-C to abort.

EOF
read dummy
WAIT=7 ; while [ ${WAIT} -gt 0 ] ; do printf "\r  You have %2d second(s) to change your mind. Hit CTRL-C to abort." ${WAIT} ; sleep 1 ; ((WAIT--)) ; done ; echo
syncwerk-server stop
pkill -SIGKILL -f "mysqld" || true
apt purge $(dpkg -l "*syncwerk*" | grep ii | awk '{ print $2 }' | xargs) -y
for TYPE in d f ; do find / -iname "*syncwerk*" -type ${TYPE} | while read LINE ; do rm -rf ${LINE} ; done ; done
apt purge $(dpkg -l "*mariadb*"  | grep ii | awk '{ print $2 }' | xargs) -y
rm -rf /etc/nginx/conf.d/syncwerk.conf
pkill -SIGKILL -f "nginx" || true
apt purge nginx -y
apt-get autoremove -y
aptitude purge ~c -y
rm -rf /var/lib/mysql/ /etc/mysql/
apt-get update
}


# Install python tools
function install-python-tools {
command pip  > /dev/null 2>&1 || (echo "Installing latest Python pip 2.7" ; curl -s https://syncwerk.io/python2.7/get-pip.py | python2.7)
echo "Installing virtualenv 16.7.9" ; pip install virtualenv==16.7.9
echo "Installing virtualenv-tools 1.0.0" ; pip install virtualenv-tools==1.0

}


# Setup virtualenv
function setup-virtualenv {
#   Creating MySQL symlink for Python MySQL module to build on jessie and xenial
if [ ${DIST} = jessie ] || [ ${DIST} = xenial ] ; then
  ln -sf /usr/bin/mariadb_config /usr/bin/mysql_config
fi
virtualenv --python=python2.7 /usr/share/python/syncwerk/restapi
if ! md5sum --check /tmp/syncwerk_restapi_requirements_txt.md5 > /dev/null 2>&1 ; then
  echo "Python requirements changed. Updating.."
  /usr/share/python/syncwerk/restapi/bin/python2.7 /usr/share/python/syncwerk/restapi/bin/pip freeze | xargs pip uninstall -y || true
  /usr/share/python/syncwerk/restapi/bin/python2.7 /usr/share/python/syncwerk/restapi/bin/pip install -r /usr/share/python/syncwerk/restapi/requirements.txt
else
  echo "Python requirements have not changed. Skipping update.."
fi
# Delete md5 file created during package system preinst phase 
if [ -f /tmp/syncwerk_restapi_requirements_txt.md5 ] ; then 
  rm /tmp/syncwerk_restapi_requirements_txt.md5
fi
}


# Install Let's Encrypt certificate
function setup-letsencrypt-certificate {
unset PYTHONPATH
command certbot -h > /dev/null 2>&1 || ( if [ "${DISTID}" = "Debian" ] ; then echo "Certbot is not installed. Please install it manually and try again." ; fi )
command certbot -h > /dev/null 2>&1 || ( if [ "${DISTID}" = "Ubuntu" ] ; then apt-get update ; apt-get install software-properties-common -y ; add-apt-repository ppa:certbot/certbot -y ; fi ; apt-get update ; apt-get install certbot -y )
if [ ! -f "/etc/letsencrypt/renewal/${HOSTNAME}.conf" ] ; then
certbot certonly --standalone --agree-tos --preferred-challenges http-01 --http-01-port 54321 --domains ${HOSTNAME} --register-unsafely-without-email || exit
sed -i '/.*ssl_certificate.*\/ssl\/syncwerk.crt/ s/^#*/#/' /etc/nginx/conf.d/syncwerk.conf
sed -i '/.*ssl_certificate.*\/ssl\/syncwerk.key/ s/^#*/#/' /etc/nginx/conf.d/syncwerk.conf
grep 'letsencrypt/live' /etc/nginx/conf.d/syncwerk.conf || \
eval "sed -i '/.*  ssl on;/a \ \
 ssl_certificate \/etc\/letsencrypt\/live\/${HOSTNAME}\/fullchain.pem;\n \
 ssl_certificate_key \/etc\/letsencrypt\/live\/${HOSTNAME}\/privkey.pem;\
 ' /etc/nginx/conf.d/syncwerk.conf" && \
nginx -t && \
service nginx restart
echo "Your Let's Encrypt certificate has been installed"
else
certbot renew
sed -i '/.*ssl_certificate.*\/ssl\/syncwerk.crt/ s/^#*/#/' /etc/nginx/conf.d/syncwerk.conf
sed -i '/.*ssl_certificate.*\/ssl\/syncwerk.key/ s/^#*/#/' /etc/nginx/conf.d/syncwerk.conf
grep 'letsencrypt/live' /etc/nginx/conf.d/syncwerk.conf || \
eval "sed -i '/.*  ssl on;/a \ \
 ssl_certificate \/etc\/letsencrypt\/live\/${HOSTNAME}\/fullchain.pem;\n \
 ssl_certificate_key \/etc\/letsencrypt\/live\/${HOSTNAME}\/privkey.pem;\
 ' /etc/nginx/conf.d/syncwerk.conf" && \
nginx -t && \
service nginx restart
echo "Your Let's Encrypt certificate has been installed"
fi
export PYTHONPATH=/usr/share/python/syncwerk/restapi/lib/python2.7/site-packages
}


# Install ONLYOFFICE Document Server - Don't call during initial setup since it will break due to dpkg locks
function setup-onlyoffice {
if [ -f /etc/supervisor/conf.d/onlyoffice-documentserver.conf ] ; then 
echo "ONLYOFFICE document server config exists. Skipping.."
else
curl -sL https://deb.nodesource.com/setup_10.x | sed 's/^script_deprecation_warning$/#script_deprecation_warning/g; s/^node_deprecation_warning$/#node_deprecation_warning/g' | bash -
apt-get install postgresql -y
if [ -f /.dockerenv ] ; then service postgresql start ; fi
sudo -i -u postgres psql -c "CREATE DATABASE onlyoffice;"
sudo -i -u postgres psql -c "CREATE USER onlyoffice WITH password 'onlyoffice';"
sudo -i -u postgres psql -c "GRANT ALL privileges ON DATABASE onlyoffice TO onlyoffice;"
apt-get install redis-server -y
if [ -f /.dockerenv ] ; then service redis-server start ; fi
apt-get install rabbitmq-server -y
if [ -f /.dockerenv ] ; then service rabbitmq-server start ; fi
if [ -f /.dockerenv ] ; then service nginx start ; fi
echo "onlyoffice-documentserver onlyoffice/db-pwd password onlyoffice
onlyoffice-documentserver onlyoffice/ds-port string 9090" | debconf-set-selections
echo "deb [signed-by=/usr/share/keyrings/onlyoffice.gpg] https://repo.syncwerk.com/repo/mirror/download.onlyoffice.com/repo/debian squeeze main" > /etc/apt/sources.list.d/syncwerk-onlyoffice-mirror.list
curl -fsSL https://download.onlyoffice.com/GPG-KEY-ONLYOFFICE | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/onlyoffice.gpg --import
chmod 644 /usr/share/keyrings/onlyoffice.gpg
apt-get update
apt-get install onlyoffice-documentserver -y
if [ -f /.dockerenv ] ; then service supervisor start ; fi
#if [[ "${DIST}" = "bionic" || "${DIST}" = "buster" ]] ; then
#  # Rebuilding spellchecker for Ubuntu 18.04 and Debian 10 to work correctly
#  apt-get update
#  apt-get install npm -y
#  npm install -g npm
#  supervisorctl stop all
#  apt-get install build-essential git -y
#  cd /var/www/onlyoffice/documentserver/server/SpellChecker/
#  rm -rf node_modules
#  npm install 2> /dev/null 
#  chown -R ds:ds node_modules
#  supervisorctl start all
#fi
sed -i '/ONLYOFFICE/s/^#//g' /etc/syncwerk/restapi_settings.py
# Kill restapi process. Restart will get triggered by monitoring service.
kill $(pidof web-service)
if [ -f /.dockerenv ] ; then
  update-rc.d -f rabbitmq-server disable
  service rabbitmq-server stop
cat > /etc/supervisor/conf.d/rabbitmq.conf <<EOF
[program:rabbitmq-server]
command=/usr/sbin/rabbitmq-server
autostart=true
autorestart=true
EOF
fi
fi
# Upgrading connection limit from 20 to 200 connections # This hack no longer works
#sed -i 's/exports.LICENSE_CONNECTIONS.*/exports.LICENSE_CONNECTIONS = 200;/g' /var/www/onlyoffice/documentserver/server/Common/sources/constants.js
# Hide ONLYOFFICE logo
sed -i 's/#header-logo{max-width/#header-logo{display:none;max-width/g' /var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/main/resources/css/app.css /var/www/onlyoffice/documentserver/web-apps/apps/spreadsheeteditor/main/resources/css/app.css /var/www/onlyoffice/documentserver/web-apps/apps/presentationeditor/main/resources/css/app.css
supervisorctl reload
}


# Ensuring required dirs exist
mkdir -p ${OBJECT_STORAGE_PATH}/template ${OBJECT_STORAGE_PATH}/avatars /var/log/syncwerk


function start-database {
if [ -f /.dockerenv ] ; then
  service mysql start
fi
}


function create-database {
if [ ! -f "/etc/syncwerk/mysql.txt" ] ; then
SYNCWERK_DB_PW=$(pwgen 14 1)
cat > /etc/syncwerk/mysql.txt <<EOF
[client]
user=syncwerk
password=${SYNCWERK_DB_PW}
EOF
chmod 600 /etc/syncwerk/mysql.txt
mysql -e "CREATE DATABASE IF NOT EXISTS \`syncwerk-ccnet\` character set = 'utf8';"
mysql -e "CREATE DATABASE IF NOT EXISTS \`syncwerk-server\` character set = 'utf8';"
mysql -e "CREATE DATABASE IF NOT EXISTS \`syncwerk-restapi\` character set = 'utf8';"
mysql -e "CREATE USER 'syncwerk'@'localhost' IDENTIFIED BY '${SYNCWERK_DB_PW}';"
mysql -e "GRANT ALL PRIVILEGES ON  \`syncwerk-ccnet\` . * TO  'syncwerk'@'localhost';"
mysql -e "GRANT ALL PRIVILEGES ON  \`syncwerk-server\` . * TO  'syncwerk'@'localhost';"
mysql -e "GRANT ALL PRIVILEGES ON  \`syncwerk-restapi\` . * TO  'syncwerk'@'localhost';"
else
    echo "/etc/syncwerk/mysql.txt exists. Skipping.."
fi
}


function update-database {
# Ensuring paths in virtualenv are valid
virtualenv-tools --reinitialize /usr/share/python/syncwerk/restapi

# Ensuring sql_mode is set
grep -q sql_mode /etc/syncwerk/restapi_settings.py || sed -i 's/storage_engine=INNODB/storage_engine=INNODB, sql_mode=STRICT_TRANS_TABLES/' /etc/syncwerk/restapi_settings.py

echo "Upgrading restapi database"
mysql --force syncwerk-restapi < /usr/share/python/syncwerk/restapi/sql/latest-restapi.sql

# Ensuring institutions are renamed
mysql --force syncwerk-restapi <<EOF  >& /dev/null
RENAME TABLE \`syncwerk-restapi\`.\`institutions_institution\` TO \`syncwerk-restapi\`.\`tenants_tenant\`;
RENAME TABLE \`syncwerk-restapi\`.\`institutions_institutionadmin\` TO \`syncwerk-restapi\`.\`tenants_tenantadmin\`;
RENAME TABLE \`syncwerk-restapi\`.\`institutions_institutionquota\` TO \`syncwerk-restapi\`.\`tenants_tenantquota\`;
ALTER TABLE \`tenants_tenantadmin\` CHANGE \`institution_id\` \`tenant_id\` INT(11) NOT NULL;
ALTER TABLE \`tenants_tenantquota\` CHANGE \`institution_id\` \`tenant_id\` INT(11) NOT NULL;
ALTER TABLE \`profile_profile\` CHANGE \`institution\` \`tenant\` VARCHAR(225) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
UPDATE \`django_migrations\` SET \`app\` = Replace(app, 'institution', 'tenant') WHERE \`app\` like "%institution%";
UPDATE \`django_migrations\` SET \`name\` = Replace(name, 'institution', 'tenant') WHERE \`name\` like "%institution%";
UPDATE \`auth_permission\` SET \`name\` = Replace(name, 'institution', 'tenant') WHERE \`name\` like "%institution%";
UPDATE \`auth_permission\` SET \`codename\` = Replace(codename, 'institution', 'tenant') WHERE \`name\` like "%institution%";
EOF

# Ensuring shared repo table is updated
mysql --force syncwerk-server <<EOF  >& /dev/null
ALTER TABLE \`syncwerk-server\`.\`SharedRepo\` ADD \`allow_view_history\` BOOLEAN DEFAULT True;
ALTER TABLE \`syncwerk-server\`.\`SharedRepo\` ADD \`allow_view_snapshot\` BOOLEAN DEFAULT False;
ALTER TABLE \`syncwerk-server\`.\`SharedRepo\` ADD \`allow_restore_snapshot\` BOOLEAN DEFAULT False;
EOF

# Upgrading API3 related tables
/usr/share/python/syncwerk/restapi/manage.py migrate api3 > /dev/null 2>&1 || true

# Ensuring django site id is set. Otherwise public user registration fails..
mysql -e "INSERT INTO \`syncwerk-restapi\`.\`django_site\` VALUES (1,'example.com','example.com');" || true

# Ensuring api2_tokenv2 is migrated to api3_tokenv2
mysql -e "INSERT INTO \`syncwerk-restapi\`.\`api3_tokenv2\` SELECT * FROM \`syncwerk-restapi\`.\`api2_tokenv2\` AS \`tmp\` WHERE NOT EXISTS ( SELECT * FROM \`syncwerk-restapi\`.\`api3_tokenv2\` WHERE \`syncwerk-restapi\`.\`api3_tokenv2\`.user = \`tmp\`.user AND \`syncwerk-restapi\`.\`api3_tokenv2\`.device_id = \`tmp\`.device_id );" || true

# Check if the database layout has changed. Requires latest-restapi.sql to include all recent changes at any time
if ! md5sum --check /tmp/syncwerk_restapi_sql.md5 > /dev/null 2>&1 ; then
  echo "Reinitialising restapi database schema. This may take a while.."
  for i in $(python /usr/share/python/syncwerk/restapi/manage.py migrate --fake 2> /dev/null | grep "Apply all migrations" | sed 's/Apply all migrations://g; s/, / /g' | xargs) ; do
    python /usr/share/python/syncwerk/restapi/manage.py migrate ${i} > /dev/null 2>&1 || python /usr/share/python/syncwerk/restapi/manage.py migrate ${i} --fake > /dev/null 2>&1
  done
else
  echo "Restapi database schema has not changed. Skipping update.."
fi
# Delete md5 file created during package system preinst phase 
if [ -f /tmp/syncwerk_restapi_sql.md5 ] ; then 
  rm /tmp/syncwerk_restapi_sql.md5
fi

# Fixing typo issue introduce at https://gitlab.syncwerk.com/development/free/syncwerk-server-restapi/-/commit/278b925d217bf2cc75b9117462641774b1f1dc9c
mysql -e "ALTER TABLE \`syncwerk-restapi\`.\`AuditLog\` CHANGE COLUMN \`recepient\` \`recipient\` longtext;" > /dev/null 2>&1 || true

echo "Upgrading ccnet database"
mysql --force syncwerk-ccnet < /usr/share/python/syncwerk/restapi/sql/latest-ccnet.sql > /dev/null 2>&1

# Ensuring language column is present
mysql -e "alter table \`syncwerk-ccnet\`.\`EmailUser\` add \`language\` varchar(255) after \`passwd\`;" > /dev/null 2>&1 || true
mysql -e "alter table \`syncwerk-ccnet\`.\`LDAPUsers\` add \`language\` varchar(255) after \`password\`;" > /dev/null 2>&1 || true 

# Ensuring ctime column is present
mysql -e "alter table \`syncwerk-ccnet\`.\`LDAPUsers\` add \`ctime\` BIGINT after \`is_active\`;" > /dev/null 2>&1 || true 

echo "Upgrading server database"
mysql --force syncwerk-server < /usr/share/python/syncwerk/restapi/sql/latest-server.sql > /dev/null 2>&1
}


function get-database-credentials {
CCNET_DB=$(grep "DB.*=.*" /etc/syncwerk/ccnet.conf | awk '{ print $3 }')
RESTAPI_DB=$(grep "'NAME'.*:.*" /etc/syncwerk/restapi_settings.py | awk -F"'" '{ print $4 }')
SERVER_DB=$(grep -i "db_name" /etc/syncwerk/server.conf | awk '{ print $3 }')
}


function update-translations {
sync
# Updateing translations
for lang in en de ; do nice -n 19 /usr/share/python/syncwerk/restapi/manage.py compilemessages --verbosity 3 --locale ${lang} || true ; done
}


function update-static-files {
sync
# Updateing static files
nice -n 19 /usr/share/python/syncwerk/restapi/manage.py collectstatic --no-input --verbosity 3 || true
}


function help {
cat <<EOF

Name:
  syncwerk-server-admin - A Syncwerk server setup and administration tool

Usage:
  $(basename ${0}) [OPTIONS] [ARGS]

Commands:
  support                         Show how to receive official support
  setup                           Automatically setup production ready Syncwerk server
  update-translations             Update translations (May take very long)
  update-static-files             Update static files (collectstatic)
  start                           Start all Syncwerk server services
  stop                            Stop all Syncwerk server services
  restart                         Restart all Syncwerk server services
  fix-permissions                 Fix file permissions and ownership of Syncwerk server components
  report                          Create report for support requests
  fsck                            Check Syncwerk block storage data
  mount [MOUNTPOINT]              Mount unencrypted folders locally in read only mode
  umount                          Unmount locally mounted folders
  gc                              Run garabage collection to delete admin trash and expired file versions
  change-email-address            Change user accounts email address 
  backup-databases                Backup Syncwerk server databases and save to ${OBJECT_STORAGE_PATH}/backup/
  backup-object-storage           Backup Syncwerk server object storage and save to ${OBJECT_STORAGE_PATH}/backup/
  backup-configurations           Backup Syncwerk server configurations and save to ${OBJECT_STORAGE_PATH}/backup/
  backup-server-applications      Backup installed Syncwerk server application and save to ${OBJECT_STORAGE_PATH}/backup/
  backup-all                      Backup Syncwerk server configuration, databases, object-storage and save to ${OBJECT_STORAGE_PATH}/backup/
  setup-onlyoffice                Install ONLYOFFICE for file preview and editing
  setup-clamav-virus-scanner      Install and setup ClamAV virus scanner 
  run-virus-scanner               Runs virus scanner manually
  setup-letsencrypt-certificate   Install Let's Encrypt certificate for the domain name: ${HOSTNAME}
                                  Make sure the configured domain name publicly resolves to this server before running.
  setup-samba-ad-dc               Install Samba based Active Directory for "$(hostname -d | sed 's/^/DC=/ ; s/\./,DC=/g')"
  create-file-list                Create a list of all files in unencrypted folders


SUPPORT:
  For support contact us at support@syncwerk.com or visit https://www.syncwerk.com

EOF
}


function setup-nginx {
if [ -z "${SYNCWERK_HOSTNAME}" ] ; then
  export HOSTNAME="$(hostname -f)"
else
  export HOSTNAME="${SYNCWERK_HOSTNAME}"
fi

echo "Setup NGINX proxy for Syncwerk services"
if [ ! -f "/etc/nginx/conf.d/syncwerk.conf" ] ; then
mkdir -p /etc/nginx/conf.d/
cat > /etc/nginx/conf.d/syncwerk.conf <<'EOF'
upstream syncwerk-server-restapi {
  server unix:/run/syncwerk/restapi.sock fail_timeout=0;
}

# Required for ONLYOFFICE
map $http_x_forwarded_proto $the_scheme {
        default $http_x_forwarded_proto;
        "" $scheme;
    }

map $http_x_forwarded_host $the_host {
        default $http_x_forwarded_host;
        "" $host;
    }

map $http_upgrade $proxy_connection {
        default upgrade;
        "" close;
    }
    
server {
  listen [::]:80 ipv6only=off;
  server_name  "";
  return 301 https://$http_host$request_uri;
}

server {
  listen [::]:443 ipv6only=off http2;
  server_name  "";
  ssl on;
  ssl_certificate /etc/nginx/ssl/syncwerk.crt;
  ssl_certificate_key /etc/nginx/ssl/syncwerk.key;

  proxy_set_header X-Forwarded-For $remote_addr;
  proxy_max_temp_file_size 0;

  location / {
    try_files $uri $uri/ /index.html;
    root /usr/share/syncwerk/webapp/;
    access_log      /var/log/syncwerk/webapp.log;
    error_log       /var/log/syncwerk/webapp.log;
  }

  location /notification/list {
    return 301 /notifications;
  }

  location /seafhttp {
    rewrite ^/seafhttp(.*)$ $1 break;
    proxy_pass http://127.0.0.1:8082;
    client_max_body_size 0;
    proxy_connect_timeout  36000s;
    proxy_read_timeout  36000s;
    proxy_send_timeout  36000s;
    proxy_request_buffering off;
  }

  location /api2 {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://syncwerk-server-restapi;
    client_max_body_size 0;
    access_log      /var/log/syncwerk/restapi.log;
    error_log       /var/log/syncwerk/restapi.log;
  }
  
  # Sync client: Events place holder FIXME TODO
  location /api2/events/ {
    return 200 '{ "more_offset": 0, "events": [ { "author": "john.doe@example.com", "nick": "John Doe", "time": 1524031159, "repo_name": "Demo", "desc": "Events are not implemented yet" }, { "author": "jane.doe@example.com", "nick": "Jane Doe", "time": 1521266009, "repo_name": "Demo", "desc": "Events are not implemented yet" } ] }';
  }

  # Sync client: File search place holder FIXME TODO
  location /api2/search/ {
    return 200 '{ "has_more": false, "total": 1, "results": [ { "name": "File search is not implemented yet", "is_dir": false, "last_modified": 1520007294, "size": 0 } ] }';
  }

  # Sync client: Enable events and search tabs FIXME TODO
  location /api2/server-info/ {
    return 200 '{"features": ["seafile-basic", "seafile-pro", "office-preview", "file-search"]}';
  }

  location /api3 {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://syncwerk-server-restapi;
    client_max_body_size 0;
    proxy_connect_timeout  120s;
    proxy_read_timeout  120s;
    proxy_send_timeout  120s;
    access_log      /var/log/syncwerk/restapi.log;
    error_log       /var/log/syncwerk/restapi.log;
  }


  location /media {
    root /usr/share/python/syncwerk/restapi/;
  }

  location /client-login {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://syncwerk-server-restapi;
    client_max_body_size 0;
    access_log      /var/log/syncwerk/restapi.log;
    error_log       /var/log/syncwerk/restapi.log;
  }
  
  location /webdav {
    fastcgi_pass    127.0.0.1:8090;
    fastcgi_param   SCRIPT_FILENAME     $document_root$fastcgi_script_name;
    fastcgi_param   PATH_INFO           $fastcgi_script_name;
    fastcgi_param   SERVER_PROTOCOL     $server_protocol;
    fastcgi_param   QUERY_STRING        $query_string;
    fastcgi_param   REQUEST_METHOD      $request_method;
    fastcgi_param   CONTENT_TYPE        $content_type;
    fastcgi_param   CONTENT_LENGTH      $content_length;
    fastcgi_param   SERVER_ADDR         $server_addr;
    fastcgi_param   SERVER_PORT         $server_port;
    fastcgi_param   SERVER_NAME         $server_name;
    fastcgi_param   REMOTE_ADDR         $remote_addr;
    fastcgi_param   HTTPS               on;
    client_max_body_size 0;
    access_log      /var/log/syncwerk/webdav.log;
    error_log       /var/log/syncwerk/webdav.log;
  }
  
  location /onlyofficeds/ {
    proxy_pass http://127.0.0.1:9090/;
    proxy_http_version 1.1;
    client_max_body_size 100M;
    proxy_read_timeout 3600s;
    proxy_connect_timeout 3600s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $proxy_connection;
    proxy_set_header X-Forwarded-Host $the_host/onlyofficeds;
    proxy_set_header X-Forwarded-Proto $the_scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    access_log      /var/log/syncwerk/onlyoffice.log;
    error_log       /var/log/syncwerk/onlyoffice.log;
  }
  
  location /.well-known/acme-challenge {
    proxy_pass http://127.0.0.1:54321;
  }
}
EOF
sed -i "s/HOSTNAME/${HOSTNAME}/g" /etc/nginx/conf.d/syncwerk.conf
else
    echo "/etc/nginx/conf.d/syncwerk.conf exists. Skipping.."
fi
echo


echo "Setting up self-signed SSL certificate for Syncwerk services"
if [ ! -f "/etc/nginx/ssl/syncwerk.key" ] ; then
mkdir -p /etc/nginx/ssl
openssl genrsa -out /etc/nginx/ssl/syncwerk.key 4096
cat > /etc/nginx/ssl/syncwerk.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
countryName = DE
stateOrProvinceName = Bayern
localityName = Wiesentheid
organizationName = Syncwerk GmbH
organizationalUnitName = WebApp
emailAddress = support@syncwerk.com
# Must be last for Syncwerk client to validate...
commonName = ${HOSTNAME}
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:TRUE
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = $(hostname -f)
DNS.3 = $(hostname -s)
EOF
openssl req -new -x509 -key /etc/nginx/ssl/syncwerk.key -out /etc/nginx/ssl/syncwerk.crt -days 10950 -config /etc/nginx/ssl/syncwerk.cnf -sha256
else
    echo "/etc/nginx/ssl/syncwerk.key exists. Skipping.."
fi
echo


echo "Setting up NGINX proxy for Syncwerk services"
echo

echo "Backing up old /etc/nginx/nginx.conf"
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.syncwerk-backup.$(date +"%Y-%m-%d_%H-%M-%S")
echo

echo "Deleting redundant backups"
fdupes /etc/nginx/ | grep "nginx.conf.syncwerk-backup" | xargs rm
echo

echo "Creating optimized nginx.conf"
cat > /etc/nginx/nginx.conf <<ENDOFFILE
worker_processes auto;
events {
  worker_connections 8096;
  multi_accept on;
  use epoll;
}
pid /var/run/nginx.pid;
worker_rlimit_nofile 40000;
http {
  server_tokens off;
  server_names_hash_bucket_size 128;
  client_max_body_size 50M;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
  '\$status \$body_bytes_sent "\$http_referer" '
  '"\$http_user_agent" "\$http_x_forwarded_for"';
  access_log /var/log/nginx/access.log main;
  error_log /var/log/nginx/error.log warn;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  client_body_timeout 12;
  client_header_timeout 12;
  keepalive_timeout 15;
  send_timeout 10;
  gzip on;
  gzip_vary on;
  gzip_proxied expired no-cache no-store private auth any;
  gzip_comp_level 9;
  gzip_min_length 10240;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/xml font/woff2;
  gzip_disable "MSIE [1-6].";
  include /etc/nginx/conf.d/*.conf;
  map \$scheme \$php_https {
    default off;
    https on;
  }
  include perfect-forward-secrecy.conf;
}
ENDOFFILE
echo


echo "Setting up perfect forward secrecy"
if [ ! -f "/etc/nginx/perfect-forward-secrecy.conf" ] ; then
openssl dhparam -dsaparam -out /etc/nginx/dh4096.pem 4096
cat > /etc/nginx/perfect-forward-secrecy.conf <<'EOF'
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA";
ssl_dhparam dh4096.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
EOF
echo
else
    echo "/etc/nginx/ssl/syncwerk.key exists. Skipping.."
fi


# Ensuring log dir exists
mkdir -p /var/log/syncwerk/
echo


OS=$(lsb_release -sc)
if [ ${OS} = jessie ] ; then
  echo "Removing HTTP/2 extension"
  sed -i 's/http2//g' /etc/nginx/conf.d/syncwerk.conf
  echo
fi


echo "Restarting NGINX"
service nginx restart
}


function setup-ccnet-conf {
SERVERID="$(cat /dev/urandom | tr -dc "a-fA-F0-9" | fold -w 40 | head -n 1)"
DBUSER="$(grep user /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
DBPASS="$(grep password /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
DBNAME="syncwerk-ccnet"
sed -i "s/SERVERID/${SERVERID}/g" /etc/syncwerk/ccnet.conf
sed -i "s/HOSTNAME/${HOSTNAME}/g" /etc/syncwerk/ccnet.conf
sed -i "s/DBUSER/${DBUSER}/g" /etc/syncwerk/ccnet.conf
sed -i "s/DBPASS/${DBPASS}/g" /etc/syncwerk/ccnet.conf
sed -i "s/DBNAME/${DBNAME}/g" /etc/syncwerk/ccnet.conf
}


function setup-my-key-peer {
if [ ! -f "/etc/syncwerk/mykey.peer" ] ; then
openssl genrsa -out /etc/syncwerk/mykey.peer 2048
chmod 600 /etc/syncwerk/mykey.peer
else
    echo "/etc/syncwerk/mykey.peer exists. Skipping.."
fi
}


function setup-ccnet-database {
# Setup EmailUser and LDAPUsers tables so syncwerk-server binary is satisfied and will not abort. CCNET will create the other missing tables during startup.
mysql -e "CREATE TABLE IF NOT EXISTS \`syncwerk-ccnet\`.\`EmailUser\` ( \`id\` int(11) NOT NULL AUTO_INCREMENT, \`email\` varchar(255) DEFAULT NULL, \`passwd\` varchar(256) DEFAULT NULL, \`is_staff\` tinyint(1) NOT NULL, \`is_active\` tinyint(1) NOT NULL, \`ctime\` bigint(20) DEFAULT NULL, PRIMARY KEY (\`id\`), UNIQUE KEY \`email\` (\`email\`) );"
mysql -e "CREATE TABLE IF NOT EXISTS \`syncwerk-ccnet\`.\`LDAPUsers\` ( \`id\` bigint(20) NOT NULL AUTO_INCREMENT, \`email\` varchar(255) NOT NULL, \`password\` varchar(255) NOT NULL, \`language\` varchar(255) DEFAULT NULL, \`is_staff\` tinyint(1) NOT NULL, \`is_active\` tinyint(1) NOT NULL, \`ctime\` bigint(20) DEFAULT NULL, \`extra_attrs\` text DEFAULT NULL, \`reference_id\` varchar(255) DEFAULT NULL, PRIMARY KEY (\`id\`), UNIQUE KEY \`email\` (\`email\`), UNIQUE KEY \`reference_id\` (\`reference_id\`) );"
}


function setup-file-server-conf {
DBUSER="$(grep user /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
DBPASS="$(grep password /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
DBNAME="syncwerk-server"
sed -i "s/DBUSER/${DBUSER}/g" /etc/syncwerk/server.conf
sed -i "s/DBPASS/${DBPASS}/g" /etc/syncwerk/server.conf
sed -i "s/DBNAME/${DBNAME}/g" /etc/syncwerk/server.conf
}


function setup-gunicorn-conf {
if [ ! -f "/etc/syncwerk/gunicorn.conf" ] ; then
cat > /etc/syncwerk/gunicorn.conf <<EOF
import multiprocessing
daemon = False
workers = multiprocessing.cpu_count()
threads = 5
timeout = 1200
pid = "/run/syncwerk/restapi.pid"
bind = "unix:/run/syncwerk/restapi.sock"
EOF
else
    echo "/etc/syncwerk/gunicorn.conf exists. Skipping.."
fi
}


function setup-restapi-settings-py {
SECRETKEY="$(</dev/urandom tr -dc 'A-Za-z0-9!#$%&\''()*+,-.:;<=>?@[\]^_`{|}~' | head -c 50  ; echo)"
APIDBNAME="syncwerk-restapi"
CCNETDBNAME="syncwerk-ccnet"
SERVERDBNAME="syncwerk-server"
DBUSER="$(grep user /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
DBPASS="$(grep password /etc/syncwerk/mysql.txt | awk -F"=" '{ print $2}')"
sed -i "s/SECRETKEY/${SECRETKEY}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/APIDBNAME/${APIDBNAME}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/CCNETDBNAME/${CCNETDBNAME}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/SERVERDBNAME/${SERVERDBNAME}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/DBUSER/${DBUSER}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/DBPASS/${DBPASS}/g" /etc/syncwerk/restapi_settings.py
sed -i "s/HOSTNAME/${HOSTNAME}/g" /etc/syncwerk/restapi_settings.py
sed -i 's/default_admin/superadmin/g' /etc/syncwerk/restapi_settings.py
}


function setup-services {
# Ensuring required dirs exist
mkdir -p ${OBJECT_STORAGE_PATH}/template ${OBJECT_STORAGE_PATH}/avatars /var/log/syncwerk

# Ensuring correct ownerships is set
chown -R syncwerk:nogroup /etc/syncwerk /usr/share/python/syncwerk /usr/share/syncwerk /var/log/syncwerk
ps aux | grep "chown -R syncwerk:nogroup /var/lib/syncwerk" | grep -vq grep || (nice -n 19 chown -R syncwerk:nogroup /var/lib/syncwerk &)

if [[ ! $(tr -d '\0' < /proc/1/environ) == *container* ]] ; then
echo "Setting up systemd autostart"
cat > /etc/systemd/system/syncwerk-server.service <<'EOF'
[Unit]
Description=Syncwerk Server
After=network.target mysql.service
[Service]
Type=simple
ExecStart=/usr/bin/syncwerk-server start --foreground
ExecStop=/usr/bin/syncwerk-server stop
[Install]
WantedBy=multi-user.target
EOF
systemctl enable syncwerk-server
else
echo "Setting up sysv autostart"
cat > /etc/init.d/syncwerk-server <<'EOF'
#!/bin/bash
### BEGIN INIT INFO
# Provides:          syncwerk-server
# Required-Start:    $remote_fs $syslog mysql
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Syncwerk server
# Description:       Start Syncwerk server
### END INIT INFO
# Author: Alexander Jackson <alexander.jackson@syncwerk.com>
#
case "$1" in
  start)
    /usr/bin/syncwerk-server start
    ;;
  restart)
    /usr/bin/syncwerk-server stop
    /usr/bin/syncwerk-server start
    ;;
  stop)
    /usr/bin/syncwerk-server stop
    ;;
  *)
    echo "Usage: /etc/init.d/syncwerk-server {start|stop|restart}"
    exit 1
    ;;
esac
EOF
chmod +x /etc/init.d/syncwerk-server
update-rc.d syncwerk-server defaults
fi

if [ -f /.dockerenv ] ; then
cat > /etc/init.d/syncwerk-server <<'EOF'
#!/bin/bash
### BEGIN INIT INFO
# Provides:          syncwerk-server
# Required-Start:    $remote_fs $syslog mysql
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Syncwerk server
# Description:       Start Syncwerk server
### END INIT INFO
# Author: Alexander Jackson <alexander.jackson@syncwerk.com>
#
case "$1" in
  start)
    /usr/bin/syncwerk-server start
    ;;
  restart)
    /usr/bin/syncwerk-server stop
    /usr/bin/syncwerk-server start
    ;;
  stop)
    /usr/bin/syncwerk-server stop
    ;;
  status)
    if PID=$(pgrep -f /usr/bin/syncwerk-server)
    then
      echo "syncwerk-server is running with PID ${PID}"
    else
      echo "syncwerk-server is not running"
    fi
    ;;
  *)
    echo "Usage: /etc/init.d/syncwerk-server {start|stop|restart|status}"
    exit 1
    ;;
esac

EOF
chmod +x /etc/init.d/syncwerk-server
update-rc.d syncwerk-server defaults
fi
}


function migrate-avatars {
if [ -L /usr/share/python/syncwerk/restapi/media/avatars ] ; then 
  echo "Avatars seem migrated. Aborting.." 
else 
  mkdir -p /var/lib/syncwerk/avatars
  if [ -e /usr/share/python/syncwerk/restapi/media/avatars/ ] ; then
    mv /usr/share/python/syncwerk/restapi/media/avatars/* /var/lib/syncwerk/avatars/
    rm -rf /usr/share/python/syncwerk/restapi/media/avatars
  fi
  ln -s /var/lib/syncwerk/avatars /usr/share/python/syncwerk/restapi/media/avatars
  chown -R syncwerk:nogroup /var/lib/syncwerk/avatars /usr/share/python/syncwerk/restapi/media/avatars    
fi
}


function fix-permissions {
# Ensuring required dirs exist
mkdir -p ${OBJECT_STORAGE_PATH}/template ${OBJECT_STORAGE_PATH}/avatars /var/log/syncwerk

echo "Ensuring correct ownership is set. Running chown in background..."
chown -R syncwerk:nogroup /etc/syncwerk /usr/share/python/syncwerk /usr/share/syncwerk /var/log/syncwerk
ps aux | grep "chown -R syncwerk:nogroup /var/lib/syncwerk" | grep -vq grep || (nice -n 19 chown -R syncwerk:nogroup /var/lib/syncwerk &)
}


function stop {
syncwerk-server stop
}


function start {
if [ ! -f /.dockerenv ] ; then
  systemctl start syncwerk-server.service
else
  service syncwerk-server start
fi
command supervisorctl start all > /dev/null 2>&1 || true
}


function restart {
stop
start
}


function fsck {
sudo -u syncwerk bash -c "syncwerk-server-fsck -c /etc/syncwerk -d /var/lib/syncwerk -F /etc/syncwerk ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} | tee -a /var/log/syncwerk/fsck.log"
}


function mount {
touch /var/log/syncwerk/fuse.log
chown syncwerk:nogroup /var/log/syncwerk/fuse.log
syncwerk-server-fuse -c /etc/syncwerk/ -F /etc/syncwerk/ -d ${OBJECT_STORAGE_PATH} -l /var/log/syncwerk/fuse.log ${1}
}


function umount {
pkill -SIGTERM -f "syncwerk-server-fuse" || true
}


function gc {
sudo -u syncwerk bash -c "syncwerk-server-gc -c /etc/syncwerk -d /var/lib/syncwerk -F /etc/syncwerk ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} | tee -a /var/log/syncwerk/gc.log"
}


function backup-databases {
get-database-credentials
if [ ! -z "${CCNET_DB}" ] ; then
  if mysqlshow ${CCNET_DB} > /dev/null 2>&1 && mysqlshow ${RESTAPI_DB} > /dev/null 2>&1 && mysqlshow ${SERVER_DB} > /dev/null 2>&1 ; then
    echo "Could not backup databases. They probably don't exist yet. Skipping.."
  else
    echo "Backing up current databases"
    mkdir -p ${OBJECT_STORAGE_PATH}/backup
    mysqldump --databases ${CCNET_DB} ${RESTAPI_DB} ${SERVER_DB} | pigz > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-databases.sql.gz
    echo "Calculating sha256sum for databases backup file"
    pv ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-databases.sql.gz | sha256sum > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-databases.sql.gz.sha256.txt
  fi
else
  echo "Databases not configured. Skipping backup.."
fi
}


function backup-object-storage {
AVAILABLE_SPACE_ON_BACKUP_DRIVE=$(df --output=avail -m ${OBJECT_STORAGE_PATH}/backup/ | tail -1)
TOTAL_SPACE_USED_FOR_BLOCK_STORAGE=$(du --total --summarize --block-size=1M ${OBJECT_STORAGE_PATH}/fs ${OBJECT_STORAGE_PATH}/storage ${OBJECT_STORAGE_PATH}/commits | tail -1 | cut -f1)
AVAILABLE_SPACE_AFTER_BACKUP=$(( AVAILABLE_SPACE_ON_BACKUP_DRIVE - TOTAL_SPACE_USED_FOR_BLOCK_STORAGE ))
if [[ ${AVAILABLE_SPACE_AFTER_BACKUP} -gt 2000 ]] ; then
  (( ${AVAILABLE_SPACE_AFTER_BACKUP} >= $(( AVAILABLE_SPACE_ON_BACKUP_DRIVE - $(( TOTAL_SPACE_USED_FOR_BLOCK_STORAGE * 3 / 2 )) )) )) || (echo "Not enough backup space available. You need to free up at least $(( AVAILABLE_SPACE_ON_BACKUP_DRIVE - $(( TOTAL_SPACE_USED_FOR_BLOCK_STORAGE * 3 / 2 )))) MB of disk space at ${OBJECT_STORAGE_PATH}/backup/" | tee ${OBJECT_STORAGE_PATH}/${TIMESTAMP}_syncwerk-object-storage-backup-not-possible-due-to-insufficient-backup-space.txt ; df -h >> ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage-backup-not-possible-due-to-insufficient-backup-space.txt ; exit)
  echo "Backing up object storage"
  mkdir -p ${OBJECT_STORAGE_PATH}/backup
  tar --exclude="${OBJECT_STORAGE_PATH}/backup" -cf - ${OBJECT_STORAGE_PATH} | pv -s $(du -sb ${OBJECT_STORAGE_PATH} | awk '{print $1}') | ${ZIPPING_COMMAND} > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage.gz
  #tar --exclude="${OBJECT_STORAGE_PATH}/backup" -cf - ${OBJECT_STORAGE_PATH} | pv -s $(du -sb ${OBJECT_STORAGE_PATH} | awk '{print $1}') | ${ZIPPING_COMMAND} | gpg --batch --symmetric --passphrase MySecretPassword1 --cipher-algo aes256 -o backup.tar.gz.gpg
  echo "Calculating sha256sum for object storage backup file"
  pv ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage.gz | sha256sum > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage.gz.sha256.txt
else
  echo "Not enough backup space available. You need to free at least 2000 MB of disk space on ${OBJECT_STORAGE_PATH}/backup/. Then try again." | tee ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage-backup-not-possible-due-to-insufficient-backup-space.txt ; df -h >> ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-object-storage-backup-not-possible-due-to-insufficient-backup-space.txt
fi
}


function backup-configurations {
echo "Backing up configuration"
mkdir -p ${OBJECT_STORAGE_PATH}/backup
tar -cf - /etc/syncwerk/ /etc/nginx/ /etc/mysql/ | ${ZIPPING_COMMAND} > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-configurations.gz
echo "Calculating sha256sum for configurations backup file"
pv ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-configurations.gz | sha256sum > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-configurations.gz.sha256.txt
}


function backup-server-applications {
echo "Backing up server application"
mkdir -p ${OBJECT_STORAGE_PATH}/backup
tar -cf - /usr/bin/syncwerk-server* /usr/sbin/syncwerk-server* /usr/include/syncwerk /usr/share/python/syncwerk /usr/share/syncwerk | pv -s $(du --total --summarize --block-size=1M /usr/bin/syncwerk-server* /usr/sbin/syncwerk-server* /usr/include/syncwerk /usr/share/python/syncwerk /usr/share/syncwerk | tail -1 | cut -f1) | ${ZIPPING_COMMAND} > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-server-applications.gz
pv ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-server-applications.gz | sha256sum > ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_syncwerk-server-applications.gz.sha256.txt
}


function backup-all {
backup-configurations
backup-server-applications
backup-databases
backup-object-storage
echo "Here are your backups"
ls -ahl ${OBJECT_STORAGE_PATH}/backup/${TIMESTAMP}_*
}


function create-admin {
if [ ! -f "/etc/syncwerk/admin.txt" ] ; then
echo "Creating Syncwerk admin user"
ADMIN_USER=admin@${HOSTNAME}
ADMIN_PASSWORD=$(pwgen 14 1)
cat > /etc/syncwerk/admin.txt <<EOF
{
  "email": "${ADMIN_USER}",
  "password": "${ADMIN_PASSWORD}"
}
EOF
/usr/share/python/syncwerk/restapi/bin/python2.7 /usr/share/python/syncwerk/restapi/restapi/create-admin.py
echo "Saving Syncwerk admin credentials to /etc/syncwerk/admin.txt"
cat > /etc/syncwerk/admin.txt <<EOF
Mail = ${ADMIN_USER}
Pass = ${ADMIN_PASSWORD}
EOF
chmod 600 /etc/syncwerk/admin.txt
chown syncwerk:nogroup /etc/syncwerk/admin.txt
echo
fi
}


function report {
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
SERVERID=$(syncwerk-server show-id)
cat >> /var/log/syncwerk/report.log <<EOF
Syncwerk Server System Report created on &(date)


Syncwerk Server ID
-------------------------------------------------------
${SERVERID}


Hostnames
-------------------------------------------------------
$(hostname -f),$(hostname -s),$(hostname -d),$(hostname -i),${HOSTNAME}


Content of /etc/hosts
-------------------------------------------------------
$(cat /etc/hosts)


OS
-------------------------------------------------------
$(lsb_release -a)


OS Architecture
-------------------------------------------------------
${ARCH}


Debian Package Architecture
-------------------------------------------------------
${DEB_ARCH}


CPU info
-------------------------------------------------------
$(cat /proc/cpuinfo)


Memory info
-------------------------------------------------------
$(cat /proc/meminfo)


Active Kernel
-------------------------------------------------------
$(uname -a)


Network Interfaces
-------------------------------------------------------
$(ifconfig -a)


IP Addresses
-------------------------------------------------------
$(ip addr show)


DNS Servers
-------------------------------------------------------
$(cat /etc/resolv.conf)


Routes
-------------------------------------------------------
$(route -n)


Content of /etc/network/interfaces
-------------------------------------------------------
$(cat /etc/network/interfaces)


Debian Version
-------------------------------------------------------
$(cat /etc/debian_version)ort created on &(date)

$(find /etc/apt/ -type f | grep -v gpg | while read line ; do echo ; \
    echo Content of ${line} ; \
    cat ${line} ; \
    echo ;
done)


Installed packages
-------------------------------------------------------
$(dpkg -l)


Process List
-------------------------------------------------------
$(ps axu)


Local user accounts
-------------------------------------------------------
$(cat /etc/passwd)
EOF

tar czf /tmp/syncwerk-server-report_${TIMESTAMP}.tgz --exclude="admin.txt" --exclude="mykey.peer" --exclude="*.pyc" /etc/apt /etc/syncwerk /var/log/syncwerk > /dev/null 2>&1
chmod 600 /tmp/syncwerk-server-report_${TIMESTAMP}.tgz /var/log/syncwerk/report.log
cat <<EOF


  EN The report has been saved to /tmp/syncwerk-server-report_${TIMESTAMP}.tgz
     Would you like to submit the report to Syncwerk for further investigations?
     Press Y for Yes and N for No

     Privacy information can be found at https://www.syncwerk.com/en/privacy-disclaimer/


  DE Der Report wurde unter /tmp/syncwerk-server-report_${TIMESTAMP}.tgz gespeichert
     Möchten Sie den Report zur weiteren Diagnose an Syncwerk übermitteln?
     Drücken Sie J für Ja oder N für Nein

     Datenschutzinfos finden Sie unter https://www.syncwerk.com/datenschutzerklaerung/


EOF

read -p "Submit report to Syncwerk? [YyNn] / Report an Syncwerk übertragen? [JjNn]" -n 1 -r
if [[ ${REPLY} =~ ^[YyJj]$ ]]
then
mv /tmp/syncwerk-server-report_${TIMESTAMP}.tgz /tmp/syncwerk-server-report_${SERVERID}_${TIMESTAMP}.tgz
curl -sS "https://$(curl 'https://app.syncwerk.de/ajax/u/d/01ff77fb9f/upload/?r=d99f9958-cedd-41f0-b513-21e5f06a8326' -H 'Accept: application/json' -H 'X-Requested-With: XMLHttpRequest' | awk -F'"https://' '{ print $2 }' | sed 's/"}//')" -F file=@/tmp/syncwerk-server-report_${SERVERID}_${TIMESTAMP}.tgz -F filename=syncwerk-server-report_${SERVERID}_${TIMESTAMP}.tgz -F parent_dir="/" > /dev/null 2>&1 && \

cat <<EOF


  EN Your report was uploaded. Now submit your error description to support@syncwerk.com
     and include this reference: syncwerk-server-report_${SERVERID}_${TIMESTAMP}

  DE Ihr Report wurde auf übertragen. Senden Sie uns jetzt Ihre Fehlerbeschreibung an
     support@syncwerk.com und fügen folgenden Referenz hinzu: syncwerk-server-report_${SERVERID}_${TIMESTAMP}


EOF
else
cat <<EOF


  EN For technical support submit this report with your error description to support@syncwerk.com

  DE Für technische Unterstützung senden Sie den Report inkl. Fehlerbeschreibung an support@syncwerk.com


EOF
fi
}


function setup-samba-ad-dc {
if ! samba ; then
grep -q "\[.*LDAP.*\]" /etc/syncwerk/ccnet.conf && (echo "Found existing LDAP setting in /etc/syncwerk/ccnet.conf. Aborting.." ; exit 1)
domain="$(hostname -d | awk -F '.' '{ print $1 }' | tr "[:lower:]" "[:upper:]")"
export domain
realm="$(hostname -d | tr "[:lower:]" "[:upper:]")"
export realm
hostname=$(hostname -d)
export hostname
adminpass="$(pwgen -ns 14 1)"
export adminpass
base="CN=Users,$(hostname -d | sed 's/^/DC=/ ; s/\./,DC=/g')"
export base
export DEBIAN_FRONTEND=noninteractive
apt-get update
if [ -f /etc/samba/smb.conf.orig ] ; then
  mv /etc/samba/smb.conf.orig /etc/samba/smb.conf
fi
apt-get install samba samba-dsdb-modules samba-vfs-modules krb5-config winbind smbclient heimdal-clients ldap-utils python-ldap -y
systemctl stop smbd nmbd winbind samba-ad-dc
systemctl disable smbd nmbd winbind
systemctl unmask samba-ad-dc
mv /etc/samba/smb.conf /etc/samba/smb.conf.orig
samba-tool domain provision --server-role=dc --use-rfc2307 --dns-backend=SAMBA_INTERNAL --realm="${realm}" --domain="${domain}" --adminpass="${adminpass}"
grep -q "ldap server require strong auth = no" /etc/samba/smb.conf || sed -i '/.*rfc2307.*/a \        ldap server require strong auth = no' /etc/samba/smb.conf
echo "nameserver 127.0.0.1" | uniq | cat - /etc/resolv.conf | uniq > /etc/resolv.conf.new && mv /etc/resolv.conf /etc/resolv.conf.bak && mv /etc/resolv.conf.new /etc/resolv.conf
if [[ -f /etc/krb5.conf || -h /etc/krb5.conf ]] ; then
  if [ ! -h /etc/krb5.conf ] ; then
    if [ ! -f /etc/krb5.conf.orig ] ; then
      mv /etc/krb5.conf /etc/krb5.conf.orig
    else
      rm -f /etc/krb5.conf
      ln -s /var/lib/samba/private/krb5.conf /etc/krb5.conf
    fi
  fi
fi
systemctl enable samba-ad-dc
systemctl start samba-ad-dc
echo "Waiting 15 seconds for samba-ad-dc to start "
sleep 15
if ! ldapsearch -x -h 127.0.0.1 -D "administrator@${hostname}" -w "${adminpass}" -b "${base}" > /dev/null 2>&1 ; then
echo "Connecting to Samba Active Directory failed. Aborting.."
else
grep -q "\[.*LDAP.*\]" /etc/syncwerk/ccnet.conf || \
cat >> /etc/syncwerk/ccnet.conf <<EOF

[LDAP]
HOST = ldap://127.0.0.1/
BASE = ${base}
USER_DN = administrator@${hostname}
PASSWORD = ${adminpass}
LOGIN_ATTR = name
FILTER = memberOf=CN=Syncwerk,${base}
EOF
service syncwerk-server restart
USERNAME="aduser1"
USERPASS=$(pwgen -ns 14 1)
USERGROUP="Syncwerk"
samba-tool group list | grep -q "^${USERGROUP}$" || samba-tool group add "${USERGROUP}"
if ! samba-tool user list | grep -q "^${USERNAME}$" ; then
  samba-tool user create "${USERNAME}" "${USERPASS}"
  samba-tool group addmembers "${USERGROUP}" "${USERNAME}"
  echo "Login with User: ${USERNAME} Password: ${USERPASS} at https://$(hostname -f)"
fi
fi
else
echo "Samba is already installed. Aborting.."
fi
}


function setup-clamav-virus-scanner {
if ! clamdscan -V  > /dev/null 2>&1 ; then
grep -iq "\[.*virus.*\]" /etc/syncwerk/restapi_settings.py && (echo "Found existing virus scanning settings in /etc/syncwerk/restapi_settings.py. Aborting.." ; exit 1)
systemctl stop clamav-daemon
systemctl stop clamav-freshclam
apt-get update
apt-get install clamav clamav-daemon -y
cp /etc/clamav/clamd.conf /etc/clamav/clamd.conf.bak
sed -i 's/^User .*/User root/g' /etc/clamav/clamd.conf
sed -i 's/^LocalSocketGroup .*/LocalSocketGroup root/g' /etc/clamav/clamd.conf
systemctl start clamav-daemon
systemctl start clamav-freshclam
cat >> /etc/syncwerk/restapi_settings.py <<EOF

# Enable virus scanning or not. Default to "False"
ENABLE_VIRUS_SCANNING = True
# The command line used for virus scanning.
VIRUS_SCAN_COMMAND = 'clamdscan'
# Enter the status code for infected files
VIRUS_SCAN_RESULT_INFECTED_CODE = [1]
# Enter the status code for clean files
VIRUS_SCAN_RESULT_SAFE_CODE = [0]
# Set virus scan interval
VIRUS_SCAN_INTERVAL = 60
# Exclude extension
VIRUS_SCAN_SKIP_EXT = ['bmp', 'gif', 'ico', 'png', 'jpg', 'mp3', 'mp4', 'wav', 'avi', 'rmvb', 'mkv']
# Exlude files larger bigger than this (set in bytes). Default to 1GB
VIRUS_SCAN_FILE_SIZE_LIMIT = 1024*1024*1024
# Check virus scanner availability
VIRUS_SCAN_CHECK_SCAN_COMMAND_READY = ['which clamdscan', 'systemctl status clamav-daemon.service']

EOF
restart
else
echo "Virus scanner is already installed. Aborting.."
fi
}



function run-virus-scanner {
if grep -iqv "\[.*virus.*\]" /etc/syncwerk/restapi_settings.py ; then
sudo -E -u syncwerk /usr/share/python/syncwerk/restapi/manage.py trigger_virus_scanning
echo "Finished virus scanning"
else
echo "Virus scanner is not installed. Aborting.."
fi
}


function support {
if  [[ ${LANG} = *"de"* ]] ; then
cat <<EOF

  Anwendung  Syncwerk Server

  Anbieter   Syncwerk GmbH, Wiesentheid (Deutschland)
             https://www.syncwerk.com

  Telefon    +49 (0) 9383 33337-0


  Hilfe      support@syncwerk.com

  Handbuch   https://support.syncwerk.de

EOF
else
cat <<EOF

  Program    Syncwerk Server

  Vendor     Syncwerk GmbH, Wiesentheid (Germany)
             https://www.syncwerk.com

  Phone      +49 (0) 9383 33337-0


  Support    support@syncwerk.com

  Manual     https://support.syncwerk.de

EOF
fi
}


function setup {
stop
backup-databases
install-python-tools
setup-nginx
setup-virtualenv
setup-user
start-database
create-database
setup-ccnet-conf
setup-my-key-peer
setup-ccnet-database
setup-file-server-conf
setup-gunicorn-conf
setup-restapi-settings-py
update-database
setup-services
migrate-avatars
fix-permissions
update-static-files
start
stop
start
support
syncwerk-server start
if [ ! -f "/etc/syncwerk/admin.txt" ] ; then
  sleep 12
  create-admin
fi
}


function manage.py {
sudo -E -u syncwerk /usr/share/python/syncwerk/restapi/manage.py ${1} ${2}
}


function change-email-address {
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -c|--current)
    CURRENTEMAIL="${2}"
    shift # past argument
    shift # past value
    ;;
    -n|--new)
    NEWEMAIL="${2}"
    shift # past argument
    shift # past value
    ;;
    *)    # unknown option
    POSITIONAL+=("${1}") # save it in an array for later
    shift # past argument
    ;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters


IFS="@"
set -- ${CURRENTEMAIL}

if [ "${#@}" -ne 2 ] ; then
    echo "Incorrect format for current email. Aborting.."
    echo "Usage: ${0} change-email-address --current old@email.tld --new new@email.tld"
    exit
fi

set -- ${NEWEMAIL}
if [ "${#@}" -ne 2 ] ; then
    echo "Incorrect format for new email. Aborting.."
    echo "Usage: ${0} change-email-address --current old@email.tld --new new@email.tld"
    exit
fi

if [ -z "${NEWEMAIL}" ]
then
    echo "Usage: ${0} change-email-address --current old@email.tld --new new@email.tld"
    exit
fi

if [ -z "${CURRENTEMAIL}" ]
then
    echo "Usage: ${0} change-email-address --current old@email.tld --new new@email.tld"
    exit
else
    EXISTCHECK=$(mysql -e "SELECT * FROM \`syncwerk-ccnet\`.\`EmailUser\` WHERE \`email\` = '${NEWEMAIL}';")
    if [ ! -z "${EXISTCHECK}" ]
        then
            echo "The provided new email address '${NEWEMAIL}' is already registered in syncwerk-ccnet. Aborting.."
            exit
    fi
    EXISTCHECK=$(mysql -e "SELECT * FROM \`syncwerk-ccnet\`.\`EmailUser\` WHERE \`email\` = '${CURRENTEMAIL}';")
    if [ -z "${EXISTCHECK}" ]
        then
            echo "The provided current email address '${CURRENTEMAIL}' is not registered in syncwerk-ccnet. Aborting.."
            exit
    fi
    mysql -e "UPDATE \`syncwerk-ccnet\`.\`EmailUser\` SET \`email\` = '${NEWEMAIL}' WHERE \`EmailUser\`.\`email\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-server\`.\`RepoOwner\` SET \`owner_id\` = '${NEWEMAIL}' WHERE \`RepoOwner\`.\`owner_id\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-server\`.\`UserQuota\` SET \`user\` = '${NEWEMAIL}' WHERE \`UserQuota\`.\`user\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-server\`.\`RepoUserToken\` SET \`email\` = '${NEWEMAIL}' WHERE \`RepoUserToken\`.\`email\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`api2_token\` SET \`user\` = '${NEWEMAIL}' WHERE \`api2_token\`.\`user\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`api2_tokenv2\` SET \`user\` = '${NEWEMAIL}' WHERE \`api2_tokenv2\`.\`user\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`api3_token\` SET \`user\` = '${NEWEMAIL}' WHERE \`api3_token\`.\`user\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`api3_tokenv2\` SET \`user\` = '${NEWEMAIL}' WHERE \`api3_tokenv2\`.\`user\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`base_clientlogintoken\` SET \`username\` = '${NEWEMAIL}' WHERE \`base_clientlogintoken\`.\`username\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`base_userlastlogin\` SET \`username\` = '${NEWEMAIL}' WHERE \`base_userlastlogin\`.\`username\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`base_userstarredfiles\` SET \`email\` = '${NEWEMAIL}' WHERE \`base_userstarredfiles\`.\`email\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`options_useroptions\` SET \`email\` = '${NEWEMAIL}' WHERE \`options_useroptions\`.\`email\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`share_fileshare\` SET \`username\` = '${NEWEMAIL}' WHERE \`share_fileshare\`.\`username\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`sysadmin_extra_userloginlog\` SET \`username\` = '${NEWEMAIL}' WHERE \`sysadmin_extra_userloginlog\`.\`username\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`admin_log_adminlog\` SET \`email\` = '${NEWEMAIL}' WHERE \`admin_log_adminlog\`.\`email\` = '${CURRENTEMAIL}';"
    mysql -e "UPDATE \`syncwerk-restapi\`.\`notifications_usernotification\` SET \`to_user\` = '${NEWEMAIL}' WHERE \`notifications_usernotification\`.\`to_user\` = '${CURRENTEMAIL}';"

    echo "Changed registered email from ${CURRENTEMAIL} to ${NEWEMAIL}"
fi
}


function create-file-list {
epoch=$(date +%s)
mkdir -p /mnt/syncwerk-server-mount /var/log/syncwerk/filetree
syncwerk-server-admin umount /mnt/syncwerk-server-mount
syncwerk-server-admin mount /mnt/syncwerk-server-mount
cd /mnt/syncwerk-server-mount
for user in $(ls | xargs) ; do
    printf "Char\tSize\tFile\n" | awk -F'\t' '{printf("%20s %30s   %s \n", $1, $2, $3)}' | tee /var/log/syncwerk/filetree/${epoch}_${user}.log
    printf '%s\n' ------------------------------------------------------------------------------------------------------------------------------------------------------- | tee -a /var/log/syncwerk/filetree/${epoch}_${user}.log
    find ${user}/ -type f | while read file ; do
        filelength=$(echo -n "${file}" | wc -m)
        userlength=$(echo -n "${user}" | wc -m)
        prefixlength=37
        pathlength=$((filelength-userlength-prefixlength))
        filesize=$(du -sb "${file}" | cut -f -1)
        filesizeinmb=$(echo ${filesize} | awk '{ byte =$1 /1024/1024 ; print byte " MB" }')
        printf "${pathlength}\t${filesizeinmb}\t\"${file}\"\n" | awk -F'\t' '{printf("%20s %30s   %s \n", $1, $2, $3)}'
        files=$((files+1))
        echo -n ${files} > /var/log/syncwerk/filetree/${epoch}_${user}_files.txt
    done | sort --numeric-sort | tee -a /var/log/syncwerk/filetree/${epoch}_${user}.log
    totalusage=$(du -sb "${user}" | cut -f -1 | awk '{ byte =$1 /1024/1024 ; print byte " MB" }')
    printf '%s\n' ------------------------------------------------------------------------------------------------------------------------------------------------------- | tee -a /var/log/syncwerk/filetree/${epoch}_${user}.log
    printf "$(if [ -f "/var/log/syncwerk/filetree/${epoch}_${user}_files.txt" ]; then cat /var/log/syncwerk/filetree/${epoch}_${user}_files.txt; fi)\t${totalusage}\t\n" | awk -F'\t' '{printf("%20s %30s   %s \n", $1, $2, $3)}' | tee -a /var/log/syncwerk/filetree/${epoch}_${user}.log
    rm -f /var/log/syncwerk/filetree/${epoch}_${user}_files.txt
    printf '\n\n'
done
echo "Your file list was saved to /var/log/syncwerk/filetree/${epoch}_${user}.log"
}


# Get options and execute task
while true ; do
    case "$1" in
        start) start ; break ;;
        stop) stop ; break ;;
        restart) restart ; break ;;
        setup) setup ; break ;;
        update-translations) update-translations ; break ;;
        update-static-files) update-static-files ; break ;;
        purge) purge ; break ;;
        fsck) fsck ${2} ${3} ${4} ${5} ${6} ${7} ${8} ; break ;;
        mount) mount ${2} ; break ;;
        umount) umount ; break ;;
        gc) gc ${2} ${3} ${4} ${5} ${6} ${7} ${8} ; break ;;
        backup-databases) backup-databases ; fix-permissions ; break ;;
        backup-object-storage) backup-object-storage ; fix-permissions ; break ;;
        backup-configurations) backup-configurations ; fix-permissions ; break ;;
        backup-server-applications) backup-server-applications ; fix-permissions ; break ;;
        backup-all) backup-all ; fix-permissions ; break ;;
        fix-permissions) fix-permissions ; break ;;
        setup-onlyoffice) setup-onlyoffice || support ; break ;;
        setup-letsencrypt-certificate) setup-letsencrypt-certificate || support; break ;;
        setup-samba-ad-dc) setup-samba-ad-dc || support ; break ;;
        setup-clamav-virus-scanner) setup-clamav-virus-scanner || support ; break ;;
        run-virus-scanner) run-virus-scanner || support ; break ;;
        report) report ; break ;;
        support) support ; break ;;
        manage.py) manage.py ${2} ${3} ; break ;;
        change-email-address) backup-databases ; change-email-address ${2} ${3} ${4} ${5} ; break ;;
        create-file-list) create-file-list ; break ;;
        *) help ; break ;;
    esac
done
