#!/bin/bash # _____ _ _ # | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___ # | __| _| -_| -_| . | . | | . | . | | -_| # |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___| # # Freedom in the Cloud # # Etherpad app # # License # ======= # # Copyright (C) 2016-2018 Bob Mottram # # 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 . VARIANTS="full full-vim writer" IN_DEFAULT_INSTALL=0 SHOW_ON_ABOUT=1 MINIMUM_RAM_MB=2000 ETHERPAD_DOMAIN_NAME= ETHERPAD_CODE= ETHERPAD_ONION_PORT=8101 ETHERPAD_PORT=9001 ETHERPAD_REPO="https://github.com/ether/etherpad-lite" ETHERPAD_COMMIT='454f539561a8d9de51ed107a29d974eb79198bc6' ETHERPAD_ADMIN_PASSWORD= ETHERPAD_TITLE=$'Freedombone Docs' ETHERPAD_WELCOME_MESSAGE=$"Welcome to ${ETHERPAD_TITLE}!\\n\\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!" ETHERPAD_SHORT_DESCRIPTION=$'Collaborative document editor' ETHERPAD_DESCRIPTION=$'Collaborative document editor' ETHERPAD_MOBILE_APP_URL= etherpad_variables=(ONION_ONLY DEFAULT_DOMAIN_NAME ETHERPAD_DOMAIN_NAME ETHERPAD_CODE ETHERPAD_TITLE ETHERPAD_WELCOME_MESSAGE DDNS_PROVIDER MY_USERNAME) function logging_on_etherpad { echo -n '' } function logging_off_etherpad { echo -n '' } function change_password_etherpad { change_username="$1" new_user_password="$2" read_config_param ETHERPAD_DOMAIN_NAME if grep -q "\"$change_username\": {" /var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json; then user_line=$(grep "\"$change_username\": {" "/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json") if [[ "$user_line" == *"\"is_admin\": true"* ]]; then sed -i "s|\"$change_username\": {.*|\"$change_username\": { \"password\": \"$new_user_password\", \"is_admin\": true }|g" "/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json" else sed -i "s|\"$change_username\": {.*|\"$change_username\": { \"password\": \"$new_user_password\", \"is_admin\": false },|g" /var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json fi "${PROJECT_NAME}-pass" -u "$change_username" -a etherpad -p "$2" systemctl restart etherpad fi } function etherpad_create_database { if [ -f "$IMAGE_PASSWORD_FILE" ]; then ETHERPAD_ADMIN_PASSWORD="$(printf "%s" "$(cat "$IMAGE_PASSWORD_FILE")")" else if [ ! "$ETHERPAD_ADMIN_PASSWORD" ]; then ETHERPAD_ADMIN_PASSWORD="$(create_password "${MINIMUM_PASSWORD_LENGTH}")" fi fi if [ ! "$ETHERPAD_ADMIN_PASSWORD" ]; then return fi function_check create_database create_database etherpad "$ETHERPAD_ADMIN_PASSWORD" "$MY_USERNAME" } function create_etherpad_settings { settings_file="/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json" { echo '{'; echo " \"title\": \"${ETHERPAD_TITLE}\","; echo ' "favicon": "favicon.ico",'; echo ' "ip": "127.0.0.1",'; echo " \"port\" : ${ETHERPAD_PORT},"; echo ' "showSettingsInAdminPage" : true,'; echo ' "dbType" : "mysql",'; echo ' "dbSettings" : {'; echo ' "user" : "root",'; echo ' "host" : "localhost",'; echo " \"password\": \"${MARIADB_PASSWORD}\","; echo ' "database": "etherpad",'; echo ' "charset" : "utf8mb4"'; echo ' },'; echo " \"defaultPadText\" : \"${ETHERPAD_WELCOME_MESSAGE}\","; echo ' "padOptions": {'; echo ' "noColors": false,'; echo ' "showControls": true,'; echo ' "showChat": true,'; echo ' "showLineNumbers": false,'; echo ' "useMonospaceFont": false,'; echo ' "userName": false,'; echo ' "userColor": true,'; echo ' "rtl": false,'; echo ' "alwaysShowChat": true,'; echo ' "chatAndUsers": true,'; echo ' "lang": "en-gb"'; echo ' },'; echo ' "suppressErrorsInPadText" : true,'; echo ' "requireSession" : false,'; echo ' "editOnly" : false,'; echo ' "sessionNoPassword" : false,'; echo ' "minify" : true,'; echo ' "maxAge" : 21600, // 60 * 60 * 6 = 6 hours'; echo ' "abiword" : null,'; echo ' "soffice" : null,'; echo ' "tidyHtml" : null,'; echo ' "allowUnknownFileEnds" : false,'; echo ' "requireAuthentication" : true,'; echo ' "requireAuthorization" : true,'; echo ' "trustProxy" : false,'; echo ' "disableIPlogging" : true,'; echo ' "users": {'; echo " \"${MY_USERNAME}\": { \"password\": \"${ETHERPAD_ADMIN_PASSWORD}\", \"is_admin\": true }"; echo ' },'; echo ' "socketTransportProtocols" : ["xhr-polling", "jsonp-polling", "htmlfile"],'; echo ' "loadTest": false,'; echo ' "indentationOnNewLine": false,'; echo ' "toolbar": {'; echo ' "left": ['; echo ' ["bold", "italic", "underline", "strikethrough"],'; echo ' ["orderedlist", "unorderedlist", "indent", "outdent"],'; echo ' ["undo", "redo"],'; echo ' ["clearauthorship"]'; echo ' ],'; echo ' "right": ['; echo ' ["importexport", "timeslider", "savedrevision"],'; echo ' ["settings", "embed"],'; echo ' ["showusers"]'; echo ' ],'; echo ' "timeslider": ['; echo ' ["timeslider_export", "timeslider_returnToPad"]'; echo ' ]'; echo ' },'; echo ' "loglevel": "INFO"'; echo '}'; } > $settings_file chmod 600 $settings_file } function remove_user_etherpad { remove_username="$1" settings_file=/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json "${PROJECT_NAME}-pass" -u "$remove_username" --rmapp etherpad if grep -q "\"$remove_username\": {" $settings_file; then sed -i "/\"$remove_username\": {/d" $settings_file systemctl restart etherpad fi } function add_user_etherpad { new_username="$1" new_user_password="$2" settings_file=/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json if ! grep -q "\"$new_username\": {" $settings_file; then "${PROJECT_NAME}-pass" -u "$new_username" -a etherpad -p "$2" sed -i "/\"users\": {/a \"$new_username\": { \"password\": \"$new_user_password\", \"is_admin\": false }," $settings_file if grep -q "\"$new_username\": {" $settings_file; then systemctl restart etherpad else echo '1' return fi fi echo '0' } function install_interactive_etherpad { if [ ! "$ONION_ONLY" ]; then ONION_ONLY='no' fi if [[ "$ONION_ONLY" != "no" ]]; then ETHERPAD_DOMAIN_NAME='etherpad.local' write_config_param "ETHERPAD_DOMAIN_NAME" "$ETHERPAD_DOMAIN_NAME" else function_check interactive_site_details interactive_site_details "etherpad" "ETHERPAD_DOMAIN_NAME" "ETHERPAD_CODE" fi APP_INSTALLED=1 } function etherpad_set_title { read_config_param "ETHERPAD_TITLE" data=$(mktemp 2>/dev/null) dialog --title $"Etherpad Title" \ --backtitle $"Freedombone Control Panel" \ --inputbox $'Set a title for your etherpad system' 10 60 "$ETHERPAD_TITLE" 2>"$data" sel=$? case $sel in 0) temp_title=$(<"$data") if [ ${#temp_title} -gt 0 ]; then ETHERPAD_TITLE="$temp_title" settings_file="/var/www/$ETHERPAD_DOMAIN_NAME/htdocs/settings.json" write_config_param "ETHERPAD_TITLE" "$ETHERPAD_TITLE" sed -i "s|\"title\":.*|\"title\": \"${ETHERPAD_TITLE}\"|g" $settings_file dialog --title $"Etherpad Title" \ --msgbox $"Title has been set" 6 60 fi ;; esac rm -f "$data" } function etherpad_set_welcome_message { read_config_param "ETHERPAD_WELCOME_MESSAGE" data=$(mktemp 2>/dev/null) dialog --title $"Etherpad Welcome Message" \ --backtitle $"Freedombone Control Panel" \ --inputbox $'Set a welcome message, which can include html formatting' 10 60 "$ETHERPAD_WELCOME_MESSAGE" 2>"$data" sel=$? case $sel in 0) temp_welcome=$(<"$data") if [ ${#temp_welcome} -gt 0 ]; then ETHERPAD_WELCOME_MESSAGE="$temp_welcome" settings_file="/var/www/$ETHERPAD_DOMAIN_NAME/htdocs/settings.json" write_config_param "ETHERPAD_WELCOME_MESSAGE" "$ETHERPAD_WELCOME_MESSAGE" sed -i "s|\"defaultPadText\" :.*|\"defaultPadText\" : \"${ETHERPAD_WELCOME_MESSAGE}\"|g" $settings_file dialog --title $"Etherpad Welcome Message" \ --msgbox $"Welcome message has been set" 6 60 fi ;; esac rm -f "$data" } function configure_interactive_etherpad { W=(1 $"Set Title" 2 $"Set a welcome message") while true do # shellcheck disable=SC2068 selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Etherpad" --menu $"Choose an operation, or ESC to exit:" 10 60 2 "${W[@]}" 3>&2 2>&1 1>&3) if [ ! "$selection" ]; then break fi case $selection in 1) etherpad_set_title;; 2) etherpad_set_welcome_message;; esac done } function reconfigure_etherpad { create_etherpad_settings systemctl restart etherpad } function upgrade_etherpad { CURR_ETHERPAD_COMMIT=$(get_completion_param "etherpad commit") if [[ "$CURR_ETHERPAD_COMMIT" == "$ETHERPAD_COMMIT" ]]; then return fi read_config_param "ETHERPAD_DOMAIN_NAME" function_check set_repo_commit set_repo_commit /var/www/$ETHERPAD_DOMAIN_NAME/htdocs "etherpad commit" "$ETHERPAD_COMMIT" $ETHERPAD_REPO } function backup_local_etherpad { ETHERPAD_DOMAIN_NAME='etherpad' if grep -q "etherpad domain" "$COMPLETION_FILE"; then ETHERPAD_DOMAIN_NAME=$(get_completion_param "etherpad domain") fi source_directory=/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs if [ -d "$source_directory" ]; then dest_directory=etherpad function_check suspend_site suspend_site "${ETHERPAD_DOMAIN_NAME}" function_check backup_directory_to_usb backup_directory_to_usb "$source_directory" "$dest_directory" function_check backup_database_to_usb backup_database_to_usb etherpad function_check restart_site restart_site fi } function restore_local_etherpad { if ! grep -q "etherpad domain" "$COMPLETION_FILE"; then return fi ETHERPAD_DOMAIN_NAME=$(get_completion_param "etherpad domain") if [ "$ETHERPAD_DOMAIN_NAME" ]; then temp_restore_dir=/root/tempetherpad #etherpad_dir="/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs" function_check etherpad_create_database etherpad_create_database restore_database etherpad "${ETHERPAD_DOMAIN_NAME}" if [ -d $temp_restore_dir ]; then rm -rf $temp_restore_dir fi chown -R etherpad: "/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs" if [ -f "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" ]; then chown etherpad: "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" fi if [ -f "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" ]; then chown etherpad: "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" fi MARIADB_PASSWORD=$("${PROJECT_NAME}-pass" -u root -a mariadb) settings_file="/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json" sed -i "s|\"password\":.*|\"password\": \"${MARIADB_PASSWORD}\",|g" "$settings_file" MARIADB_PASSWORD= fi } function backup_remote_etherpad { if grep -q "etherpad domain" "$COMPLETION_FILE"; then ETHERPAD_DOMAIN_NAME=$(get_completion_param "etherpad domain") temp_backup_dir="/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs" if [ -d "$temp_backup_dir" ]; then function_check suspend_site suspend_site "${ETHERPAD_DOMAIN_NAME}" function_check backup_database_to_friend backup_database_to_friend etherpad function_check backup_directory_to_friend backup_directory_to_friend "$temp_backup_dir" etherpad function_check restart_site restart_site else echo $"etherpad domain specified but not found in ${temp_backup_dir}" fi fi } function restore_remote_etherpad { if grep -q "etherpad domain" "$COMPLETION_FILE"; then ETHERPAD_DOMAIN_NAME=$(get_completion_param "etherpad domain") function_check etherpad_create_database etherpad_create_database function_check restore_database_from_friend restore_database_from_friend etherpad "${ETHERPAD_DOMAIN_NAME}" if [ -d /root/tempetherpad ]; then rm -rf /root/tempetherpad fi chown -R etherpad: "/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs" if [ -f "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" ]; then chown etherpad: "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" fi if [ -f "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" ]; then chown etherpad: "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" fi MARIADB_PASSWORD=$("${PROJECT_NAME}-pass" -u root -a mariadb) settings_file="/var/www/${ETHERPAD_DOMAIN_NAME}/htdocs/settings.json" sed -i "s|\"password\":.*|\"password\": \"${MARIADB_PASSWORD}\",|g" "$settings_file" MARIADB_PASSWORD= fi } function remove_etherpad { if [ ${#ETHERPAD_DOMAIN_NAME} -eq 0 ]; then return fi read_config_param "ETHERPAD_DOMAIN_NAME" read_config_param "MY_USERNAME" echo "Removing $ETHERPAD_DOMAIN_NAME" if [ -f /etc/systemd/system/etherpad.service ]; then systemctl stop etherpad systemctl disable etherpad rm /etc/systemd/system/etherpad.service fi systemctl daemon-reload nginx_dissite "$ETHERPAD_DOMAIN_NAME" remove_certs "$ETHERPAD_DOMAIN_NAME" if [ -d "/var/www/$ETHERPAD_DOMAIN_NAME" ]; then rm -rf "/var/www/$ETHERPAD_DOMAIN_NAME" fi if [ -f "/etc/nginx/sites-available/$ETHERPAD_DOMAIN_NAME" ]; then rm "/etc/nginx/sites-available/$ETHERPAD_DOMAIN_NAME" fi function_check drop_database drop_database etherpad function_check remove_onion_service remove_onion_service etherpad ${ETHERPAD_ONION_PORT} remove_app etherpad remove_completion_param install_etherpad sed -i '/etherpad/d' "$COMPLETION_FILE" remove_backup_database_local etherpad remove_nodejs etherpad groupdel -f etherpad userdel -r etherpad function_check remove_ddns_domain remove_ddns_domain "$ETHERPAD_DOMAIN_NAME" } function install_etherpad { if [ ! "$ETHERPAD_DOMAIN_NAME" ]; then echo $'No domain name was given for etherpad' exit 7359 fi check_ram_availability 2000 if [ -f "$IMAGE_PASSWORD_FILE" ]; then ETHERPAD_ADMIN_PASSWORD="$(printf "%s" "$(cat "$IMAGE_PASSWORD_FILE")")" else if [ ! "$ETHERPAD_ADMIN_PASSWORD" ]; then ETHERPAD_ADMIN_PASSWORD="$(create_password "${MINIMUM_PASSWORD_LENGTH}")" fi fi function_check install_mariadb install_mariadb function_check get_mariadb_password get_mariadb_password function_check repair_databases_script repair_databases_script apt-get -yq install gzip git curl python libssl-dev pkg-config \ build-essential python g++ make checkinstall \ python-bcrypt python-passlib function_check install_nodejs install_nodejs etherpad if [ ! -d "/var/www/$ETHERPAD_DOMAIN_NAME" ]; then mkdir "/var/www/$ETHERPAD_DOMAIN_NAME" fi if [ ! -d "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" ]; then if [ -d /repos/etherpad ]; then mkdir "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" cp -r -p /repos/etherpad/. "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" cd "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" || exit 32468346 git pull else function_check git_clone git_clone "$ETHERPAD_REPO" "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" fi if [ ! -d "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" ]; then echo $'Unable to clone etherpad repo' exit 56382 fi fi cd "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" || exit 24654824 git checkout "$ETHERPAD_COMMIT" -b "$ETHERPAD_COMMIT" set_completion_param "etherpad commit" "$ETHERPAD_COMMIT" chmod a+w "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" chown www-data:www-data "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs" function_check etherpad_create_database etherpad_create_database function_check add_ddns_domain add_ddns_domain "$ETHERPAD_DOMAIN_NAME" create_etherpad_settings adduser --system --home="/var/www/$ETHERPAD_DOMAIN_NAME/htdocs/" --group etherpad chown -R etherpad: "/var/www/$ETHERPAD_DOMAIN_NAME/htdocs/" { echo '[Unit]'; echo 'Description=etherpad-lite (real-time collaborative document editing)'; echo 'After=syslog.target network.target'; echo ''; echo '[Service]'; echo 'Type=simple'; echo 'User=etherpad'; echo 'Group=etherpad'; echo "WorkingDirectory=/var/www/$ETHERPAD_DOMAIN_NAME/htdocs"; echo "ExecStart=/var/www/$ETHERPAD_DOMAIN_NAME/htdocs/bin/run.sh"; echo 'Restart=on-failure'; echo 'SuccessExitStatus=3 4'; echo 'RestartForceExitStatus=3 4'; echo ''; echo '[Install]'; echo 'WantedBy=multi-user.target'; } > /etc/systemd/system/etherpad.service chmod +x /etc/systemd/system/etherpad.service etherpad_nginx_site=/etc/nginx/sites-available/$ETHERPAD_DOMAIN_NAME if [[ $ONION_ONLY == "no" ]]; then function_check nginx_http_redirect nginx_http_redirect "$ETHERPAD_DOMAIN_NAME" { echo 'server {'; echo ' listen 443 ssl;'; echo ' #listen [::]:443 ssl;'; echo " server_name $ETHERPAD_DOMAIN_NAME;"; echo ''; echo ' # Security'; } >> "$etherpad_nginx_site" function_check nginx_ssl nginx_ssl "$ETHERPAD_DOMAIN_NAME" function_check nginx_security_options nginx_security_options "$ETHERPAD_DOMAIN_NAME" { echo ' add_header Strict-Transport-Security max-age=15768000;'; echo ''; echo ' # Logs'; echo ' access_log /dev/null;'; echo ' error_log /dev/null;'; echo ''; echo ' # Root'; echo " root /var/www/$ETHERPAD_DOMAIN_NAME/htdocs;"; echo ''; echo ' location / {'; } >> "$etherpad_nginx_site" function_check nginx_limits nginx_limits "$ETHERPAD_DOMAIN_NAME" '15m' { echo " proxy_pass http://localhost:${ETHERPAD_PORT}/;"; echo " proxy_set_header Host \$host;"; echo ' proxy_buffering off;'; echo ' }'; echo '}'; } >> "$etherpad_nginx_site" else echo -n '' > "$etherpad_nginx_site" fi { echo 'server {'; echo " listen 127.0.0.1:$ETHERPAD_ONION_PORT default_server;"; echo " server_name $ETHERPAD_ONION_HOSTNAME;"; echo ''; } >> "$etherpad_nginx_site" function_check nginx_security_options nginx_security_options "$ETHERPAD_DOMAIN_NAME" { echo ''; echo ' # Logs'; echo ' access_log /dev/null;'; echo ' error_log /dev/null;'; echo ''; echo ' # Root'; echo " root /var/www/$ETHERPAD_DOMAIN_NAME/htdocs;"; echo ''; echo ' location / {'; } >> "$etherpad_nginx_site" function_check nginx_limits nginx_limits "$ETHERPAD_DOMAIN_NAME" '15m' { echo " proxy_pass http://localhost:${ETHERPAD_PORT}/;"; echo " proxy_set_header Host \$host;"; echo ' proxy_buffering off;'; echo ' }'; echo '}'; } >> "$etherpad_nginx_site" function_check create_site_certificate create_site_certificate "$ETHERPAD_DOMAIN_NAME" 'yes' if [ -f "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.crt" ]; then # shellcheck disable=SC2086 mv /etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.crt /etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem fi if [ -f "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" ]; then chown etherpad: "/etc/ssl/certs/${ETHERPAD_DOMAIN_NAME}.pem" fi if [ -f "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" ]; then chown etherpad: "/etc/ssl/private/${ETHERPAD_DOMAIN_NAME}.key" fi usermod -a -G ssl-cert etherpad # Ensure that the database gets backed up locally, if remote # backups are not being used function_check backup_databases_script_header backup_databases_script_header function_check backup_database_local backup_database_local etherpad function_check nginx_ensite nginx_ensite "$ETHERPAD_DOMAIN_NAME" ETHERPAD_ONION_HOSTNAME=$(add_onion_service etherpad 80 ${ETHERPAD_ONION_PORT}) "${PROJECT_NAME}-pass" -u "$MY_USERNAME" -a etherpad -p "$ETHERPAD_ADMIN_PASSWORD" function_check add_ddns_domain add_ddns_domain "$ETHERPAD_DOMAIN_NAME" set_completion_param "etherpad domain" "$ETHERPAD_DOMAIN_NAME" systemctl restart mariadb systemctl enable etherpad systemctl daemon-reload systemctl start etherpad systemctl restart nginx APP_INSTALLED=1 }