#!/bin/bash
set -e
root_directory="/var/www/flarum/"
unprivileged_php_user="php_flarum"

install_os="ubuntu"

help_message() {
    echo ""
    echo "##################################"
    echo " Usage"
    echo ""
    echo -e " -a Restore the most recent backup"
    echo " -a sub.domain.tld"
    echo " Eg. $0 -a flarum.mysite.org"
    echo " Eg. $0 -a flarum.mysite.org -a mysecondflarum.mysite.org"
    echo ""
    echo -e " -b Create a backup of specified site"
    echo " -b sub.domain.tld"
    echo " Eg. $0 -b flarum.mysite.org"
    echo " Eg. $0 -b flarum.mysite.org -a mysecondflarum.mysite.org"
    echo ""
    echo " -f sub.domain.tld"
    echo " Eg. $0 -f flarum.mysite.org"
    echo " Eg. $0 -f flarum.mysite.org -f mysecondflarum.mysite.org"
    echo ""
    echo " -h This help message"
    echo ""
    echo -e " -i Install LEMP stack\n (Linux Nginx Mysql Php)"
    echo " Eg. $0 -i"
    echo ""
    echo -e " -r Remove existing site install and database. SSL certificate\n removed if used with -s"
    echo " Eg. $0 -r flarum.mysite.org"
    echo " Eg. $0 -sr flarum.mysite.org"
    echo ""
    echo " -s Configure with ssl. When used with -r will remove ssl. Use before -f or -s."
    echo " Eg $0 -s -f flarum.mysite.org"
    echo " Eg $0 -s -r flarum.mysite.org"
    echo " Eg $0 -s -r flarum.mysite.org -f mysecondflarum.mysite.org"
    echo "##################################"
    echo ""
}

if [ -z "${1+x}" ]; 
    then 
        help_message
        exit 1
  fi


setup_users() {
    # Adds needed users and assigns them to their groups
    sudo mkdir -p "$root_directory"
    sudo useradd "$unprivileged_php_user" --home-dir "$root_directory" --system --shell /bin/false || true
    sudo useradd "$webserver_user" --system --shell /bin/false || true
    sudo gpasswd -a "$unprivileged_php_user" "$webserver_user"
    sudo gpasswd -a "$webserver_user" "$unprivileged_php_user" 
}

setup_php_config() {
    ### Write php7-fpm pool config
    ### Usage: setup_php_config /config/directory
    echo writing php7-fpm config

    sudo tee << EOF "$1" &> /dev/null
[flarum]

listen = /var/run/php7-fpm.\$pool.sock
listen.allowed_clients = 127.0.0.1

user = "$unprivileged_php_user"
group = "$unprivileged_php_user"

listen.owner = www-data
listen.group = www-data

pm = ondemand

pm.max_children = 10
pm.max_requests = 5000
pm.process_idle_timeout = 180s

chdir = /
EOF
}
initial_install_nginx_ubuntu-19.04() {

    webserver_user="www-data"

    # Sets up initial users and groups
    setup_users
    
    # Update lists
    echo 'Updating...'
    sudo apt-get update
    sudo apt-get install \
        nginx \
        mysql-server \
        mysql-client \
    	php7.2 \
        php7.2-curl \
        php7.2-gd \
        php7.2-cli \
        php7.2-mysql \
        php7.2-mbstring \
        php7.2-dom \
        php7.2-fpm \
        pwgen \
        zip \
        unzip \
        git
        
    # Writes php config
    setup_php_config '/etc/php/7.2/fpm/pool.d/flarum.conf'

    # If default nginx config exists delete it
    if [ -f /etc/nginx/sites-enabled/default ]
      then
          sudo rm /etc/nginx/sites-enabled/default
    fi

    sudo service php7.2-fpm stop; sudo service php7.2-fpm start
}


initial_install_nginx_ubuntu-18.10() {

    webserver_user="www-data"

    # Sets up initial users and groups
    setup_users
    
    # Update lists
    echo 'Updating...'
    sudo apt-get update
    sudo apt-get install \
        nginx \
        mysql-server \
        mysql-client \
    	php7.2 \
        php7.2-curl \
        php7.2-gd \
        php7.2-cli \
        php7.2-mysql \
        php7.2-mbstring \
        php7.2-dom \
        php7.2-fpm \
        pwgen \
        zip \
        unzip \
        git
        
    # Writes php config
    setup_php_config '/etc/php/7.2/fpm/pool.d/flarum.conf'

    # If default nginx config exists delete it
    if [ -f /etc/nginx/sites-enabled/default ]
      then
          sudo rm /etc/nginx/sites-enabled/default
    fi

    sudo service php7.2-fpm stop; sudo service php7.1-fpm start


}

