#!/bin/bash # # _____ _ _ # | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___ # | __| _| -_| -_| . | . | | . | . | | -_| # |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___| # # Freedom in the Cloud # # 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 SHOW_ON_ABOUT=1 BABYBUDDY_DOMAIN_NAME= BABYBUDDY_CODE= BABYBUDDY_ONION_PORT=9495 BABYBUDDY_REPO="https://github.com/cdubz/babybuddy" BABYBUDDY_COMMIT='27c914228d9ec5ecc1dd39e6874c99364d1a63d9' # These parameters are used by the FreedomBox mobile app BABYBUDDY_SHORT_DESCRIPTION= BABYBUDDY_DESCRIPTION= BABYBUDDY_MOBILE_APP_URL= babybuddy_variables=(ONION_ONLY BABYBUDDY_DOMAIN_NAME BABYBUDDY_CODE DDNS_PROVIDER MY_USERNAME) function logging_on_babybuddy { echo -n '' } function logging_off_babybuddy { echo -n '' } function remove_user_babybuddy { remove_username="$1" "${PROJECT_NAME}-pass" -u "$remove_username" --rmapp babybuddy } function add_user_babybuddy { new_username="$1" new_user_password="$2" "${PROJECT_NAME}-pass" -u "$new_username" -a babybuddy -p "$new_user_password" echo '0' } function install_interactive_babybuddy { if [ ! "$ONION_ONLY" ]; then ONION_ONLY='no' fi if [[ "$ONION_ONLY" != "no" ]]; then BABYBUDDY_DOMAIN_NAME='babybuddy.local' write_config_param "BABYBUDDY_DOMAIN_NAME" "$BABYBUDDY_DOMAIN_NAME" else interactive_site_details "babybuddy" "BABYBUDDY_DOMAIN_NAME" "BABYBUDDY_CODE" fi APP_INSTALLED=1 } function change_password_babybuddy { curr_username="$1" new_user_password="$2" read_config_param 'BABYBUDDY_DOMAIN_NAME' "${PROJECT_NAME}-pass" -u "$curr_username" -a babybuddy -p "$new_user_password" } function reconfigure_babybuddy { # This is used if you need to switch identity. Dump old keys and generate new ones echo -n '' } function configure_interactive_babybuddy { W=(1 $"Option 1" 2 $"Option 2") while true do # shellcheck disable=SC2068 selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"babybuddy" --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_babybuddy { CURR_BABYBUDDY_COMMIT=$(get_completion_param "babybuddy commit") if [[ "$CURR_BABYBUDDY_COMMIT" == "$BABYBUDDY_COMMIT" ]]; then return fi if grep -q "babybuddy domain" "$COMPLETION_FILE"; then BABYBUDDY_DOMAIN_NAME=$(get_completion_param "babybuddy domain") fi # update to the next commit set_repo_commit "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" "babybuddy commit" "$BABYBUDDY_COMMIT" "$BABYBUDDY_REPO" chown -R www-data:www-data "/var/www/${BABYBUDDY_DOMAIN_NAME}/htdocs" } function backup_local_babybuddy { BABYBUDDY_DOMAIN_NAME='babybuddy' if grep -q "babybuddy domain" "$COMPLETION_FILE"; then BABYBUDDY_DOMAIN_NAME=$(get_completion_param "babybuddy domain") fi source_directory=/var/www/${BABYBUDDY_DOMAIN_NAME}/data cp "/var/www/${BABYBUDDY_DOMAIN_NAME}/htdocs/babybuddy/settings/production.py" "$source_directory/production.py" suspend_site "${BABYBUDDY_DOMAIN_NAME}" dest_directory=babybuddy backup_directory_to_usb "$source_directory" $dest_directory rm "$source_directory/production.py" restart_site } function restore_local_babybuddy { if ! grep -q "babybuddy domain" "$COMPLETION_FILE"; then return fi BABYBUDDY_DOMAIN_NAME=$(get_completion_param "babybuddy domain") if [ ! "$BABYBUDDY_DOMAIN_NAME" ]; then return fi suspend_site "${BABYBUDDY_DOMAIN_NAME}" temp_restore_dir=/root/tempbabybuddy babybuddy_dir=/var/www/${BABYBUDDY_DOMAIN_NAME}/data restore_directory_from_usb $temp_restore_dir babybuddy if [ -d $temp_restore_dir ]; then if [ -d "$temp_restore_dir$babybuddy_dir" ]; then cp -rp "$temp_restore_dir$babybuddy_dir"/* "$babybuddy_dir"/ else if [ ! -d "$babybuddy_dir" ]; then mkdir "$babybuddy_dir" fi cp -rp "$temp_restore_dir"/* "$babybuddy_dir"/ fi babybuddy_secret_key=$(grep "SECRET_KEY" "$babybuddy_dir/production.py" | awk -F "'" '{print $2}') sed -i "s|SECRET_KEY.*|SECRET_KEY = '$babybuddy_secret_key'|g" "/var/www/${BABYBUDDY_DOMAIN_NAME}/htdocs/babybuddy/settings/production.py" rm "$babybuddy_dir/production.py" chown -R www-data:www-data "$babybuddy_dir" rm -rf $temp_restore_dir fi restart_site } function backup_remote_babybuddy { BABYBUDDY_DOMAIN_NAME='babybuddy' if grep -q "babybuddy domain" "$COMPLETION_FILE"; then BABYBUDDY_DOMAIN_NAME=$(get_completion_param "babybuddy domain") fi source_directory=/var/www/${BABYBUDDY_DOMAIN_NAME}/data cp "/var/www/${BABYBUDDY_DOMAIN_NAME}/htdocs/babybuddy/settings/production.py" "$source_directory/production.py" suspend_site "${BABYBUDDY_DOMAIN_NAME}" dest_directory=babybuddy backup_directory_to_friend "$source_directory" $dest_directory rm "$source_directory/production.py" restart_site } function restore_remote_babybuddy { if ! grep -q "babybuddy domain" "$COMPLETION_FILE"; then return fi BABYBUDDY_DOMAIN_NAME=$(get_completion_param "babybuddy domain") if [ ! "$BABYBUDDY_DOMAIN_NAME" ]; then return fi suspend_site "${BABYBUDDY_DOMAIN_NAME}" temp_restore_dir=/root/tempbabybuddy babybuddy_dir=/var/www/${BABYBUDDY_DOMAIN_NAME}/data restore_directory_from_friend $temp_restore_dir babybuddy if [ -d $temp_restore_dir ]; then if [ -d "$temp_restore_dir$babybuddy_dir" ]; then cp -rp "$temp_restore_dir$babybuddy_dir"/* "$babybuddy_dir"/ else if [ ! -d "$babybuddy_dir" ]; then mkdir "$babybuddy_dir" fi cp -rp $temp_restore_dir/* "$babybuddy_dir"/ fi babybuddy_secret_key=$(grep "SECRET_KEY" "$babybuddy_dir/production.py" | awk -F "'" '{print $2}') sed -i "s|SECRET_KEY.*|SECRET_KEY = '$babybuddy_secret_key'|g" "/var/www/${BABYBUDDY_DOMAIN_NAME}/htdocs/babybuddy/settings/production.py" rm "$babybuddy_dir/production.py" chown -R www-data:www-data "$babybuddy_dir" rm -rf $temp_restore_dir fi restart_site } function remove_babybuddy { nginx_dissite "$BABYBUDDY_DOMAIN_NAME" remove_certs "$BABYBUDDY_DOMAIN_NAME" remove_nodejs babybuddy if [ -d "/var/www/$BABYBUDDY_DOMAIN_NAME" ]; then rm -rf "/var/www/$BABYBUDDY_DOMAIN_NAME" fi if [ -f "/etc/nginx/sites-available/$BABYBUDDY_DOMAIN_NAME" ]; then rm "/etc/nginx/sites-available/$BABYBUDDY_DOMAIN_NAME" fi if [ -f /etc/uwsgi/apps-available/babybuddy.ini ]; then rm /etc/uwsgi/apps-available/babybuddy.ini systemctl restart uwsgi fi remove_onion_service babybuddy "${BABYBUDDY_ONION_PORT}" if grep -q "babybuddy" /etc/crontab; then sed -i "/babybuddy/d" /etc/crontab fi remove_app babybuddy remove_completion_param install_babybuddy sed -i '/babybuddy/d' "$COMPLETION_FILE" remove_ddns_domain "$BABYBUDDY_DOMAIN_NAME" } function install_babybuddy { $INSTALL_PACKAGES python3 python3-pip uwsgi uwsgi-plugin-python3 libopenjp2-7-dev $INSTALL_PACKAGES python3-virtualenv python-virtualenv $INSTALL_PACKAGES postgresql $INSTALL_PACKAGES python-psycopg2 $INSTALL_PACKAGES libpq-dev if [ ! -d /etc/uwsgi/apps-available ]; then echo $'Directory not found /etc/uwsgi/apps-available' exit 364876328 fi install_nodejs babybuddy if [ ! "$BABYBUDDY_DOMAIN_NAME" ]; then echo $'No domain name was given' exit 3568356 fi if [ -d "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" ]; then rm -rf "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" fi mkdir -p "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" if [ ! -d "/var/www/$BABYBUDDY_DOMAIN_NAME/data/media" ]; then mkdir -p "/var/www/$BABYBUDDY_DOMAIN_NAME/data/media" fi if [ -d /repos/babybuddy ]; then cp -r -p /repos/babybuddy/. "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" cd "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" || exit 324687356 git pull else git_clone "$BABYBUDDY_REPO" "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" fi if [ ! -d "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" ]; then echo $'Unable to clone babybuddy repo' exit 87525 fi cd "/var/www/$BABYBUDDY_DOMAIN_NAME/htdocs" || exit 36587356 git checkout "$BABYBUDDY_COMMIT" -b "$BABYBUDDY_COMMIT" set_completion_param "babybuddy commit" "$BABYBUDDY_COMMIT" if [ -d "$INSTALL_DIR/babybuddy" ]; then rm -rf "$INSTALL_DIR/babybuddy" fi mkdir -p "$INSTALL_DIR/babybuddy" export TEMP="$INSTALL_DIR/babybuddy" export PYTHONPATH=/usr/lib/python3.5/dist-packages:/usr/local/lib/python3.5/dist-packages pip3 install \ pipenv django djangorestframework django-filter \ django-widget-tweaks plotly pandas faker \ dj-database-url gunicorn whitenoise \ easy-thumbnails python-dotenv \ django-storages boto3 coveralls flake8 ipaddress pip3 install psycopg2 export TEMP=/tmp rm -rf "$INSTALL_DIR/babybuddy" if ! npm install -g gulp-cli; then exit 3468365 fi pipenv install --three --dev --skip-lock if ! npm install; then echo $'Failed to run npm install' exit 56376832 fi if ! gulp build; then echo $'Failed to run gulp build' exit 36587356 fi if [ ! -f babybuddy/settings/production.example.py ]; then echo $'File not found babybuddy/settings/production.example.py' exit 36587365835 fi cp babybuddy/settings/production.example.py babybuddy/settings/production.py BABYBUDDY_ONION_HOSTNAME=$(add_onion_service babybuddy 80 "${BABYBUDDY_ONION_PORT}") babybuddy_secret_key="$(create_password "${MINIMUM_PASSWORD_LENGTH}")$(create_password "${MINIMUM_PASSWORD_LENGTH}")$(create_password "${MINIMUM_PASSWORD_LENGTH}")" sed -i "s|SECRET_KEY.*|SECRET_KEY = '$babybuddy_secret_key'|g" babybuddy/settings/production.py sed -i "s|ALLOWED_HOSTS.*|ALLOWED_HOSTS = ['$BABYBUDDY_DOMAIN_NAME', '$BABYBUDDY_ONION_HOSTNAME']|g" babybuddy/settings/production.py export DJANGO_SETTINGS_MODULE=babybuddy.settings.production if ! gulp collectstatic; then echo $'gulp collectstatic failed' exit 368262 fi gulp migrate if [ ! -f "/var/www/$BABYBUDDY_DOMAIN_NAME/data/db.sqlite3" ]; then echo $'db.sqlite3 not found' exit 24528746 fi chown -R www-data:www-data "/var/www/$BABYBUDDY_DOMAIN_NAME/data" chmod 640 "/var/www/$BABYBUDDY_DOMAIN_NAME/data/db.sqlite3" chmod 750 "/var/www/$BABYBUDDY_DOMAIN_NAME/data" pipenv_value=$(pipenv --venv) if [ ! "$pipenv_value" ]; then echo $'No pipenv found' exit 3568353 fi mv "$pipenv_value" "/var/www/$BABYBUDDY_DOMAIN_NAME/base" chown -R www-data:www-data "/var/www/$BABYBUDDY_DOMAIN_NAME/base" { echo '[uwsgi]'; echo 'plugins = python3'; echo 'project = babybuddy'; echo "base_dir = /var/www/$BABYBUDDY_DOMAIN_NAME"; echo ''; echo 'virtualenv = %(base_dir)/base'; echo 'chdir = %(base_dir)/htdocs'; echo 'module = %(project).wsgi:application'; echo 'env = DJANGO_SETTINGS_MODULE=%(project).settings.production'; echo 'env = PYTHONPATH=/usr/lib/python3.5/dist-packages:/usr/local/lib/python3.5/dist-packages'; echo 'master = True'; echo 'vacuum = True'; } > /etc/uwsgi/apps-available/babybuddy.ini ln -s /etc/uwsgi/apps-available/babybuddy.ini /etc/uwsgi/apps-enabled/babybuddy.ini systemctl restart uwsgi add_ddns_domain "$BABYBUDDY_DOMAIN_NAME" babybuddy_nginx_site=/etc/nginx/sites-available/$BABYBUDDY_DOMAIN_NAME if [[ "$ONION_ONLY" == "no" ]]; then nginx_http_redirect "$BABYBUDDY_DOMAIN_NAME" "index index.html" { echo 'upstream babybuddy {'; echo ' server unix:///run/uwsgi/app/babybuddy/socket;'; echo '}'; echo ''; echo 'server {'; echo ' listen 443 ssl;'; echo ' #listen [::]:443 ssl;'; echo " server_name $BABYBUDDY_DOMAIN_NAME;"; echo ''; } >> "$babybuddy_nginx_site" nginx_compress "$BABYBUDDY_DOMAIN_NAME" echo '' >> "$babybuddy_nginx_site" echo ' # Security' >> "$babybuddy_nginx_site" nginx_ssl "$BABYBUDDY_DOMAIN_NAME" nginx_security_options "$BABYBUDDY_DOMAIN_NAME" { echo ' add_header Strict-Transport-Security max-age=15768000;'; echo ''; echo ' access_log /dev/null;'; echo ' error_log /dev/null;'; echo ''; echo " root /var/www/$BABYBUDDY_DOMAIN_NAME/htdocs;"; echo ''; echo ' index index.html;'; echo ' # Location'; echo ' location / {'; } >> "$babybuddy_nginx_site" nginx_limits "$BABYBUDDY_DOMAIN_NAME" '15m' { echo ' uwsgi_pass babybuddy;'; echo ' include uwsgi_params;'; echo ' }'; echo '}'; } >> "$babybuddy_nginx_site" else { echo 'upstream babybuddy {'; echo ' server unix:///run/uwsgi/app/babybuddy/socket;'; echo '}'; echo ''; } > "$babybuddy_nginx_site" fi { echo 'server {'; echo " listen 127.0.0.1:$BABYBUDDY_ONION_PORT default_server;"; echo " server_name $BABYBUDDY_ONION_HOSTNAME;"; echo ''; } >> "$babybuddy_nginx_site" nginx_compress "$BABYBUDDY_DOMAIN_NAME" echo '' >> "$babybuddy_nginx_site" nginx_security_options "$BABYBUDDY_DOMAIN_NAME" { echo ''; echo ' access_log /dev/null;'; echo ' error_log /dev/null;'; echo ''; echo " root /var/www/$BABYBUDDY_DOMAIN_NAME/htdocs;"; echo ''; echo ' index index.html;'; echo ' # Location'; echo ' location / {'; } >> "$babybuddy_nginx_site" nginx_limits "$BABYBUDDY_DOMAIN_NAME" '15m' { echo ' uwsgi_pass babybuddy;'; echo ' include uwsgi_params;'; echo ' }'; echo '}'; } >> "$babybuddy_nginx_site" create_site_certificate "$BABYBUDDY_DOMAIN_NAME" 'yes' nginx_ensite "$BABYBUDDY_DOMAIN_NAME" systemctl restart nginx "${PROJECT_NAME}-pass" -u "$MY_USERNAME" -a babybuddy -p "$BABYBUDDY_ADMIN_PASSWORD" set_completion_param "babybuddy domain" "$BABYBUDDY_DOMAIN_NAME" APP_INSTALLED=1 } # NOTE: deliberately there is no "exit 0"