From cbd2a71a217b6fec5f0b37a85e19dfaf09f0cf68 Mon Sep 17 00:00:00 2001
From: Bob Mottram <bob@freedombone.net>
Date: Sun, 4 Nov 2018 13:09:54 +0000
Subject: [PATCH] New turtl app implementation

---
 src/freedombone-app-turtl | 781 +++++++++++++-------------------------
 src/freedombone-template  |   2 +-
 src/turtl_old             | 682 +++++++++++++++++++++++++++++++++
 3 files changed, 946 insertions(+), 519 deletions(-)
 mode change 100755 => 100644 src/freedombone-app-turtl
 create mode 100755 src/turtl_old

diff --git a/src/freedombone-app-turtl b/src/freedombone-app-turtl
old mode 100755
new mode 100644
index 6af653323..636ab4150
--- a/src/freedombone-app-turtl
+++ b/src/freedombone-app-turtl
@@ -1,4 +1,5 @@
 #!/bin/bash
+#
 #  _____               _           _
 # |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
 # |   __|  _| -_| -_| . | . |     | . | . |   | -_|
@@ -6,15 +7,10 @@
 #
 #                              Freedom in the Cloud
 #
-# turtl app
-#
-# http://portallinux.es/instalacion-servidor-turtl-debian-8
-# http://framacloud.org/cultiver-son-jardin/installation-de-turtl/
-#
 # License
 # =======
 #
-# Copyright (C) 2016-2018 Bob Mottram <bob@freedombone.net>
+# 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
@@ -29,38 +25,34 @@
 # 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 writer"
+VARIANTS='full full-vim'
 
 IN_DEFAULT_INSTALL=0
+INSTALLED_ON_DEFAULT_DOMAIN=0
 SHOW_ON_ABOUT=1
-NOT_ON_ARM=1
+
+# whether to show the domain name in the web UI
+SHOW_DOMAIN_IN_WEBADMIN=1
+NOT_ON_API=0
 
 TURTL_DOMAIN_NAME=
 TURTL_CODE=
-TURTL_ONION_PORT=8107
-TURTL_PORT=8181
-TURTL_REPO="https://github.com/turtl/api.git"
-TURTL_COMMIT='53e00a5583f52de8f86ef380fe11c176b5738dcf'
-TURTL_ADMIN_PASSWORD=
-TURTL_STORAGE_LIMIT_MB=100
-TURTL_BASE_DIR=/etc/turtl
-
-# part of a hack to enable/disable signups
-TURTL_SIGNUP_STRING='Signup a new user'
-turtl_users_file=$TURTL_BASE_DIR/api/controllers/users.lisp
-
-TURTL_SHORT_DESCRIPTION=$'Note taking'
-TURTL_DESCRIPTION=$'Note taking'
-TURTL_MOBILE_APP_URL=https://turtlapp.com/releases/mobile/turtl-android-0.6.4.apk
+TURTL_ONION_PORT=9473
+TURTL_REPO="https://github.com/turtl/server"
+TURTL_COMMIT='475de66908c7537ddde4397e918f9da4ab2a5aea'
+TURTL_PORT_INTERNAL=8181
+TURTL_APP_VERSION='0.7.2'
+
+# These parameters are used by the FreedomBox mobile app and web UI
+TURTL_SHORT_DESCRIPTION='The secure collaborative notebook'
+TURTL_DESCRIPTION='Whether its bookmarks or passwords, files or shopping lists...Turtl organizes it all and makes it easy to find later. Sync across your devices.'
+TURTL_MOBILE_APP_URL="https://github.com/turtl/android/releases/download/v${TURTL_APP_VERSION}/turtl-${TURTL_APP_VERSION}-android.apk"
 
 turtl_variables=(ONION_ONLY
-                 DEFAULT_DOMAIN_NAME
-                 TURTL_DOMAIN_NAME
-                 TURTL_CODE
-                 TURTL_STORAGE_LIMIT_MB
-                 DDNS_PROVIDER
-                 MY_EMAIL_ADDRESS
-                 MY_USERNAME)
+                       TURTL_DOMAIN_NAME
+                       TURTL_CODE
+                       DDNS_PROVIDER
+                       MY_USERNAME)
 
 function logging_on_turtl {
     echo -n ''
@@ -70,20 +62,17 @@ function logging_off_turtl {
     echo -n ''
 }
 
-function change_password_turtl {
-    echo -n ''
-#    change_username="$1"
-#    new_user_password="$2"
-}
-
 function remove_user_turtl {
-    echo -n ''
-#    remove_username="$1"
+    remove_username="$1"
+
+    "${PROJECT_NAME}-pass" -u "$remove_username" --rmapp turtl
 }
 
 function add_user_turtl {
-#    new_username="$1"
-#    new_user_password="$2"
+    new_username="$1"
+    new_user_password="$2"
+
+    "${PROJECT_NAME}-pass" -u "$new_username" -a turtl -p "$new_user_password"
     echo '0'
 }
 
@@ -92,113 +81,67 @@ function install_interactive_turtl {
         ONION_ONLY='no'
     fi
 
-    if [[ $ONION_ONLY != "no" ]]; then
-        TURTL_DOMAIN_NAME='notes.local'
+    if [[ "$ONION_ONLY" != "no" ]]; then
+        TURTL_DOMAIN_NAME='turtl.local'
         write_config_param "TURTL_DOMAIN_NAME" "$TURTL_DOMAIN_NAME"
     else
-        function_check interactive_site_details
         interactive_site_details "turtl" "TURTL_DOMAIN_NAME" "TURTL_CODE"
     fi
     APP_INSTALLED=1
 }
 
-function turtl_disable_registrations {
-    if grep -q "$TURTL_SIGNUP_STRING" $turtl_users_file; then
-        if [ -f $turtl_users_file ]; then
-            cp $turtl_users_file $TURTL_BASE_DIR/.users.lisp
-            sed -i '/(route (:post "\/users") (req res)/,/(send-json res user))))/{//!d}' $turtl_users_file
-            sed -i 's|(send-json res user))))|())|g' $turtl_users_file
-            chown -R turtl:turtl $TURTL_BASE_DIR
-            systemctl restart turtl
-        fi
-    fi
+function change_password_turtl {
+    curr_username="$1"
+    new_user_password="$2"
+
+    read_config_param 'TURTL_DOMAIN_NAME'
+
+    "${PROJECT_NAME}-pass" -u "$curr_username" -a turtl -p "$new_user_password"
 }
 
-function turtl_enable_registrations {
-    if ! grep -q "$TURTL_SIGNUP_STRING" $turtl_users_file; then
-        if [ -f $TURTL_BASE_DIR/.users.lisp ]; then
-            cp $TURTL_BASE_DIR/.users.lisp $turtl_users_file
-            rm $TURTL_BASE_DIR/.users.lisp
-            chown -R turtl:turtl $TURTL_BASE_DIR
-            systemctl restart turtl
+function turtl_create_database {
+    if [ -f "$IMAGE_PASSWORD_FILE" ]; then
+        TURTL_ADMIN_PASSWORD="$(printf "%d" "$(cat "")")"
+    else
+        if [ ! "$TURTL_ADMIN_PASSWORD" ]; then
+            TURTL_ADMIN_PASSWORD=$(create_password "${MINIMUM_PASSWORD_LENGTH}")
         fi
     fi
-}
+    if [ ! "$TURTL_ADMIN_PASSWORD" ]; then
+        return
+    fi
 
-function configure_interactive_turtl_signups {
-    # This implements a hack which removes or adds the function needed
-    # to sign up new users. It should eventually be removed once that
-    # capability exists within the api
-
-    dialog --title $"Allow new turtl signups" \
-           --backtitle $"Freedombone Control Panel" \
-           --defaultno \
-           --yesno $"\\nAllow registration of new users?" 10 60
-    sel=$?
-    case $sel in
-        0)
-            turtl_enable_registrations
-            dialog --title $"Allow new turtl signups" \
-                   --msgbox $"New turtl user registrations are now allowed" 6 60
-            return;;
-        1)
-            turtl_disable_registrations
-            dialog --title $"Disable new turtl signups" \
-                   --msgbox $"New turtl user registrations are now disabled" 6 60
-            return;;
-        255) return;;
-    esac
+    systemctl restart postgresql
+    run_system_query_postgresql "CREATE USER turtl WITH PASSWORD '$TURTL_ADMIN_PASSWORD';"
+    run_system_query_postgresql "CREATE DATABASE turtl OWNER turtl;"
+    run_system_query_postgresql "GRANT ALL PRIVILEGES ON DATABASE turtl to turtl;"
+    run_system_query_postgresql "set statement_timeout to 40000;"
 }
 