initial_install_nginx_ubuntu-16.04() {

    webserver_user="www-data"

    # Sets up initial users and groups
    setup_users
    
    # Update lists
    echo 'Updating...'
    sudo apt-get update
    sudo apt-get install \
        nginx-full \
        mysql-server \
        mysql-client \
        php7.0-curl \
        php7.0-gd \
        php7.0-cli \
        php7.0-mysql \
        php7.0-mbstring \
        php7.0-dom \
        php7.0-fpm \
        pwgen \
        zip \
        unzip \
        git
        
    # Writes php config
    setup_php_config '/etc/php/7.0/fpm/pool.d/flarum.conf'

    # If default nginx config exists delete it
    if [ -f /etc/nginx/sites-enabled/default ]
      then
          sudo rm /etc/nginx/sites-enabled/default
    fi

    sudo service php7.0-fpm stop; sudo service php7.0-fpm start


}
  
initial_install_nginx_ubuntu-17.10() {

    webserver_user="www-data"

    # Sets up initial users and groups
    setup_users
    
    # Update lists
    echo 'Updating...'
    sudo apt-get update
    sudo apt-get install \
        nginx-full \
        mysql-server \
        mysql-client \
        php7.1-curl \
        php7.1-gd \
        php7.1-cli \
        php7.1-mysql \
        php7.1-mbstring \
        php7.1-dom \
        php7.1-fpm \
        pwgen \
        zip \
        unzip \
        git
        
    # Writes php config
    setup_php_config '/etc/php/7.1/fpm/pool.d/flarum.conf'

    # If default nginx config exists delete it
    if [ -f /etc/nginx/sites-enabled/default ]
      then
          sudo rm /etc/nginx/sites-enabled/default
    fi

    sudo service php7.1-fpm stop; sudo service php7.1-fpm start


}

initial_install_nginx_ubuntu-16.04() {

    webserver_user="www-data"

    # Sets up initial users and groups
    setup_users
    
    # Update lists
    echo 'Updating...'
    sudo apt-get update
    sudo apt-get install \
        nginx-full \
        mysql-server \
        mysql-client \
        php7.0-curl \
        php7.0-gd \
        php7.0-cli \
        php7.0-mysql \
        php7.0-mbstring \
        php7.0-dom \
        php7.0-fpm \
        pwgen \
        zip \
        unzip \
        git
        
    # Writes php config
    setup_php_config '/etc/php/7.0/fpm/pool.d/flarum.conf'

    # If default nginx config exists delete it
    if [ -f /etc/nginx/sites-enabled/default ]
      then
          sudo rm /etc/nginx/sites-enabled/default
    fi

    sudo service php7.0-fpm stop; sudo service php7.0-fpm start


}


ssl_nginx_install() {
  
  if [ ! -f /opt/certbot-auto ]
      then
          wget https://dl.eff.org/certbot-auto
          chmod a+x certbot-auto
          sudo mv certbot-auto /opt/certbot-auto
  fi
  
  if [ ! -f /etc/nginx/ssl/dhparam.pem ]
      then
          sudo mkdir -p /etc/nginx/ssl
          echo 'Creating your dhparen.pem will take several minutes or more. It is required one-time only '
          sleep 5
          sudo openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem
  fi
          
  
  if [ ! -d /var/tmp/letsencrypt ]
      then
          sudo mkdir -p /var/tmp/letsencrypt
  fi
  
  if [ ! -f /etc/nginx/sites-available/letsencrypt ]
      then
          # Installing letsencrypt webroot config

          echo Configuring letsencrypt webroot config
          sudo tee << EOF /etc/nginx/sites-available/letsencrypt &> /dev/null
server { # autogenerated
  listen 80;

  root /var/tmp/letsencrypt;
  error_log /var/log/nginx/error.log error;

  server_name _;
  
  location /.well-known/acme-challenge {
  }
}
EOF

  fi
  if [ ! -h /etc/nginx/sites-enabled/letsencrypt ]
      then
          sudo ln -s /etc/nginx/sites-available/letsencrypt /etc/nginx/sites-enabled/letsencrypt
  fi
      
  # Remove flarum nginx config to prevent missing cert error. Will be regenerated
  if [ -f /etc/nginx/sites-available/"$site_url" ]
      then
          sudo rm /etc/nginx/sites-available/"$site_url"
  fi
  sudo nginx -t && sudo service nginx reload
  
  # Causes certificates to be renewed and then restarts nginx
  if [ ! -f /etc/cron.daily/certbot ]
      then
          echo '/opt/certbot-auto renew' | sudo tee --append /etc/cron.daily/certbot
          echo 'service nginx reload' | sudo tee --append /etc/cron.daily/certbot

  fi
}

install_nginx_flarum() {
  site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)"
  site_install_directory="${root_directory}${site_url}"

  
  
  # Only do config if directory already exists
  if [ -d "$site_install_directory" ]
    then
      echo "$site_install_directory already exists. Will only alter configuration"
      existing_install=TRUE
    else
      echo -e "\n\nInstalling $site_url to $site_install_directory\n"
      sleep 3
  fi
  
      # Install composer
  if [ ! -x /usr/bin/composer ]
      then
          php -r "readfile('https://getcomposer.org/installer');" > composer-setup.php
          sudo php composer-setup.php --install-dir=/usr/bin --filename composer
          php -r "unlink('composer-setup.php');"
  fi

  
  if [ "$existing_install" != TRUE ]
    then
      echo Installing flarum..
      sudo mkdir -p "$site_install_directory"
      sudo chown "$USER":"$unprivileged_php_user" "$site_install_directory"
      composer create-project flarum/flarum "$site_install_directory" --stability=beta
  
      # Change group and permissions
      chmod 775 "$site_install_directory"
      chmod -R 775 "$site_install_directory/public/assets" "$site_install_directory/storage"
      sudo chgrp -R "$unprivileged_php_user" "$site_install_directory/public/assets" "$site_install_directory/storage"

  fi

  if [ "$modify_ssl" == TRUE ]
    then
        ssl_nginx_install
  fi
  
  # Installing nginx config
  
  echo Configuring nginx for "$site_install_directory"
  sudo tee << EOF /etc/nginx/sites-available/"$site_url" &> /dev/null