-function configure_interactive_turtl_storage {
-    data=$(mktemp 2>/dev/null)
-    dialog --title $"Change storage limit" \
-           --backtitle $"Freedombone Control Panel" \
-           --inputbox $"Enter a storage limit in megabytes." 8 75 "$TURTL_STORAGE_LIMIT_MB" 2>"$data"
-    sel=$?
-    case $sel in
-        0)
-            STORAGE=$(<"$data")
-            if [ ${#STORAGE} -gt 0 ]; then
-                TURTL_STORAGE_LIMIT_MB=$STORAGE
-                sed -i "s|defparameter *default-storage-limit*.*|defparameter *default-storage-limit* ${TURTL_STORAGE_LIMIT_MB})|g" $TURTL_BASE_DIR/api/config/config.lisp
-                systemctl restart turtl
-                dialog --title $"Change storage limit" \
-                       --msgbox $"Storage limit changed to ${TURTL_STORAGE_LIMIT_MB}M" 6 50
-            fi
-            ;;
-    esac
-    rm -f "$data"
+function reconfigure_turtl {
+    # This is used if you need to switch identity. Dump old keys and generate new ones
+    echo -n ''
 }
 
 function configure_interactive_turtl {
-    data=$(mktemp 2>/dev/null)
-    dialog --backtitle $"Freedombone Control Panel" \
-           --title $"turtl app settings" \
-           --radiolist $"Choose an operation:" 12 70 3 \
-           1 $"Enable/disable new user registrations" off \
-           2 $"Change storage limit" off \
-           3 $"Exit" on 2> "$data"
-    sel=$?
-    case $sel in
-        1) rm -f "$data"
-           exit 1;;
-        255) rm -f "$data"
-             exit 1;;
-    esac
-    case $(cat "$data") in
-        1) configure_interactive_turtl_signups;;
-        2) configure_interactive_turtl_storage;;
-        3) rm -f "$data"
-           return;;
-    esac
-    rm -f "$data"
-}
+    W=(1 $"Option 1"
+       2 $"Option 2")
 