server { # autogenerated
  listen 80;

  root $site_install_directory;
  index index.php index.html index.htm;
  error_log /var/log/nginx/error.log error;

  server_name $site_url;
EOF

  #Optional ssl config
  if [ "$modify_ssl" == TRUE ]
    then
        sudo tee --append << EOF /etc/nginx/sites-available/"$site_url" &> /dev/null
        
  listen 443 ssl;
  ssl_certificate     /etc/letsencrypt/live/$site_url/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/$site_url/privkey.pem;

    location /.well-known/acme-challenge {
        root /var/tmp/letsencrypt;
  }


    # SSL Config
    # modern configuration. tweak to your needs.
  ssl_protocols TLSv1.1 TLSv1.2;
  ssl_session_timeout 1d;

  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:50m;
  ssl_dhparam /etc/nginx/ssl/dhparam.pem;

  # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
  # add_header Strict-Transport-Security max-age=15768000;
  
  # End SSL Config
  
EOF
  fi

  sudo tee --append << 'EOF' /etc/nginx/sites-available/"$site_url" &> /dev/null

    location / { try_files $uri $uri/ /index.php?$query_string; }
    location /api { try_files $uri $uri/ /api.php?$query_string; }
    location /admin { try_files $uri $uri/ /admin.php?$query_string; }

    location /flarum {
        deny all;
        return 404;
    }

    location ~ .php$ {
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass unix:/var/run/php7-fpm.flarum.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~* \.html$ {
        expires -1;
    }

    location ~* \.(css|js|gif|jpe?g|png)$ {
        expires 1M;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    gzip on;
    gzip_http_version 1.1;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_types application/atom+xml
               application/javascript
               application/json
               application/vnd.ms-fontobject
               application/x-font-ttf
               application/x-web-app-manifest+json
               application/xhtml+xml
               application/xml
               font/opentype
               image/svg+xml
               image/x-icon
               text/css
               text/plain
               text/xml;
    gzip_buffers 16 8k;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";


}
EOF

  # Enable flarum site
  if [ ! -h /etc/nginx/sites-enabled/"$site_url" ]
    then
        sudo ln -s /etc/nginx/sites-available/"$site_url" /etc/nginx/sites-enabled/"$site_url"
  fi
  


  # Enable ssl for current flarum install
  if [ "$modify_ssl" == TRUE ]
        then
    /opt/certbot-auto certonly --webroot -w /var/tmp/letsencrypt -d "$site_url"
  fi
  
  sudo nginx -t && sudo service nginx reload
  
  if [ "$existing_install" != TRUE ]
    then
    # Database creation
    # Generate Password
    generated_mysql_pass=$(pwgen 20 1)
    database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
    database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
    if [ -z "${mysql_pass+x}" ];
        then
            read -sp 'Enter mysql root password ' mysql_pass
      fi
      
    mysql -uroot -p"$mysql_pass" -e 'DROP DATABASE `'"$database_name"'` ;' || true
    mysql -uroot -p"$mysql_pass" -e 'CREATE DATABASE `'"$database_name"'` ;' || true
    mysql -uroot -p"$mysql_pass" -e "DROP USER '$database_username'@'localhost' ;" || true
    mysql -uroot -p"$mysql_pass" -e "CREATE USER '$database_username'@'localhost' IDENTIFIED BY '$generated_mysql_pass';" || true
    mysql -uroot -p"$mysql_pass" -e "GRANT USAGE ON * . * TO '$database_username'@'localhost' IDENTIFIED BY '$generated_mysql_pass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;"
    mysql -uroot -p"$mysql_pass" -e "GRANT ALL PRIVILEGES ON \`$database_name\` . * TO '$database_username'@'localhost';"


    echo "#############################"
    echo "Site directory created at"
    echo "$site_install_directory"
    echo ""
    echo "Database Credentials Generated!"
    echo "Copy the below credentials to your website at"
    echo "$site_url"
    echo ""
    echo "Flarum database -> $database_name"
    echo "Flarum username -> $database_username"
    echo "Flarum database password ->" "$generated_mysql_pass"
    echo ""
    echo "Ensure you have completed the web install PRIOR to hitting enter"
    echo "if you are installing flarum more then once"
    echo ""
    echo "#############################"
    unset generated_mysql_pass
    read -sp 'Hit Enter to Continue ' null
    else
      echo Configuration written
  fi
  
}



remove_nginx_site() {
  site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)"
  site_install_directory="${root_directory}${site_url}"

  # Remove site files
  if [ -d "$site_install_directory" ]
      then
          sudo rm -r "$site_install_directory"
  fi
  # Remove site nginx config
  if [ -e "/etc/nginx/sites-available/$site_url" ]
      then
          sudo rm /etc/nginx/sites-available/"$site_url" /etc/nginx/sites-enabled/"$site_url"
  fi

  # Remove ssl keys for site
  if [ "$modify_ssl" == TRUE ] && [ -e /etc/letsencrypt/renewal/"$site_url".conf ]
      then
          sudo rm -r /etc/letsencrypt/live/"$site_url"
          sudo rm -r /etc/letsencrypt/archive/"$site_url"
          sudo rm /etc/letsencrypt/renewal/"$site_url".conf
  fi

  # Drop database and user for this flarum site

  database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
  database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
  if [ -z "${mysql_pass+x}" ];
      then
          read -sp 'Enter mysql root password ' mysql_pass
    fi
  
  mysql -uroot -p"$mysql_pass" -e 'DROP DATABASE `'"$database_name"'` ;' || true
  mysql -uroot -p"$mysql_pass" -e "DROP USER '$database_username'@'localhost' ;" || true

  sudo service nginx configtest && sudo service nginx reload

}

update_flarum() {
    site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)"
    site_install_directory="${root_directory}${site_url}"

    if [ ! -f "$site_install_directory"/composer.json ]
    then
        echo "No composer.json at "$site_install_directory"/composer.json"
    else
        (
            cd "$site_install_directory" && \
            composer update "$(
            python3 -c "import sys, json; \
            [ print(key, end=' ') for key, value in json.load(sys.stdin)['require'].items()]" \
            < composer.json)" && \
            php flarum cache:clear
        )
    fi
}
    

restore_site() {
    site_url="$(echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)"        
    site_install_directory="${root_directory}${site_url}"
    backup_location="${root_directory}backups/${site_url}"

    database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
    database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"

    most_recent_backup="$(find "$backup_location" -maxdepth 1 -type d -not -name "$(basename "$backup_location")" -printf "%T@ %p\n"| sort -nr | head -n1 | cut -d' ' -f 2)"
    echo "Choosing ${most_recent_backup}"

    if [ -z "${mysql_pass+x}" ];                                                
    then                                                                      
        read -sp 'Enter mysql root password ' mysql_pass                      
    fi

    sudo rsync --owner --group -a --delete "${most_recent_backup}/site_files/" "$site_install_directory"
    mysqldump -u'root' -p"$mysql_pass" --add-drop-table --no-data "$database_name" | grep -e '^DROP \| FOREIGN_KEY_CHECKS' | mysql -u'root' -p"$mysql_pass" "$database_name"
    mysql -uroot -p"$mysql_pass" "$database_name" < <(gzip -dc "${most_recent_backup}/"database.sql.gz)

    (
        cd  "$site_install_directory"
        sudo php flarum cache:clear
    )
}

backup_site() {
    site_url="$( echo "$1" | grep -iIohE '[^[:space:]]+' | cut -d'/' -f3)"        
    site_install_directory="${root_directory}${site_url}"
    backup_location="${root_directory}backups/${site_url}"

    if [ ! -d "$backup_location" ]
    then
        echo 'Creating' "$backup_location"
        sudo mkdir -p "${backup_location}"
    fi


    database_name="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
    database_username="$(echo flrm_"${site_url}" | cut -b1-13)$(echo "${site_url}" | md5sum | cut -d' ' -f1 | tr -d '0-9' | cut -b1-3)"
    if [ -z "${mysql_pass+x}" ];
      then
          read -sp 'Enter mysql root password ' mysql_pass
    fi

    if [ -d "${backup_location}"/source ]
    then
        count=1
        new_dir="$(date '+%F')_${count}"
        while [ -d "${backup_location}/$new_dir" ]
        do
            # If new_dir exist, append and increment _n until no match
            count="$((count + 1))"
            new_dir="${new_dir%_*}_${count}"
        done

        # Sync changes and dump database to source backup
        sudo rsync --delete --owner --group -a "$site_install_directory"/ "${backup_location}/source/site_files"
        mysqldump -uroot -p"$mysql_pass" "$database_name" | gzip | sudo tee "${backup_location}/source/database".sql.gz 1> /dev/null
        echo Creating "${backup_location}/${new_dir}"
        sudo mkdir "${backup_location}/${new_dir}"
        
        # Increment backup number if done more then once per day
        if [ "$count" -gt 1 ]
        then
            old_dir="${new_dir%_*}_$((count - 1 ))"
        else
            old_dir="source"
        fi

        # Sync the old backup with the new one, using the source to hardlink only changes
        sudo rsync -a --delete --link-dest="${backup_location}"/source "${backup_location}"/"${old_dir}"/ "$backup_location"/"$new_dir"

    else
        sudo mkdir "${backup_location}"/source
        mysqldump -uroot -p"$mysql_pass" "$database_name" | gzip | sudo tee "${backup_location}/source/database".sql.gz 1> /dev/null
        sudo cp -a "$site_install_directory" "${backup_location}/source/site_files"
    fi

    sudo find "$backup_location" -maxdepth 1 -type d -mtime +14 -daystart -delete
    

}

while getopts "a:b:f:hir:su:" opt; do
    case "$opt" in
        a)
            # Restore most recent backup
            restore_site "$OPTARG"
            ;;
        b)
            # Backup site to root_directory/backups
            backup_site "$OPTARG"
            ;;
        f)
            # Install Flarum with argument of sitename eg helloworld.domain.org
            install_nginx_flarum "$OPTARG"
            ;;
        h)
            help_message
            ;;
        i)
            # initial_install
            if [ "${install_os,,}" == 'ubuntu' ]
            then
                initial_install_nginx_ubuntu-"$(lsb_release -r | grep -oE '[0-9]{1,2}\.[0-9]{1,2}')"
            fi
            ;;
        r)
        
            echo "WARNING - THIS WILL REMOVE THE SITE $OPTARG"
            echo "Are you SURE you want to continue?"
            read -p'Y/N ' kill_site
            if [ "${kill_site,,}" == 'y' ] || [ "${kill_site,,}" == 'yes' ];
            then
                remove_nginx_site "$OPTARG"
            else
                echo "Not removing $OPTARG"
            fi
            ;;
        s)
            # Configure with SSL
            modify_ssl=TRUE
            ;;
        u)
            # Update site
            update_flarum "$OPTARG"
            ;;
    esac
done