-function reconfigure_turtl {
-    if [ -d $TURTL_BASE_DIR/data ]; then
-        rm -rf $TURTL_BASE_DIR/data/*
-    fi
+    while true
+    do
+        # shellcheck disable=SC2068
+        selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"turtl" --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_turtl {
@@ -207,88 +150,76 @@ function upgrade_turtl {
         return
     fi
 
-    read_config_param "TURTL_DOMAIN_NAME"
-
-    function_check set_repo_commit
-    set_repo_commit $TURTL_BASE_DIR/api "turtl commit" "$TURTL_COMMIT" $TURTL_REPO
-
-    # this is used as a crude way of disabling signups and so
-    # should be superceded in future
-    if [ -f $TURTL_BASE_DIR/.users.lisp ]; then
-        turtl_disable_registrations
+    if grep -q "turtl domain" "$COMPLETION_FILE"; then
+        TURTL_DOMAIN_NAME=$(get_completion_param "turtl domain")
     fi
-    systemctl restart turtl
 
-    nginx_dissite $TURTL_DOMAIN_NAME
-    chown -R turtl:turtl $TURTL_BASE_DIR
-    nginx_ensite $TURTL_DOMAIN_NAME
+    # update to the next commit
+    set_repo_commit "/etc/turtl" "turtl commit" "$TURTL_COMMIT" "$TURTL_REPO"
+    chown -R turtl:turtl "/etc/turtl"
+    systemctl restart turtl
 }
 
 function backup_local_turtl {
-    read_config_param "TURTL_DOMAIN_NAME"
-    source_directory=$TURTL_BASE_DIR
-    if [ -d $source_directory ]; then
-        dest_directory=turtl
-        function_check suspend_site
-        suspend_site ${TURTL_DOMAIN_NAME}
-
-        function_check backup_directory_to_usb
-        backup_directory_to_usb $source_directory $dest_directory
-
-        function_check restart_site
-        restart_site
+    TURTL_DOMAIN_NAME='turtl'
+    if grep -q "turtl domain" "$COMPLETION_FILE"; then
+        TURTL_DOMAIN_NAME=$(get_completion_param "turtl domain")
     fi
-    source_directory=/var/lib/rethinkdb
-    if [ -d $source_directory ]; then
-        dest_directory=rethinkdb
-        function_check suspend_site
-        suspend_site ${TURTL_DOMAIN_NAME}
 
-        function_check backup_directory_to_usb
-        backup_directory_to_usb $source_directory $dest_directory
+    source_directory=/etc/turtl
 
-        function_check restart_site
-        restart_site
-    fi
+    suspend_site "${TURTL_DOMAIN_NAME}"
+
+    systemctl stop turtl
+
+    dest_directory=turtl
+    backup_directory_to_usb "$source_directory" $dest_directory
+
+    USE_POSTGRESQL=1
+    backup_database_to_usb turtl
+
+    restart_site
+    systemctl start turtl
 }
 
 function restore_local_turtl {
-    read_config_param "TURTL_DOMAIN_NAME"
-    if [ $TURTL_DOMAIN_NAME ]; then
-        temp_restore_dir=/root/tempturtl
-        restore_directory_from_usb $temp_restore_dir turtl
+    if ! grep -q "turtl domain" "$COMPLETION_FILE"; then
+        return
+    fi
+    TURTL_DOMAIN_NAME=$(get_completion_param "turtl domain")
+    if [ ! "$TURTL_DOMAIN_NAME" ]; then
+        return
+    fi
+    suspend_site "${TURTL_DOMAIN_NAME}"
+    systemctl stop turtl
 
-        if [ -d ${temp_restore_dir}/etc/turtl ]; then
-            cp -r ${temp_restore_dir}/etc/turtl/* /etc/turtl/
-        else
-            cp -r ${temp_restore_dir}/* /etc/turtl/
-        fi
-        # shellcheck disable=SC2181
-        if [ ! "$?" = "0" ]; then
-            set_user_permissions
-            backup_unmount_drive
-            exit 36723
-        fi
-        rm -rf ${temp_restore_dir}
-        chown -R turtl:turtl $TURTL_BASE_DIR
+    temp_restore_dir=/root/tempturtl
+    turtl_dir=/etc/turtl
 
-        temp_restore_dir=/root/temprethinkdb
-        restore_directory_from_usb $temp_restore_dir rethinkdb
+    turtl_create_database
 
-        if [ -d ${temp_restore_dir}/var/lib/rethinkdb ]; then
-            cp -r ${temp_restore_dir}/var/lib/rethinkdb/* /var/lib/rethinkdb/
-        else
-            cp -r ${temp_restore_dir}/* /var/lib/rethinkdb/
-        fi
+    USE_POSTGRESQL=1
+    restore_database turtl
+    if [ -d $temp_restore_dir ]; then
+        rm -rf $temp_restore_dir
+    fi
 
-        # shellcheck disable=SC2181
-        if [ ! "$?" = "0" ]; then
-            set_user_permissions
-            backup_unmount_drive
-            exit 378324
+    restore_directory_from_usb $temp_restore_dir turtl
+    if [ -d $temp_restore_dir ]; then
+        if [ -d "$temp_restore_dir$turtl_dir" ]; then
+            cp -rp "$temp_restore_dir$turtl_dir"/* "$turtl_dir"/
+        else
+            if [ ! -d "$turtl_dir" ]; then
+                mkdir "$turtl_dir"
+            fi
+            cp -rp "$temp_restore_dir"/* "$turtl_dir"/
         fi
-        rm -rf ${temp_restore_dir}
+        chown -R turtl:turtl "$turtl_dir"
+        rm -rf $temp_restore_dir
     fi
+    systemctl start turtl
+
+    restart_site
 }
 
 function backup_remote_turtl {
@@ -300,383 +231,197 @@ function restore_remote_turtl {
 }
 
 function remove_turtl {
-    if [ ! -d $TURTL_BASE_DIR ]; then
-        return
-    fi
-    systemctl stop turtl
-    systemctl disable turtl
-    rm /etc/systemd/system/turtl.service
-    systemctl daemon-reload
+    nginx_dissite "$TURTL_DOMAIN_NAME"
+    remove_certs "$TURTL_DOMAIN_NAME"
 
-    remove_rethinkdb
-    remove_app turtl
-    remove_completion_param install_turtl
-    sed -i '/turtl/d' "$COMPLETION_FILE"
-    nginx_dissite $TURTL_DOMAIN_NAME
-    if [ -f /etc/nginx/sites-available/$TURTL_DOMAIN_NAME ]; then
-        rm /etc/nginx/sites-available/$TURTL_DOMAIN_NAME
+    if [ -f /etc/systemd/system/turtl.service ]; then
+        systemctl stop turtl
+        systemctl disable turtl
+        rm /etc/systemd/system/turtl.service
     fi
-    remove_certs $TURTL_DOMAIN_NAME
-    function_check remove_onion_service
-    remove_onion_service turtl ${TURTL_ONION_PORT}
-    function_check remove_ddns_domain
-    remove_ddns_domain $TURTL_DOMAIN_NAME
-    rm -rf /etc/rethinkdb
-    rm -rf /var/lib/rethinkdb
-    rm -rf $TURTL_BASE_DIR
-
-    groupdel -f turtl
     userdel -r turtl
-}
+    remove_nodejs turtl
 
 
-function turtl_setup {
-    PIDFILE=${PIDFILE:-nil}
-    BINDADDR=${BINDADDR:-0.0.0.0}
-    BINDPORT=${BINDPORT:-8181}
-    PROD_ERR_HANDLING=${PROD_ERR_HANDLING:-t}
-    if [[ $ONION_ONLY == 'no' ]]; then
-        FQDN=${FQDN:-$TURTL_DOMAIN_NAME}
-        SITE_URL=${SITE_URL:-https://$TURTL_DOMAIN_NAME}
-    else
-        FQDN=${FQDN:-$TURTL_ONION_HOSTNAME}
-        SITE_URL=${SITE_URL:-http://$TURTL_ONION_HOSTNAME}
-    fi
-    ADMIN_EMAIL=${ADMIN_EMAIL:-$MY_EMAIL_ADDRESS}
-    EMAIL_FROM=${EMAIL_FROM:-noreply@$DEFAULT_DOMAIN_NAME}
-    SMTP_USER=${SMTP_USER:-}
-    SMTP_PASS=${SMTP_PASS:-}
-    DISPLAY_ERRORS=${DISPLAY_ERRORS:-t}
-    DEFAULT_STORAGE_LIMIT=${DEFAULT_STORAGE_LIMIT:-100}
-    STORAGE_INVITE_CREDIT=${STORAGE_INVITE_CREDIT:-25}
-    if [[ $ONION_ONLY == 'no' ]]; then
-        LOCAL_UPLOAD_URL=${LOCAL_UPLOAD_URL:-https://$TURTL_DOMAIN_NAME}
-    else
-        LOCAL_UPLOAD_URL=${LOCAL_UPLOAD_URL:-http://$TURTL_ONION_HOSTNAME}
+    if [ -d "/var/www/$TURTL_DOMAIN_NAME" ]; then
+        rm -rf "/var/www/$TURTL_DOMAIN_NAME"
     fi
-    LOCAL_UPLOAD_PATH=${LOCAL_UPLOAD_PATH:-"$TURTL_BASE_DIR/data"}
-    AWS_S3_TOKEN=${AWS_S3_TOKEN:-(:token ''
-                                  :secret ''
-                                  :bucket ''
-                                  :endpoint 'https://s3.amazonaws.com')}
-
-    # generates the config-file
-    cat  << __ENDCONFIG__ > $TURTL_BASE_DIR/api/config/config.lisp
-(in-package :turtl)
-(defparameter *root* (asdf:system-relative-pathname :turtl #P""))
-(defparameter *pid-file* "${PIDFILE}")
-(defvar *server-bind* "${BINDADDR}")
-(defvar *server-port* ${BINDPORT})
-(defvar *db-name* "turtl")
-(defvar *db-host* "127.0.0.1")
-(defvar *db-port* 28015)
-(defvar *production-error-handling* ${PROD_ERR_HANDLING})
-(defvar *enable-hsts-header* nil)
-(defvar *site-url* "${SITE_URL}")
-(defvar *api-path* "")
-(defvar *admin-email* "${ADMIN_EMAIL}")
-(defvar *email-from* "${EMAIL_FROM}")
-(defvar *email-user* "${SMTP_USER}")
-(defvar *email-pass* "${SMTP_PASS}")
-(defvar *display-errors* ${DISPLAY_ERRORS})
-(defparameter *default-storage-limit* ${DEFAULT_STORAGE_LIMIT})
-(defparameter *storage-invite-credit* ${STORAGE_INVITE_CREDIT})
-(vom:config :turtl :info)
-(defvar *local-upload* "${LOCAL_UPLOAD_PATH}")
-(defvar *local-upload-url* "${LOCAL_UPLOAD_URL}")
-(defvar *amazon-s3* "${AWS_S3_TOKEN}")
-__ENDCONFIG__
-
-    cat $TURTL_BASE_DIR/api/config/config.footer >> $TURTL_BASE_DIR/api/config/config.lisp
-
-    # start the turtl server
-    systemctl restart rethinkdb
-
-    if [ ! -f $TURTL_BASE_DIR/quicklisp/setup.lisp ]; then
-        echo $"$TURTL_BASE_DIR/quicklisp/setup.lisp was not found"
-        exit 6238234
+    if [ -f "/etc/nginx/sites-available/$TURTL_DOMAIN_NAME" ]; then
+        rm "/etc/nginx/sites-available/$TURTL_DOMAIN_NAME"
     fi
-
-    { echo '[Unit]';
-      echo 'Description=Note taking service';
-      echo 'Documentation=http://turtl.it';
-      echo 'Requires=network.target';
-      echo 'Requires=rethinkdb.service';
-      echo 'After=network.target';
-      echo 'After=rethinkdb.service';
-      echo '';
-      echo '[Service]';
-      echo 'Type=simple';
-      echo 'User=turtl';
-      echo "WorkingDirectory=$TURTL_BASE_DIR/api/"; } > /etc/systemd/system/turtl.service
-
-    if [[ "$check_architecture" == *"64"* && "$check_architecture" != *"arm"* ]]; then
-        echo "ExecStart=$TURTL_BASE_DIR/ccl/lx86cl64 -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
-    else
-        if [[ "$check_architecture" != *"arm"* ]]; then
-            echo "ExecStart=$TURTL_BASE_DIR/ccl/lx86cl -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
-        else
-            echo "ExecStart=$TURTL_BASE_DIR/ccl/armcl -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
-        fi
+    drop_database_postgresql turtl
+    remove_onion_service turtl "${TURTL_ONION_PORT}"
+    if grep -q "turtl" /etc/crontab; then
+        sed -i "/turtl/d" /etc/crontab
     fi
-    { echo '';
-      echo '[Install]';
-      echo 'WantedBy=multi-user.target'; } >> /etc/systemd/system/turtl.service
-    chmod +x /etc/systemd/system/turtl.service
+    remove_app turtl
+    remove_completion_param install_turtl
+    sed -i '/turtl/d' "$COMPLETION_FILE"
 
-    chown -R turtl:turtl $TURTL_BASE_DIR
-    systemctl enable turtl
-    systemctl daemon-reload
-    systemctl start turtl
+    remove_ddns_domain "$TURTL_DOMAIN_NAME"
 }
 
-function install_turtl_api {
-    # https://github.com/ArthurGarnier/turtl-docker
-    $INSTALL_PACKAGES wget libterm-readline-perl-perl gcc libuv1-dev
+function install_turtl {
+    install_postgresql
 
-    if [ ! -d $TURTL_BASE_DIR ]; then
-        mkdir -p $TURTL_BASE_DIR
-    fi
-    cd "$TURTL_BASE_DIR" || exit 745726542
-    mkdir cd $TURTL_BASE_DIR/data
-    check_architecture=$(uname -a)
-
-    # Install ccl
-    if [[ "$check_architecture" != *"arm"* ]]; then
-        wget -P $TURTL_BASE_DIR/ ftp://ftp.clozure.com/pub/release/1.11/ccl-1.11-linuxx86.tar.gz
-        mkdir -p $TURTL_BASE_DIR/ccl
-        tar xvzf $TURTL_BASE_DIR/ccl-1.11-linuxx86.tar.gz -C $TURTL_BASE_DIR/ccl --strip-components=1
-    else
-        wget -P $TURTL_BASE_DIR/ ftp://ftp.clozure.com/pub/release/1.11/ccl-1.11-linuxarm.tar.gz
-        mkdir -p $TURTL_BASE_DIR/ccl
-        tar xvzf $TURTL_BASE_DIR/ccl-1.11-linuxarm.tar.gz -C $TURTL_BASE_DIR/ccl --strip-components=1
+    install_nodejs turtl
+    if [ ! "$TURTL_DOMAIN_NAME" ]; then
+        echo $'No domain name was given'
+        exit 3568356
     fi
 
-    # install quicklisp
-    cat  << __ENDCONFIG__ > $TURTL_BASE_DIR/quicklisp_install
-(load (compile-file "asdf.lisp"))
-(load (compile-file "quicklisp.lisp"))
-(quicklisp-quickstart:install)
-(ql:system-apropos "vecto")
-(ql:quickload "alexandria")
-(ql:quickload "babel")
-(ql:quickload "blackbird")
-(ql:quickload "bordeaux-threads")
-(ql:quickload "cffi")
-(ql:quickload "chipz")
-(ql:quickload "chunga")
-(ql:quickload "cl-annot")
-(ql:quickload "cl-async")
-(ql:quickload "cl-async-future")
-(ql:quickload "cl-base64")
-(ql:quickload "cl-fad")
-(ql:quickload "cl-libuv")
-(ql:quickload "cl-mongo-id")
-(ql:quickload "cl-ppcre")
-(ql:quickload "cl-rethinkdb")
-(ql:quickload "cl-smtp")
-(ql:quickload "cl+ssl")
-(ql:quickload "cl-syntax")
-(ql:quickload "cl-utilities")
-(ql:quickload "cl-vectors")
-(ql:quickload "do-urlencode")
-(ql:quickload "drakma")
-(ql:quickload "drakma-async")
-(ql:quickload "event-glue")
-(ql:quickload "fast-http")
-(ql:quickload "fast-io")
-(ql:quickload "flexi-streams")
-(ql:quickload "ironclad")
-(ql:quickload "jonathan")
-(ql:quickload "local-time")
-(ql:quickload "md5")
-(ql:quickload "named-readtables")
-(ql:quickload "nibbles")
-(ql:quickload "proc-parse")
-(ql:quickload "puri")
-(ql:quickload "quri")
-(ql:quickload "salza2")
-(ql:quickload "secure-random")
-(ql:quickload "smart-buffer")
-(ql:quickload "split-sequence")
-(ql:quickload "static-vectors")
-(ql:quickload "trivial-backtrace")
-(ql:quickload "trivial-features")
-(ql:quickload "trivial-garbage")
-(ql:quickload "trivial-gray-streams")
-(ql:quickload "trivial-types")
-(ql:quickload "usocket")
-(ql:quickload "vecto")
-(ql:quickload "vom")
-(ql:quickload "wookie")
-(ql:quickload "xmls")
-(ql:quickload "xsubseq")
-(ql:quickload "yason")
-(ql:quickload "zpb-ttf")
-(ql:quickload "zpng")
-(ql:add-to-init-file)
-(ccl::quit)
-__ENDCONFIG__
-
-    if [ ! -f asdf.lisp ]; then
-        wget https://common-lisp.net/project/asdf/asdf.lisp
+    if [ -d "/var/www/$TURTL_DOMAIN_NAME/htdocs" ]; then
+        rm -rf "/var/www/$TURTL_DOMAIN_NAME/htdocs"
     fi
-    if [ ! -f quicklisp.lisp ]; then
-        wget https://beta.quicklisp.org/quicklisp.lisp
+    mkdir "/var/www/$TURTL_DOMAIN_NAME"
+    if [ -d /repos/turtl ]; then
+        mkdir -p "/var/www/$TURTL_DOMAIN_NAME/htdocs"
+        cp -r -p /repos/turtl/. "/etc/turtl"
+        cd "/etc/turtl" || exit 36487365
+        git pull
+    else
+        mkdir "/var/www/$TURTL_DOMAIN_NAME/htdocs"
+        git_clone "$TURTL_REPO" "/etc/turtl"
     fi
 
-    if [ -d $TURTL_BASE_DIR ]; then
-        chown -R turtl:turtl $TURTL_BASE_DIR
-    fi
-    adduser --disabled-login --home=$TURTL_BASE_DIR --gecos 'turtl' turtl
-    if [ ! -d $TURTL_BASE_DIR ]; then
-        echo $"$TURTL_BASE_DIR directory not created"
-        exit 263493
+    if [ ! -d "/etc/turtl" ]; then
+        echo $'Unable to clone turtl repo'
+        exit 87525
     fi
 
-    groupadd turtl
-    chown -R turtl:turtl $TURTL_BASE_DIR
+    cd "/etc/turtl" || exit 3463754637
+    git checkout "$TURTL_COMMIT" -b "$TURTL_COMMIT"
+    set_completion_param "turtl commit" "$TURTL_COMMIT"
 
-    if [[ "$check_architecture" != *"arm"* ]]; then
-        if [[ "$check_architecture" == *"64"* ]]; then
-            su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/lx86cl64" - turtl
-        else
-            su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/lx86cl" - turtl
-        fi
-    else
-        su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/larmcl" - turtl
+    if ! npm install; then
+        echo $'Failed to install turtl'
+        exit 24682468
     fi
-    rm $TURTL_BASE_DIR/quicklisp_install
 
-    install_rethinkdb
-    echo "http-port=8091" > /etc/rethinkdb/instances.d/turtl.conf
-    chown -R rethinkdb:rethinkdb /var/lib/rethinkdb
+    mkdir /etc/turtl/plugins || exit 35683
+    ./scripts/init-db.sh
 
-    # install turtl API
-    cd "$TURTL_BASE_DIR/" || exit 6428462
+    chmod g+w "/var/www/$TURTL_DOMAIN_NAME/htdocs"
+    chown -R www-data:www-data "/var/www/$TURTL_DOMAIN_NAME/htdocs"
 
-    if [ -d /repos/turtl ]; then
-        mkdir -p $TURTL_BASE_DIR/api
-        cp -r -p /repos/turtl/. $TURTL_BASE_DIR/api
-        cd "$TURTL_BASE_DIR/api" || exit 57141845
-        git pull
-    else
-        git clone $TURTL_REPO $TURTL_BASE_DIR/api
-    fi
+    turtl_create_database
 
-    cd "$TURTL_BASE_DIR/api" || exit 35814614
-    git checkout $TURTL_COMMIT -b $TURTL_COMMIT
-    set_completion_param "turtl commit" "$TURTL_COMMIT"
-    cd "$TURTL_BASE_DIR/quicklisp/local-projects" || exit 43618941415
-    git clone git://github.com/orthecreedence/cl-hash-util
-    if [[ "$check_architecture" != *"arm"* ]]; then
-        if [[ "$check_architecture" == *"64"* ]]; then
-            su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/lx86cl64 -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
-        else
-            su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/lx86cl -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
-        fi
+    add_ddns_domain "$TURTL_DOMAIN_NAME"
+
+    TURTL_ONION_HOSTNAME=$(add_onion_service turtl 80 "${TURTL_ONION_PORT}")
+
+    cp /etc/turtl/config/config.yaml.default /etc/turtl/config/config.yaml
+    sed -i "s|connstr:.*|connstr: 'postgres://turtl:${TURTL_ADMIN_PASSWORD}@127.0.0.1:5432/turtl'|g" /etc/turtl/config/config.yaml
+    if [[ "$ONION_ONLY" != 'no' ]]; then
+        sed -i "s|api_url:.*|api_url: 'https://${TURTL_DOMAIN_NAME}'|g" /etc/turtl/config/config.yaml
+        sed -i "s|www_url:.*|www_url: 'https://${TURTL_DOMAIN_NAME}/web'|g" /etc/turtl/config/config.yaml
     else
-        su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/larmcl -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
+        sed -i "s|api_url:.*|api_url: 'http://${TURTL_ONION_HOSTNAME}'|g" /etc/turtl/config/config.yaml
+        sed -i "s|www_url:.*|www_url: 'http://${TURTL_ONION_HOSTNAME}/web'|g" /etc/turtl/config/config.yaml
     fi
+    sed -i "s|admin:.*|admin: '${MY_EMAIL_ADDRESS}'|g" /etc/turtl/config/config.yaml
+    sed -i "s|info:.*|info: 'Turtl <${MY_EMAIL_ADDRESS}>'|g" /etc/turtl/config/config.yaml
+    sed -i "s|invites:.*|invites: '${MY_EMAIL_ADDRESS}'|g" /etc/turtl/config/config.yaml
+    TURTL_HASH="$(create_random_string 30)$(create_random_string 30)$(create_random_string 30)$(create_random_string 30)$(create_random_string 30)$(create_random_string 30)"
+    sed -i "s|secure_hash_salt:.*|secure_hash_salt: \"${TURTL_HASH}\"|g" /etc/turtl/config/config.yaml
+    if [ ! -d /etc/turtl/public/uploads ]; then
+        mkdir -p /etc/turtl/public/uploads
+    fi
+    sed -i "s|local:.*|local: '/etc/turtl/public/uploads'|g" /etc/turtl/config/config.yaml
 
-    # config
-    { echo '(defvar *enabled-cors-resources* "resource://turtl-at-lyonbros-dot-com"';
-      echo '  "When set, will enable CORS for resource:// origins if they match the given';
-      echo '   string. Entries should be comma separated (this string is passed verbatim in';
-      echo '   the Access-Control-Allow-Origin header).")';
-      echo '(defparameter *public-actions*';
-      echo "  \`((:post . ,(concatenate 'string *api-path* \"/users\"))";
-      echo "    (:post . ,(concatenate 'string *api-path* \"/log/error\"))";
-      echo '    (:post . "/cla/sign")';
-      echo '    (:get  . "/ping")';
-      echo '    (:get  . "/admin")';
-      echo "    (:get . ,(cl-ppcre:create-scanner (concatenate 'string *api-path* \"/invites/codes/([0-9a-f-]+)\"))))";
-      echo "  \"A list of public resources/actions that do not require authentication.\")";
-      echo "(defvar *analytics* '(:enabled t";
-      echo '                      :db "analytics"))'; } > "$TURTL_BASE_DIR/api/config/config.footer"
-
-    cp $TURTL_BASE_DIR/asdf.lisp $TURTL_BASE_DIR/api
-    echo '(load (compile-file "asdf.lisp"))' > $TURTL_BASE_DIR/api/launch.lisp
-    echo "(pushnew \"./\" asdf:*central-registry* :test #'equal)" >> $TURTL_BASE_DIR/api/launch.lisp
-    echo '(load "start")' >> $TURTL_BASE_DIR/api/launch.lisp
-
-    TURTL_ONION_HOSTNAME=$(add_onion_service turtl 80 ${TURTL_ONION_PORT})
-
-    turtl_setup
-}
-
-function install_turtl_nginx {
     turtl_nginx_site=/etc/nginx/sites-available/$TURTL_DOMAIN_NAME
-    if [[ $ONION_ONLY == "no" ]]; then
-        function_check nginx_http_redirect
-        nginx_http_redirect $TURTL_DOMAIN_NAME
+    if [[ "$ONION_ONLY" == "no" ]]; then
+        nginx_http_redirect "$TURTL_DOMAIN_NAME" "index index.html"
         { echo 'server {';
           echo '  listen 443 ssl;';
           echo '  #listen [::]:443 ssl;';
-          echo "  server_name ${TURTL_DOMAIN_NAME};";
-          echo '';
-          echo '  # Security'; } >> "$turtl_nginx_site"
-        function_check nginx_ssl
-        nginx_ssl $TURTL_DOMAIN_NAME
+          echo "  server_name $TURTL_DOMAIN_NAME;";
+          echo ''; } >> "$turtl_nginx_site"
+        nginx_compress "$TURTL_DOMAIN_NAME"
+        echo '' >> "$turtl_nginx_site"
+        echo '  # Security' >> "$turtl_nginx_site"
+        nginx_ssl "$TURTL_DOMAIN_NAME"
 
-        function_check nginx_security_options
-        nginx_security_options $TURTL_DOMAIN_NAME
+        nginx_security_options "$TURTL_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 '    access_log /dev/null;';
+          echo '    error_log /dev/null;';
+          echo '';
+          echo "    root /var/www/$TURTL_DOMAIN_NAME/htdocs;";
           echo '';
+          echo '  index index.html;';
+          echo '  # Location';
           echo '  location / {'; } >> "$turtl_nginx_site"
-        function_check nginx_limits
-        nginx_limits $TURTL_DOMAIN_NAME '15m'
-        { echo "    proxy_pass        http://localhost:${TURTL_PORT}/;";
-          echo "    proxy_set_header  Host \$host;";
-          echo '    proxy_buffering   off;';
+        nginx_limits "$TURTL_DOMAIN_NAME" '15m'
+        { echo "    proxy_pass http://localhost:$TURTL_PORT_INTERNAL;";
+          echo '  }';
+          echo '';
+          echo '  location ^~ /web {';
           echo '  }';
           echo '}'; } >> "$turtl_nginx_site"
     else
-        echo -n '' > $turtl_nginx_site
+        echo -n '' > "$turtl_nginx_site"
     fi
     { echo 'server {';
-      echo "  listen 127.0.0.1:${TURTL_ONION_PORT};";
-      echo '  port_in_redirect off;';
-      echo "  server_name ${TURTL_ONION_HOSTNAME};";
-      echo ''; } >> $turtl_nginx_site
-    function_check nginx_security_options
-    nginx_security_options $TURTL_DOMAIN_NAME
+      echo "    listen 127.0.0.1:$TURTL_ONION_PORT default_server;";
+      echo "    server_name $TURTL_ONION_HOSTNAME;";
+      echo ''; } >> "$turtl_nginx_site"
+    nginx_compress "$TURTL_DOMAIN_NAME"
+    echo '' >> "$turtl_nginx_site"
+    nginx_security_options "$TURTL_DOMAIN_NAME"
     { echo '';
-      echo '  # Logs';
-      echo '  access_log /dev/null;';
-      echo '  error_log /dev/null;';
+      echo '    access_log /dev/null;';
+      echo '    error_log /dev/null;';
+      echo '';
+      echo "    root /var/www/$TURTL_DOMAIN_NAME/htdocs;";
+      echo '';
+      echo '  index index.html;';
+      echo '  # Location';
+      echo '  location / {'; } >> "$turtl_nginx_site"
+    nginx_limits "$TURTL_DOMAIN_NAME" '15m'
+    { echo "    proxy_pass http://localhost:$TURTL_PORT_INTERNAL;";
+      echo '  }';
       echo '';
-      echo '  location / {'; } >> $turtl_nginx_site
-    function_check nginx_limits
-    nginx_limits $TURTL_DOMAIN_NAME '15m'
-    { echo "    proxy_pass        http://localhost:${TURTL_PORT}/;";
-      echo "    proxy_set_header  Host \$host;";
-      echo '    proxy_buffering   off;';
+      echo '  location ^~ /web {';
       echo '  }';
-      echo '}'; } >> $turtl_nginx_site
+      echo '}'; } >> "$turtl_nginx_site"
 
-    function_check add_ddns_domain
-    add_ddns_domain $TURTL_DOMAIN_NAME
+    adduser --system --home="/etc/turtl" --group turtl
 
-    set_completion_param "turtl domain" "$TURTL_DOMAIN_NAME"
+    { echo '[Unit]';
+      echo 'Description=turtl';
+      echo 'After=syslog.target';
+      echo 'After=network.target';
+      echo "Documentation=$TURTL_REPO";
+      echo '';
+      echo '[Service]';
+      echo 'Type=simple';
+      echo 'User=turtl';
+      echo 'Group=turtl';
+      echo 'WorkingDirectory=/etc/turtl';
+      echo 'ExecStart=/usr/local/bin/npm server.js';
+      echo 'Environment=USER=turtl';
+      echo 'Restart=always';
+      echo 'StandardError=syslog';
+      echo '';
+      echo '[Install]';
+      echo 'WantedBy=multi-user.target'; } > "/etc/systemd/system/turtl.service"
+    systemctl enable turtl
+    chown -R turtl:turtl "/etc/turtl"
+    systemctl start turtl
 
-    function_check create_site_certificate
-    create_site_certificate $TURTL_DOMAIN_NAME 'yes'
+    create_site_certificate "$TURTL_DOMAIN_NAME" 'yes'
 
-    function_check nginx_ensite
-    nginx_ensite $TURTL_DOMAIN_NAME
+    nginx_ensite "$TURTL_DOMAIN_NAME"
 
     systemctl restart nginx
-}
 
-function install_turtl {
-    install_turtl_api
-    install_turtl_nginx
+    "${PROJECT_NAME}-pass" -u "$MY_USERNAME" -a turtl -p "$TURTL_ADMIN_PASSWORD"
+    set_completion_param "turtl domain" "$TURTL_DOMAIN_NAME"
 
     APP_INSTALLED=1
 }
+
+# NOTE: deliberately there is no "exit 0"
diff --git a/src/freedombone-template b/src/freedombone-template
index aa450ca96..920b96be5 100755
--- a/src/freedombone-template
+++ b/src/freedombone-template
@@ -375,7 +375,7 @@ if [[ "$database_type" == "mariadb" || "$database_type" == "mysql" || "$database
     fi
     if [[ "$database_type" == "postgres"* ]]; then
         echo '    systemctl restart postgresql'
-        echo "    run_system_query_postgresql \"CREATE USER peertube WITH PASSWORD '\$${app_name_upper}_ADMIN_PASSWORD';\""
+        echo "    run_system_query_postgresql \"CREATE USER ${app_name} WITH PASSWORD '\$${app_name_upper}_ADMIN_PASSWORD';\""
         echo "    run_system_query_postgresql \"CREATE DATABASE ${app_name} OWNER ${app_name};\""
         echo "    run_system_query_postgresql \"GRANT ALL PRIVILEGES ON DATABASE ${app_name} to ${app_name};\""
         echo "    run_system_query_postgresql \"set statement_timeout to 40000;\""
diff --git a/src/turtl_old b/src/turtl_old
new file mode 100755
index 000000000..6af653323
--- /dev/null
+++ b/src/turtl_old
@@ -0,0 +1,682 @@
+#!/bin/bash
+#  _____               _           _
+# |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
+# |   __|  _| -_| -_| . | . |     | . | . |   | -_|
+# |__|  |_| |___|___|___|___|_|_|_|___|___|_|_|___|
+#
+#                              Freedom in the Cloud
+#
+# turtl app
+#
+# http://portallinux.es/instalacion-servidor-turtl-debian-8
+# http://framacloud.org/cultiver-son-jardin/installation-de-turtl/
+#
+# License
+# =======
+#
+# Copyright (C) 2016-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 writer"
+
+IN_DEFAULT_INSTALL=0
+SHOW_ON_ABOUT=1
+NOT_ON_ARM=1
+
+TURTL_DOMAIN_NAME=
+TURTL_CODE=
+TURTL_ONION_PORT=8107
+TURTL_PORT=8181
+TURTL_REPO="https://github.com/turtl/api.git"
+TURTL_COMMIT='53e00a5583f52de8f86ef380fe11c176b5738dcf'
+TURTL_ADMIN_PASSWORD=
+TURTL_STORAGE_LIMIT_MB=100
+TURTL_BASE_DIR=/etc/turtl
+
+# part of a hack to enable/disable signups
+TURTL_SIGNUP_STRING='Signup a new user'
+turtl_users_file=$TURTL_BASE_DIR/api/controllers/users.lisp
+
+TURTL_SHORT_DESCRIPTION=$'Note taking'
+TURTL_DESCRIPTION=$'Note taking'
+TURTL_MOBILE_APP_URL=https://turtlapp.com/releases/mobile/turtl-android-0.6.4.apk
+
+turtl_variables=(ONION_ONLY
+                 DEFAULT_DOMAIN_NAME
+                 TURTL_DOMAIN_NAME
+                 TURTL_CODE
+                 TURTL_STORAGE_LIMIT_MB
+                 DDNS_PROVIDER
+                 MY_EMAIL_ADDRESS
+                 MY_USERNAME)
+
+function logging_on_turtl {
+    echo -n ''
+}
+
+function logging_off_turtl {
+    echo -n ''
+}
+
+function change_password_turtl {
+    echo -n ''
+#    change_username="$1"
+#    new_user_password="$2"
+}
+
+function remove_user_turtl {
+    echo -n ''
+#    remove_username="$1"
+}
+
+function add_user_turtl {
+#    new_username="$1"
+#    new_user_password="$2"
+    echo '0'
+}
+
+function install_interactive_turtl {
+    if [ ! "$ONION_ONLY" ]; then
+        ONION_ONLY='no'
+    fi
+
+    if [[ $ONION_ONLY != "no" ]]; then
+        TURTL_DOMAIN_NAME='notes.local'
+        write_config_param "TURTL_DOMAIN_NAME" "$TURTL_DOMAIN_NAME"
+    else
+        function_check interactive_site_details
+        interactive_site_details "turtl" "TURTL_DOMAIN_NAME" "TURTL_CODE"
+    fi
+    APP_INSTALLED=1
+}
+
+function turtl_disable_registrations {
+    if grep -q "$TURTL_SIGNUP_STRING" $turtl_users_file; then
+        if [ -f $turtl_users_file ]; then
+            cp $turtl_users_file $TURTL_BASE_DIR/.users.lisp
+            sed -i '/(route (:post "\/users") (req res)/,/(send-json res user))))/{//!d}' $turtl_users_file
+            sed -i 's|(send-json res user))))|())|g' $turtl_users_file
+            chown -R turtl:turtl $TURTL_BASE_DIR
+            systemctl restart turtl
+        fi
+    fi
+}
+
+function turtl_enable_registrations {
+    if ! grep -q "$TURTL_SIGNUP_STRING" $turtl_users_file; then
+        if [ -f $TURTL_BASE_DIR/.users.lisp ]; then
+            cp $TURTL_BASE_DIR/.users.lisp $turtl_users_file
+            rm $TURTL_BASE_DIR/.users.lisp
+            chown -R turtl:turtl $TURTL_BASE_DIR
+            systemctl restart turtl
+        fi
+    fi
+}
+
+function configure_interactive_turtl_signups {
+    # This implements a hack which removes or adds the function needed
+    # to sign up new users. It should eventually be removed once that
+    # capability exists within the api
+
+    dialog --title $"Allow new turtl signups" \
+           --backtitle $"Freedombone Control Panel" \
+           --defaultno \
+           --yesno $"\\nAllow registration of new users?" 10 60
+    sel=$?
+    case $sel in
+        0)
+            turtl_enable_registrations
+            dialog --title $"Allow new turtl signups" \
+                   --msgbox $"New turtl user registrations are now allowed" 6 60
+            return;;
+        1)
+            turtl_disable_registrations
+            dialog --title $"Disable new turtl signups" \
+                   --msgbox $"New turtl user registrations are now disabled" 6 60
+            return;;
+        255) return;;
+    esac
+}
+
+function configure_interactive_turtl_storage {
+    data=$(mktemp 2>/dev/null)
+    dialog --title $"Change storage limit" \
+           --backtitle $"Freedombone Control Panel" \
+           --inputbox $"Enter a storage limit in megabytes." 8 75 "$TURTL_STORAGE_LIMIT_MB" 2>"$data"
+    sel=$?
+    case $sel in
+        0)
+            STORAGE=$(<"$data")
+            if [ ${#STORAGE} -gt 0 ]; then
+                TURTL_STORAGE_LIMIT_MB=$STORAGE
+                sed -i "s|defparameter *default-storage-limit*.*|defparameter *default-storage-limit* ${TURTL_STORAGE_LIMIT_MB})|g" $TURTL_BASE_DIR/api/config/config.lisp
+                systemctl restart turtl
+                dialog --title $"Change storage limit" \
+                       --msgbox $"Storage limit changed to ${TURTL_STORAGE_LIMIT_MB}M" 6 50
+            fi
+            ;;
+    esac
+    rm -f "$data"
+}
+
+function configure_interactive_turtl {
+    data=$(mktemp 2>/dev/null)
+    dialog --backtitle $"Freedombone Control Panel" \
+           --title $"turtl app settings" \
+           --radiolist $"Choose an operation:" 12 70 3 \
+           1 $"Enable/disable new user registrations" off \
+           2 $"Change storage limit" off \
+           3 $"Exit" on 2> "$data"
+    sel=$?
+    case $sel in
+        1) rm -f "$data"
+           exit 1;;
+        255) rm -f "$data"
+             exit 1;;
+    esac
+    case $(cat "$data") in
+        1) configure_interactive_turtl_signups;;
+        2) configure_interactive_turtl_storage;;
+        3) rm -f "$data"
+           return;;
+    esac
+    rm -f "$data"
+}
+
+function reconfigure_turtl {
+    if [ -d $TURTL_BASE_DIR/data ]; then
+        rm -rf $TURTL_BASE_DIR/data/*
+    fi
+}
+
+function upgrade_turtl {
+    CURR_TURTL_COMMIT=$(get_completion_param "turtl commit")
+    if [[ "$CURR_TURTL_COMMIT" == "$TURTL_COMMIT" ]]; then
+        return
+    fi
+
+    read_config_param "TURTL_DOMAIN_NAME"
+
+    function_check set_repo_commit
+    set_repo_commit $TURTL_BASE_DIR/api "turtl commit" "$TURTL_COMMIT" $TURTL_REPO
+
+    # this is used as a crude way of disabling signups and so
+    # should be superceded in future
+    if [ -f $TURTL_BASE_DIR/.users.lisp ]; then
+        turtl_disable_registrations
+    fi
+    systemctl restart turtl
+
+    nginx_dissite $TURTL_DOMAIN_NAME
+    chown -R turtl:turtl $TURTL_BASE_DIR
+    nginx_ensite $TURTL_DOMAIN_NAME
+}
+
+function backup_local_turtl {
+    read_config_param "TURTL_DOMAIN_NAME"
+    source_directory=$TURTL_BASE_DIR
+    if [ -d $source_directory ]; then
+        dest_directory=turtl
+        function_check suspend_site
+        suspend_site ${TURTL_DOMAIN_NAME}
+
+        function_check backup_directory_to_usb
+        backup_directory_to_usb $source_directory $dest_directory
+
+        function_check restart_site
+        restart_site
+    fi
+    source_directory=/var/lib/rethinkdb
+    if [ -d $source_directory ]; then
+        dest_directory=rethinkdb
+        function_check suspend_site
+        suspend_site ${TURTL_DOMAIN_NAME}
+
+        function_check backup_directory_to_usb
+        backup_directory_to_usb $source_directory $dest_directory
+
+        function_check restart_site
+        restart_site
+    fi
+}
+
+function restore_local_turtl {
+    read_config_param "TURTL_DOMAIN_NAME"
+    if [ $TURTL_DOMAIN_NAME ]; then
+        temp_restore_dir=/root/tempturtl
+        restore_directory_from_usb $temp_restore_dir turtl
+
+        if [ -d ${temp_restore_dir}/etc/turtl ]; then
+            cp -r ${temp_restore_dir}/etc/turtl/* /etc/turtl/
+        else
+            cp -r ${temp_restore_dir}/* /etc/turtl/
+        fi
+        # shellcheck disable=SC2181
+        if [ ! "$?" = "0" ]; then
+            set_user_permissions
+            backup_unmount_drive
+            exit 36723
+        fi
+        rm -rf ${temp_restore_dir}
+        chown -R turtl:turtl $TURTL_BASE_DIR
+
+        temp_restore_dir=/root/temprethinkdb
+        restore_directory_from_usb $temp_restore_dir rethinkdb
+
+        if [ -d ${temp_restore_dir}/var/lib/rethinkdb ]; then
+            cp -r ${temp_restore_dir}/var/lib/rethinkdb/* /var/lib/rethinkdb/
+        else
+            cp -r ${temp_restore_dir}/* /var/lib/rethinkdb/
+        fi
+
+        # shellcheck disable=SC2181
+        if [ ! "$?" = "0" ]; then
+            set_user_permissions
+            backup_unmount_drive
+            exit 378324
+        fi
+        rm -rf ${temp_restore_dir}
+    fi
+}
+
+function backup_remote_turtl {
+    echo -n ''
+}
+
+function restore_remote_turtl {
+    echo -n ''
+}
+
+function remove_turtl {
+    if [ ! -d $TURTL_BASE_DIR ]; then
+        return
+    fi
+    systemctl stop turtl
+    systemctl disable turtl
+    rm /etc/systemd/system/turtl.service
+    systemctl daemon-reload
+
+    remove_rethinkdb
+    remove_app turtl
+    remove_completion_param install_turtl
+    sed -i '/turtl/d' "$COMPLETION_FILE"
+    nginx_dissite $TURTL_DOMAIN_NAME
+    if [ -f /etc/nginx/sites-available/$TURTL_DOMAIN_NAME ]; then
+        rm /etc/nginx/sites-available/$TURTL_DOMAIN_NAME
+    fi
+    remove_certs $TURTL_DOMAIN_NAME
+    function_check remove_onion_service
+    remove_onion_service turtl ${TURTL_ONION_PORT}
+    function_check remove_ddns_domain
+    remove_ddns_domain $TURTL_DOMAIN_NAME
+    rm -rf /etc/rethinkdb
+    rm -rf /var/lib/rethinkdb
+    rm -rf $TURTL_BASE_DIR
+
+    groupdel -f turtl
+    userdel -r turtl
+}
+
+
+function turtl_setup {
+    PIDFILE=${PIDFILE:-nil}
+    BINDADDR=${BINDADDR:-0.0.0.0}
+    BINDPORT=${BINDPORT:-8181}
+    PROD_ERR_HANDLING=${PROD_ERR_HANDLING:-t}
+    if [[ $ONION_ONLY == 'no' ]]; then
+        FQDN=${FQDN:-$TURTL_DOMAIN_NAME}
+        SITE_URL=${SITE_URL:-https://$TURTL_DOMAIN_NAME}
+    else
+        FQDN=${FQDN:-$TURTL_ONION_HOSTNAME}
+        SITE_URL=${SITE_URL:-http://$TURTL_ONION_HOSTNAME}
+    fi
+    ADMIN_EMAIL=${ADMIN_EMAIL:-$MY_EMAIL_ADDRESS}
+    EMAIL_FROM=${EMAIL_FROM:-noreply@$DEFAULT_DOMAIN_NAME}
+    SMTP_USER=${SMTP_USER:-}
+    SMTP_PASS=${SMTP_PASS:-}
+    DISPLAY_ERRORS=${DISPLAY_ERRORS:-t}
+    DEFAULT_STORAGE_LIMIT=${DEFAULT_STORAGE_LIMIT:-100}
+    STORAGE_INVITE_CREDIT=${STORAGE_INVITE_CREDIT:-25}
+    if [[ $ONION_ONLY == 'no' ]]; then
+        LOCAL_UPLOAD_URL=${LOCAL_UPLOAD_URL:-https://$TURTL_DOMAIN_NAME}
+    else
+        LOCAL_UPLOAD_URL=${LOCAL_UPLOAD_URL:-http://$TURTL_ONION_HOSTNAME}
+    fi
+    LOCAL_UPLOAD_PATH=${LOCAL_UPLOAD_PATH:-"$TURTL_BASE_DIR/data"}
+    AWS_S3_TOKEN=${AWS_S3_TOKEN:-(:token ''
+                                  :secret ''
+                                  :bucket ''
+                                  :endpoint 'https://s3.amazonaws.com')}
+
+    # generates the config-file
+    cat  << __ENDCONFIG__ > $TURTL_BASE_DIR/api/config/config.lisp
+(in-package :turtl)
+(defparameter *root* (asdf:system-relative-pathname :turtl #P""))
+(defparameter *pid-file* "${PIDFILE}")
+(defvar *server-bind* "${BINDADDR}")
+(defvar *server-port* ${BINDPORT})
+(defvar *db-name* "turtl")
+(defvar *db-host* "127.0.0.1")
+(defvar *db-port* 28015)
+(defvar *production-error-handling* ${PROD_ERR_HANDLING})
+(defvar *enable-hsts-header* nil)
+(defvar *site-url* "${SITE_URL}")
+(defvar *api-path* "")
+(defvar *admin-email* "${ADMIN_EMAIL}")
+(defvar *email-from* "${EMAIL_FROM}")
+(defvar *email-user* "${SMTP_USER}")
+(defvar *email-pass* "${SMTP_PASS}")
+(defvar *display-errors* ${DISPLAY_ERRORS})
+(defparameter *default-storage-limit* ${DEFAULT_STORAGE_LIMIT})
+(defparameter *storage-invite-credit* ${STORAGE_INVITE_CREDIT})
+(vom:config :turtl :info)
+(defvar *local-upload* "${LOCAL_UPLOAD_PATH}")
+(defvar *local-upload-url* "${LOCAL_UPLOAD_URL}")
+(defvar *amazon-s3* "${AWS_S3_TOKEN}")
+__ENDCONFIG__
+
+    cat $TURTL_BASE_DIR/api/config/config.footer >> $TURTL_BASE_DIR/api/config/config.lisp
+
+    # start the turtl server
+    systemctl restart rethinkdb
+
+    if [ ! -f $TURTL_BASE_DIR/quicklisp/setup.lisp ]; then
+        echo $"$TURTL_BASE_DIR/quicklisp/setup.lisp was not found"
+        exit 6238234
+    fi
+
+    { echo '[Unit]';
+      echo 'Description=Note taking service';
+      echo 'Documentation=http://turtl.it';
+      echo 'Requires=network.target';
+      echo 'Requires=rethinkdb.service';
+      echo 'After=network.target';
+      echo 'After=rethinkdb.service';
+      echo '';
+      echo '[Service]';
+      echo 'Type=simple';
+      echo 'User=turtl';
+      echo "WorkingDirectory=$TURTL_BASE_DIR/api/"; } > /etc/systemd/system/turtl.service
+
+    if [[ "$check_architecture" == *"64"* && "$check_architecture" != *"arm"* ]]; then
+        echo "ExecStart=$TURTL_BASE_DIR/ccl/lx86cl64 -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
+    else
+        if [[ "$check_architecture" != *"arm"* ]]; then
+            echo "ExecStart=$TURTL_BASE_DIR/ccl/lx86cl -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
+        else
+            echo "ExecStart=$TURTL_BASE_DIR/ccl/armcl -l $TURTL_BASE_DIR/quicklisp/setup.lisp -l launch.lisp" >> /etc/systemd/system/turtl.service
+        fi
+    fi
+    { echo '';
+      echo '[Install]';
+      echo 'WantedBy=multi-user.target'; } >> /etc/systemd/system/turtl.service
+    chmod +x /etc/systemd/system/turtl.service
+
+    chown -R turtl:turtl $TURTL_BASE_DIR
+    systemctl enable turtl
+    systemctl daemon-reload
+    systemctl start turtl
+}
+
+function install_turtl_api {
+    # https://github.com/ArthurGarnier/turtl-docker
+    $INSTALL_PACKAGES wget libterm-readline-perl-perl gcc libuv1-dev
+
+    if [ ! -d $TURTL_BASE_DIR ]; then
+        mkdir -p $TURTL_BASE_DIR
+    fi
+    cd "$TURTL_BASE_DIR" || exit 745726542
+    mkdir cd $TURTL_BASE_DIR/data
+    check_architecture=$(uname -a)
+
+    # Install ccl
+    if [[ "$check_architecture" != *"arm"* ]]; then
+        wget -P $TURTL_BASE_DIR/ ftp://ftp.clozure.com/pub/release/1.11/ccl-1.11-linuxx86.tar.gz
+        mkdir -p $TURTL_BASE_DIR/ccl
+        tar xvzf $TURTL_BASE_DIR/ccl-1.11-linuxx86.tar.gz -C $TURTL_BASE_DIR/ccl --strip-components=1
+    else
+        wget -P $TURTL_BASE_DIR/ ftp://ftp.clozure.com/pub/release/1.11/ccl-1.11-linuxarm.tar.gz
+        mkdir -p $TURTL_BASE_DIR/ccl
+        tar xvzf $TURTL_BASE_DIR/ccl-1.11-linuxarm.tar.gz -C $TURTL_BASE_DIR/ccl --strip-components=1
+    fi
+
+    # install quicklisp
+    cat  << __ENDCONFIG__ > $TURTL_BASE_DIR/quicklisp_install
+(load (compile-file "asdf.lisp"))
+(load (compile-file "quicklisp.lisp"))
+(quicklisp-quickstart:install)
+(ql:system-apropos "vecto")
+(ql:quickload "alexandria")
+(ql:quickload "babel")
+(ql:quickload "blackbird")
+(ql:quickload "bordeaux-threads")
+(ql:quickload "cffi")
+(ql:quickload "chipz")
+(ql:quickload "chunga")
+(ql:quickload "cl-annot")
+(ql:quickload "cl-async")
+(ql:quickload "cl-async-future")
+(ql:quickload "cl-base64")
+(ql:quickload "cl-fad")
+(ql:quickload "cl-libuv")
+(ql:quickload "cl-mongo-id")
+(ql:quickload "cl-ppcre")
+(ql:quickload "cl-rethinkdb")
+(ql:quickload "cl-smtp")
+(ql:quickload "cl+ssl")
+(ql:quickload "cl-syntax")
+(ql:quickload "cl-utilities")
+(ql:quickload "cl-vectors")
+(ql:quickload "do-urlencode")
+(ql:quickload "drakma")
+(ql:quickload "drakma-async")
+(ql:quickload "event-glue")
+(ql:quickload "fast-http")
+(ql:quickload "fast-io")
+(ql:quickload "flexi-streams")
+(ql:quickload "ironclad")
+(ql:quickload "jonathan")
+(ql:quickload "local-time")
+(ql:quickload "md5")
+(ql:quickload "named-readtables")
+(ql:quickload "nibbles")
+(ql:quickload "proc-parse")
+(ql:quickload "puri")
+(ql:quickload "quri")
+(ql:quickload "salza2")
+(ql:quickload "secure-random")
+(ql:quickload "smart-buffer")
+(ql:quickload "split-sequence")
+(ql:quickload "static-vectors")
+(ql:quickload "trivial-backtrace")
+(ql:quickload "trivial-features")
+(ql:quickload "trivial-garbage")
+(ql:quickload "trivial-gray-streams")
+(ql:quickload "trivial-types")
+(ql:quickload "usocket")
+(ql:quickload "vecto")
+(ql:quickload "vom")
+(ql:quickload "wookie")
+(ql:quickload "xmls")
+(ql:quickload "xsubseq")
+(ql:quickload "yason")
+(ql:quickload "zpb-ttf")
+(ql:quickload "zpng")
+(ql:add-to-init-file)
+(ccl::quit)
+__ENDCONFIG__
+
+    if [ ! -f asdf.lisp ]; then
+        wget https://common-lisp.net/project/asdf/asdf.lisp
+    fi
+    if [ ! -f quicklisp.lisp ]; then
+        wget https://beta.quicklisp.org/quicklisp.lisp
+    fi
+
+    if [ -d $TURTL_BASE_DIR ]; then
+        chown -R turtl:turtl $TURTL_BASE_DIR
+    fi
+    adduser --disabled-login --home=$TURTL_BASE_DIR --gecos 'turtl' turtl
+    if [ ! -d $TURTL_BASE_DIR ]; then
+        echo $"$TURTL_BASE_DIR directory not created"
+        exit 263493
+    fi
+
+    groupadd turtl
+    chown -R turtl:turtl $TURTL_BASE_DIR
+
+    if [[ "$check_architecture" != *"arm"* ]]; then
+        if [[ "$check_architecture" == *"64"* ]]; then
+            su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/lx86cl64" - turtl
+        else
+            su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/lx86cl" - turtl
+        fi
+    else
+        su -c "cat $TURTL_BASE_DIR/quicklisp_install | $TURTL_BASE_DIR/ccl/larmcl" - turtl
+    fi
+    rm $TURTL_BASE_DIR/quicklisp_install
+
+    install_rethinkdb
+    echo "http-port=8091" > /etc/rethinkdb/instances.d/turtl.conf
+    chown -R rethinkdb:rethinkdb /var/lib/rethinkdb
+
+    # install turtl API
+    cd "$TURTL_BASE_DIR/" || exit 6428462
+
+    if [ -d /repos/turtl ]; then
+        mkdir -p $TURTL_BASE_DIR/api
+        cp -r -p /repos/turtl/. $TURTL_BASE_DIR/api
+        cd "$TURTL_BASE_DIR/api" || exit 57141845
+        git pull
+    else
+        git clone $TURTL_REPO $TURTL_BASE_DIR/api
+    fi
+
+    cd "$TURTL_BASE_DIR/api" || exit 35814614
+    git checkout $TURTL_COMMIT -b $TURTL_COMMIT
+    set_completion_param "turtl commit" "$TURTL_COMMIT"
+    cd "$TURTL_BASE_DIR/quicklisp/local-projects" || exit 43618941415
+    git clone git://github.com/orthecreedence/cl-hash-util
+    if [[ "$check_architecture" != *"arm"* ]]; then
+        if [[ "$check_architecture" == *"64"* ]]; then
+            su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/lx86cl64 -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
+        else
+            su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/lx86cl -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
+        fi
+    else
+        su -c "cat '(ccl:quit)' | $TURTL_BASE_DIR/ccl/larmcl -l $TURTL_BASE_DIR/quicklisp/setup.lisp" - turtl
+    fi
+
+    # config
+    { echo '(defvar *enabled-cors-resources* "resource://turtl-at-lyonbros-dot-com"';
+      echo '  "When set, will enable CORS for resource:// origins if they match the given';
+      echo '   string. Entries should be comma separated (this string is passed verbatim in';
+      echo '   the Access-Control-Allow-Origin header).")';
+      echo '(defparameter *public-actions*';
+      echo "  \`((:post . ,(concatenate 'string *api-path* \"/users\"))";
+      echo "    (:post . ,(concatenate 'string *api-path* \"/log/error\"))";
+      echo '    (:post . "/cla/sign")';
+      echo '    (:get  . "/ping")';
+      echo '    (:get  . "/admin")';
+      echo "    (:get . ,(cl-ppcre:create-scanner (concatenate 'string *api-path* \"/invites/codes/([0-9a-f-]+)\"))))";
+      echo "  \"A list of public resources/actions that do not require authentication.\")";
+      echo "(defvar *analytics* '(:enabled t";
+      echo '                      :db "analytics"))'; } > "$TURTL_BASE_DIR/api/config/config.footer"
+
+    cp $TURTL_BASE_DIR/asdf.lisp $TURTL_BASE_DIR/api
+    echo '(load (compile-file "asdf.lisp"))' > $TURTL_BASE_DIR/api/launch.lisp
+    echo "(pushnew \"./\" asdf:*central-registry* :test #'equal)" >> $TURTL_BASE_DIR/api/launch.lisp
+    echo '(load "start")' >> $TURTL_BASE_DIR/api/launch.lisp
+
+    TURTL_ONION_HOSTNAME=$(add_onion_service turtl 80 ${TURTL_ONION_PORT})
+
+    turtl_setup
+}
+
+function install_turtl_nginx {
+    turtl_nginx_site=/etc/nginx/sites-available/$TURTL_DOMAIN_NAME
+    if [[ $ONION_ONLY == "no" ]]; then
+        function_check nginx_http_redirect
+        nginx_http_redirect $TURTL_DOMAIN_NAME
+        { echo 'server {';
+          echo '  listen 443 ssl;';
+          echo '  #listen [::]:443 ssl;';
+          echo "  server_name ${TURTL_DOMAIN_NAME};";
+          echo '';
+          echo '  # Security'; } >> "$turtl_nginx_site"
+        function_check nginx_ssl
+        nginx_ssl $TURTL_DOMAIN_NAME
+
+        function_check nginx_security_options
+        nginx_security_options $TURTL_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 '  location / {'; } >> "$turtl_nginx_site"
+        function_check nginx_limits
+        nginx_limits $TURTL_DOMAIN_NAME '15m'
+        { echo "    proxy_pass        http://localhost:${TURTL_PORT}/;";
+          echo "    proxy_set_header  Host \$host;";
+          echo '    proxy_buffering   off;';
+          echo '  }';
+          echo '}'; } >> "$turtl_nginx_site"
+    else
+        echo -n '' > $turtl_nginx_site
+    fi
+    { echo 'server {';
+      echo "  listen 127.0.0.1:${TURTL_ONION_PORT};";
+      echo '  port_in_redirect off;';
+      echo "  server_name ${TURTL_ONION_HOSTNAME};";
+      echo ''; } >> $turtl_nginx_site
+    function_check nginx_security_options
+    nginx_security_options $TURTL_DOMAIN_NAME
+    { echo '';
+      echo '  # Logs';
+      echo '  access_log /dev/null;';
+      echo '  error_log /dev/null;';
+      echo '';
+      echo '  location / {'; } >> $turtl_nginx_site
+    function_check nginx_limits
+    nginx_limits $TURTL_DOMAIN_NAME '15m'
+    { echo "    proxy_pass        http://localhost:${TURTL_PORT}/;";
+      echo "    proxy_set_header  Host \$host;";
+      echo '    proxy_buffering   off;';
+      echo '  }';
+      echo '}'; } >> $turtl_nginx_site
+
+    function_check add_ddns_domain
+    add_ddns_domain $TURTL_DOMAIN_NAME
+
+    set_completion_param "turtl domain" "$TURTL_DOMAIN_NAME"
+
+    function_check create_site_certificate
+    create_site_certificate $TURTL_DOMAIN_NAME 'yes'
+
+    function_check nginx_ensite
+    nginx_ensite $TURTL_DOMAIN_NAME
+
+    systemctl restart nginx
+}
+
+function install_turtl {
+    install_turtl_api
+    install_turtl_nginx
+
+    APP_INSTALLED=1
+}
-- 
GitLab