Skip to content
Snippets Groups Projects
freedombone-app-xmpp 70.6 KiB
Newer Older
Bob Mottram's avatar
Bob Mottram committed
#!/bin/bash
Bob Mottram's avatar
Bob Mottram committed
#  _____               _           _
# |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# |   __|  _| -_| -_| . | . |     | . | . |   | -_|
# |__|  |_| |___|___|___|___|_|_|_|___|___|_|_|___|
Bob Mottram's avatar
Bob Mottram committed
#
Bob Mottram's avatar
Bob Mottram committed
#                              Freedom in the Cloud
Bob Mottram's avatar
Bob Mottram committed
#
Bob Mottram's avatar
Bob Mottram committed
# XMPP server
#
# Try to minimize the number of daemon restarts, since that causes
# PEP to break within client apps.
Bob Mottram's avatar
Bob Mottram committed
#
Bob Mottram's avatar
Bob Mottram committed
# The two directories for prosody modules seem necessary.
# Trying to remove /usr/lib/prosody/modules causes problems, and that's
# part of the package install.
#
Bob Mottram's avatar
Bob Mottram committed
# License
# =======
#
Bob Mottram's avatar
Bob Mottram committed
# Copyright (C) 2014-2019 Bob Mottram <bob@freedombone.net>
Bob Mottram's avatar
Bob Mottram committed
#
# 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 chat'
Bob Mottram's avatar
Bob Mottram committed
APP_CATEGORY=chat

INSTALLED_ON_DEFAULT_DOMAIN=1
NOT_ON_HOMEPAGE=1
REQUIRES_APP=
# Whether to strictly enforce end-to-end security for one-to-one chat
XMPP_E2EE=no

Bob Mottram's avatar
Bob Mottram committed
# Directory where XMPP settings are stored
XMPP_DIRECTORY="/var/lib/prosody"
XMPP_PASSWORD=

XMPP_CIPHERS='"EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA"'
XMPP_ECC_CURVE='"secp384r1"'

Bob Mottram's avatar
Bob Mottram committed
prosody_latest_version='0.11'
Bob Mottram's avatar
Bob Mottram committed
prosody_nightly=30
Bob Mottram's avatar
Bob Mottram committed
prosody_nightly_directory=build11
Bob Mottram's avatar
Bob Mottram committed
prosody_nightly_hash='f3944afdd8ff3f47bcb5a870f834e4cac4d2d8f755e5da0e39c44f6f580b3440'
prosody_filename=prosody-${prosody_latest_version}-1nightly${prosody_nightly}
Bob Mottram's avatar
Bob Mottram committed
prosody_nightly_url="https://prosody.im/nightly/${prosody_latest_version}/${prosody_nightly_directory}/${prosody_filename}.tar.gz"

# From https://hg.prosody.im/prosody-modules
Bob Mottram's avatar
Bob Mottram committed
prosody_modules_filename='prosody-modules-20190127.tar.gz'
prosody_modules_hash='47aa1caea5ef411bc86620ff6c386c132d77fb255d42f5d2923d86a361b91c92'
Bob Mottram's avatar
Bob Mottram committed
xmpp_encryption_warning=$"For security reasons, OMEMO or PGP encryption is required for conversations on this server."
Bob Mottram's avatar
Bob Mottram committed
XMPP_SHORT_DESCRIPTION=$'Chat system'
XMPP_DESCRIPTION=$'Chat system'
XMPP_MOBILE_APP_URL='https://f-droid.org/packages/eu.siacs.conversations'

# commandline utility for notifications
XMPPSEND_REPO="https://code.freedombone.net/bashrc/xmppsend"
Bob Mottram's avatar
Bob Mottram committed
XMPPSEND_COMMIT='9401665f40723df779f828d01cc1fa6df28b14c9'
# used to disable TLS on onion only installs
xmpp_tls_enabled=''

Bob Mottram's avatar
Bob Mottram committed
# rate limits in kilobytes per second
XMPP_MAX_S2S_RATE=10
XMPP_MAX_C2S_RATE=10

Bob Mottram's avatar
Bob Mottram committed
xmpp_variables=(ONION_ONLY
                INSTALLED_WITHIN_DOCKER
                XMPP_CIPHERS
                XMPP_ECC_CURVE
                XMPP_ECC_CURVE
Bob Mottram's avatar
Bob Mottram committed
                MY_USERNAME
Bob Mottram's avatar
Bob Mottram committed
                MY_EMAIL_ADDRESS
                DEFAULT_DOMAIN_NAME
                XMPP_DOMAIN_CODE)
function upgrade_distro_xmpp {
    target_distro="$1"

    if [[ "$target_distro" == 'buster' ]]; then
        echo -n ''
    fi
}

function xmpp_setting_stricttls {
    # switching strict TLS on or off, which requires authentication with a letsencrypt cert
    strict_tls="$1"
    strict_tls_update=

    if [[ "$strict_tls" == '1' ]]; then
        if ! grep -q 's2s_secure_auth = true' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_secure_auth = .*|s2s_secure_auth = true|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
        if ! grep -q 's2s_require_encryption = true' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_require_encryption = .*|s2s_require_encryption = true|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
    fi

    if [[ "$strict_tls" == '0' ]]; then
        if ! grep -q 's2s_secure_auth = false' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_secure_auth = .*|s2s_secure_auth = false|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
        if ! grep -q 's2s_require_encryption = false' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_require_encryption = .*|s2s_require_encryption = false|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
    fi

    if [ $strict_tls_update ]; then
        systemctl restart prosody
    fi
}

function prosody_update_onion_certs {
    if [[ "$ONION_ONLY" == 'no' ]]; then
        return
    fi
    if [ ! -f /var/lib/prosody/xmpp.crt ]; then
        if [ -f /etc/ssl/certs/xmpp.crt ]; then
            cp /etc/ssl/certs/xmpp.crt /var/lib/prosody/xmpp.crt
            chown prosody:prosody /var/lib/prosody/xmpp.crt
            sed -i 's|/etc/ssl/certs/xmpp.crt|/var/lib/prosody/xmpp.crt|g' /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi
    if [ ! -f /var/lib/prosody/xmpp.key ]; then
        if [ -f /etc/ssl/private/xmpp.key ]; then
            cp /etc/ssl/private/xmpp.key /var/lib/prosody/xmpp.key
            chown prosody:prosody /var/lib/prosody/xmpp.key
            sed -i 's|/etc/ssl/private/xmpp.key|/var/lib/prosody/xmpp.key|g' /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi
    if ! grep -q 'dhparam = "/etc/prosody/xmpp.dhparam";' /etc/prosody/conf.d/xmpp.cfg.lua; then
        sed -i 's|dhparam = .*|dhparam = "/etc/prosody/xmpp.dhparam";|g' /etc/prosody/conf.d/xmpp.cfg.lua
        xmpp_restart=1
    fi
}

function prosody_default_security_labels {
    prosody_config_file="$1"

    if grep -q 'security_labels = {' "$prosody_config_file"; then
        return
    fi

    { echo '';
      echo 'security_labels = {';
      echo '  { -- This label will come first';
      echo '    name = "Public",';
      echo '    label = true,';
      echo '      default = true -- The default label.';
      echo '  },';
      echo '  {';
      echo '    name = "Private",';
      echo '    label = "PRIVATE",';
      echo '    color = "white",';
      echo '    bgcolor = "blue"';
      echo '  },';
      echo '  Sensitive = {';
      echo '    SECRET = {';
      echo '      label = true';
      echo '    },';
      echo '    TOPSECRET = {';
      echo '      color = "red",';
      echo '      bgcolor = "black",';
      echo '    }';
      echo '  }';
      echo '}'; } >> "$prosody_config_file"
function change_default_domain_name_xmpp {
    new_default_domain_name="$1"

    read_config_param DEFAULT_DOMAIN_NAME
    sed -i "s|$DEFAULT_DOMAIN_NAME|$new_default_domain_name|g" /etc/prosody/prosody.cfg.lua
    sed -i "s|$DEFAULT_DOMAIN_NAME|$new_default_domain_name|g" /etc/prosody/conf.avail/xmpp.cfg.lua

    systemctl restart prosody
}

Bob Mottram's avatar
Bob Mottram committed
function prosody_remove_module_from_config {
    remove_prosody_module_name="$1"
    prosody_config_file="$2"

    if [ ! "${remove_prosody_module_name}" ]; then
        return
    fi

    if [ ! -f "${prosody_config_file}" ]; then
        echo "Config file ${prosody_config_file} not found when removing module $remove_prosody_module_name"
        return
    fi

    if grep -q "\"${remove_prosody_module_name}\"" "${prosody_config_file}"; then
        sed -i "/\"${remove_prosody_module_name}\"/d" "${prosody_config_file}"
        xmpp_restart=1
    fi
}

function prosody_remove_module {
    remove_prosody_module_name="$1"
    prosody_remove_module_from_config "${remove_prosody_module_name}" /etc/prosody/prosody.cfg.lua
    prosody_remove_module_from_config "${remove_prosody_module_name}" /etc/prosody/conf.avail/xmpp.cfg.lua
}

function prosody_add_module_to_config {
    new_prosody_module_name="$1"
    prosody_config_file="$2"
    add_to_muc="$3"

    if [ ! "${new_prosody_module_name}" ]; then
        return
    fi

    if [ ! -f "${prosody_config_file}" ]; then
        echo "Config file ${prosody_config_file} not found when adding module $new_prosody_module_name"
        return
    fi

    if ! grep -q "\"${new_prosody_module_name}\"" "$prosody_config_file"; then
        sed -i "/\"pep\"/a \"${new_prosody_module_name}\";" "$prosody_config_file"

        if [ "$add_to_muc" ]; then
            if grep -q "\"muc_limits\"" "$prosody_config_file"; then
                sed -i "/\"muc_limits\"/a \"${new_prosody_module_name}\";" "$prosody_config_file"
            fi
        fi

        sed -i "s|\"${new_prosody_module_name}\"|        \"${new_prosody_module_name}\"|g" "$prosody_config_file"
        xmpp_restart=1
    fi
}

function prosody_add_module {
    new_prosody_module_name="$1"
    add_to_muc="$2"
    prosody_add_module_to_config "${new_prosody_module_name}" /etc/prosody/prosody.cfg.lua "$add_to_muc"
    prosody_add_module_to_config "${new_prosody_module_name}" /etc/prosody/conf.avail/xmpp.cfg.lua "$add_to_muc"
}

function xmpp_fix_exists {
    if ! grep -q "CREATE INDEX IF NOT EXISTS" plugins/mod_storage_sql1.lua; then
        sed -i 's|CREATE INDEX|CREATE INDEX IF NOT EXISTS|g' plugins/mod_storage_sql1.lua
    fi
    if ! grep -q "CREATE INDEX IF NOT EXISTS" util/sql.lua; then
        sed -i 's|CREATE INDEX|CREATE INDEX IF NOT EXISTS|g' util/sql.lua
    fi
    if ! grep -q "CREATE TABLE IF NOT EXISTS" plugins/mod_storage_sql1.lua; then
        sed -i 's|CREATE TABLE|CREATE TABLE IF NOT EXISTS|g' plugins/mod_storage_sql1.lua
    fi
    if ! grep -q "CREATE TABLE IF NOT EXISTS" util/sql.lua; then
        sed -i 's|CREATE TABLE|CREATE TABLE IF NOT EXISTS|g' util/sql.lua
    fi
}

Bob Mottram's avatar
Bob Mottram committed
function xmpp_update_e2e_policy {
    filename="$1"

    read_config_param DEFAULT_DOMAIN_NAME
    read_config_param ONION_ONLY

    if ! grep -q "e2e_policy_muc" "$filename"; then
        echo "e2e_policy_muc = \"none\"" >> "$filename"
Bob Mottram's avatar
Bob Mottram committed
    else
Bob Mottram's avatar
Bob Mottram committed
        if ! grep -q 'e2e_policy_muc = "none"' "$filename"; then
            sed -i 's|e2e_policy_muc.*|e2e_policy_muc = "none"|g' "$filename"
Bob Mottram's avatar
Bob Mottram committed
        fi
Bob Mottram's avatar
Bob Mottram committed
    fi
    if ! grep -q "e2e_policy_chat" "$filename"; then
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
            echo "e2e_policy_chat = \"required\"" >> "$filename"
        else
            echo "e2e_policy_chat = \"optional\"" >> "$filename"
Bob Mottram's avatar
Bob Mottram committed
    else
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
Bob Mottram's avatar
Bob Mottram committed
            if ! grep -q 'e2e_policy_chat = "required"' "$filename"; then
                sed -i 's|e2e_policy_chat.*|e2e_policy_chat = "required"|g' "$filename"
Bob Mottram's avatar
Bob Mottram committed
            fi
Bob Mottram's avatar
Bob Mottram committed
            if ! grep -q 'e2e_policy_chat = "optional"' "$filename"; then
                sed -i 's|e2e_policy_chat.*|e2e_policy_chat = "optional"|g' "$filename"
Bob Mottram's avatar
Bob Mottram committed
            fi
Bob Mottram's avatar
Bob Mottram committed
    fi
    if ! grep -q "e2e_policy_message_required_chat" "$filename"; then
Bob Mottram's avatar
Bob Mottram committed
        echo "e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"" >> "$filename"
Bob Mottram's avatar
Bob Mottram committed
    else
Bob Mottram's avatar
Bob Mottram committed
        if ! grep -q "e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"" "$filename"; then
            sed -i "s|e2e_policy_message_required_chat.*|e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"|g" "$filename"
Bob Mottram's avatar
Bob Mottram committed
        fi
Bob Mottram's avatar
Bob Mottram committed
    fi
    if ! grep -q "e2e_policy_whitelist" "$filename"; then
        echo "e2e_policy_whitelist = { \"notification@$HOSTNAME\" };" >> "$filename"
Bob Mottram's avatar
Bob Mottram committed
        if ! grep -q "e2e_policy_whitelist = { \"notification@$HOSTNAME\" };" "$filename"; then
            sed -i "s|e2e_policy_whitelist.*|e2e_policy_whitelist = { \"notification@$HOSTNAME\" };|g" "$filename"
Bob Mottram's avatar
Bob Mottram committed
        fi
Bob Mottram's avatar
Bob Mottram committed

    if [[ "$ONION_ONLY" != 'no' ]]; then
        XMPP_ONION_HOSTNAME=$(cat /var/lib/tor/hidden_service_email/hostname)
Bob Mottram's avatar
Bob Mottram committed
        sed -i "s|VirtualHost \".*.onion.*|VirtualHost \"${XMPP_ONION_HOSTNAME}\"|g" "$filename"
Bob Mottram's avatar
Bob Mottram committed
        # TLS is not strictly needed for onion transport security
Bob Mottram's avatar
Bob Mottram committed
        if ! grep -q 'c2s_require_encryption = false' "$filename"; then
            sed -i 's|c2s_require_encryption =.*|c2s_require_encryption = false|g' "$filename"
Bob Mottram's avatar
Bob Mottram committed
        fi
        if ! grep -q 's2s_require_encryption = false' "$filename"; then
            sed -i 's|s2s_require_encryption =.*|s2s_require_encryption = false|g' "$filename"
Bob Mottram's avatar
Bob Mottram committed
        fi
function logging_on_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    if [ ! -d /etc/prosody ]; then
        return
    fi

    if ! grep -q 'info = "/var/log/prosody/prosody.log";' /etc/prosody/prosody.cfg.lua; then
        if [ -d /etc/prosody ]; then
            if [ ! -d /var/log/prosody ]; then
                mkdir /var/log/prosody
                chown root:adm /var/log/prosody
            fi
            if ! grep -q "/var/log/prosody/prosody.log" /etc/prosody/prosody.cfg.lua; then
                sed -i 's|info = "/dev/null";|info = "/var/log/prosody/prosody.log";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|error = "/dev/null";|error = "/var/log/prosody/prosody.err";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|levels = { "error" }; to = "/dev/null";|levels = { "info" }; to = "syslog";|g' /etc/prosody/prosody.cfg.lua
                touch /var/log/prosody/prosody.log
                chown prosody:prosody /var/log/prosody/prosody.log
                touch /var/log/prosody/prosody.err
                chown prosody:prosody /var/log/prosody/prosody.err
            fi
Bob Mottram's avatar
Bob Mottram committed
        fi
        systemctl restart prosody
}

function logging_off_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    if [ ! -d /etc/prosody ]; then
        return
    fi

    logging_restart_prosody=

    # remove any chat log
    read_config_param DEFAULT_DOMAIN_NAME
    prosody_chat_domain="chat.${DEFAULT_DOMAIN_NAME}"
    # shellcheck disable=SC2001
Bob Mottram's avatar
Bob Mottram committed
    prosody_chat_domain_str=$(echo "$prosody_chat_domain" | sed 's|\.|%2e|g')
Bob Mottram's avatar
Bob Mottram committed
    if [ -d "${XMPP_DIRECTORY}/${prosody_chat_domain_str}/muc_log" ]; then
Bob Mottram's avatar
Bob Mottram committed
        # shellcheck disable=SC2086
Bob Mottram's avatar
Bob Mottram committed
        rm -rf ${XMPP_DIRECTORY}/${prosody_chat_domain_str}/muc_log*
        logging_restart_prosody=1
    fi

    if ! grep -q 'muc_log_by_default = false;' /etc/prosody/prosody.cfg.lua; then
        sed -i 's|muc_log_by_default.*|muc_log_by_default = false;|g' /etc/prosody/prosody.cfg.lua
        logging_restart_prosody=1
    fi

    if ! grep -q 'muc_log_all_rooms = false;' /etc/prosody/prosody.cfg.lua; then
        sed -i 's|muc_log_all_rooms.*|muc_log_all_rooms = false;|g' /etc/prosody/prosody.cfg.lua
        logging_restart_prosody=1
    fi

    if ! grep -q '/dev/null' /etc/prosody/prosody.cfg.lua; then
        if [ -d /etc/prosody ]; then
            if grep -q "/var/log/prosody/prosody.log" /etc/prosody/prosody.cfg.lua; then
                sed -i 's|info = "/var/log/prosody/prosody.log";|info = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|error = "/var/log/prosody/prosody.err";|error = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|levels = { "info" }; to = "syslog";|levels = { "error" }; to = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                $REMOVE_FILES_COMMAND /var/log/prosody/*
                rm -rf /var/log/prosody
            fi
Bob Mottram's avatar
Bob Mottram committed
        fi
        logging_restart_prosody=1
    fi

    if [ $logging_restart_prosody ]; then
        systemctl restart prosody
function xmpp_add_onion_address {
    domain_name="$1"
    onion_address="$2"
    if [ ${#domain_name} -eq 0 ]; then
        return
    fi
    if [ ${#onion_address} -eq 0 ]; then
        return
    fi
Bob Mottram's avatar
Bob Mottram committed
    if ! grep "${onion_address}" /etc/prosody/prosody.cfg.lua; then
        if grep -q "[\"${domain_name}\"]" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|[\"${domain_name}\"].*|[\"${domain_name}\"] = \"${onion_address}\";|g" /etc/prosody/prosody.cfg.lua
        else
            sed -i "/onions_map = {/a  [\"${domain_name}\"] = \"${onion_address}\";" /etc/prosody/prosody.cfg.lua
        fi
        systemctl restart prosody
    fi
}

function xmpp_add_onion_address_interactive {
Bob Mottram's avatar
Bob Mottram committed
    data=$(mktemp 2>/dev/null)
    dialog --backtitle $"Freedombone Control Panel" \
           --title $"Add a clearnet to Onion domain mapping" \
           --form $"Sepecify a clearnet domain name and its equivalent onion address\\n" 9 50 2 \
           $"Domain:" 1 1 "" 1 18 26 25 \
           $"Onion address:" 2 1 "" 2 18 26 25 \
Bob Mottram's avatar
Bob Mottram committed
           2> "$data"
    sel=$?
    case $sel in
Bob Mottram's avatar
Bob Mottram committed
        1) rm -f "$data"
           return;;
        255) rm -f "$data"
             return;;
Bob Mottram's avatar
Bob Mottram committed
    domain_name=$(sed -n 1p < "$data")
    onion_address=$(sed -n 2p < "$data")
    rm -f "$data"
    if [[ "$onion_address" != *".onion" ]]; then
        return
    fi
    if [[ "$domain_name" != *"."* ]]; then
        return
    fi

    xmpp_add_onion_address "$domain_name" "$onion_address"

    dialog --title $"Add a clearnet to Onion domain mapping" \
           --msgbox $"${domain_name} -> ${onion_address} added" 6 70
}

function xmpp_remove_onion_address {
    domain_name="$1"
    if [ ${#domain_name} -eq 0 ]; then
        return
    fi
Bob Mottram's avatar
Bob Mottram committed
    xmpp_changed=
    if grep -q "[\"${domain_name}\"]" /etc/prosody/prosody.cfg.lua; then
        sed -i "/[\"${domain_name}\"]/d" /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
        xmpp_changed=1
    fi

    if grep -q "= \"${domain_name}\";" /etc/prosody/prosody.cfg.lua; then
        sed -i "/= \"${domain_name}\";/d" /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
        xmpp_changed=1
    fi
    if [ $xmpp_changed ]; then
        systemctl restart prosody
    fi
}

function xmpp_remove_onion_address_interactive {
Bob Mottram's avatar
Bob Mottram committed
    data=$(mktemp 2>/dev/null)
    dialog --title $"Remove clearnet to Onion domain mapping" \
           --backtitle $"Freedombone Control Panel" \
Bob Mottram's avatar
Bob Mottram committed
           --inputbox $'Enter the domain name or onion address to be removed' 8 60 2>"$data"
    sel=$?
    case $sel in
Bob Mottram's avatar
Bob Mottram committed
        0) domain_name=$(<"$data")
           if [[ "$domain_name" != *"."* ]]; then
Bob Mottram's avatar
Bob Mottram committed
               rm -f "$data"
               return
           fi
           xmpp_remove_onion_address "$domain_name"
           dialog --title $"Remove a clearnet to Onion domain mapping" \
                  --msgbox $"${domain_name} removed" 6 70
           ;;
    esac
Bob Mottram's avatar
Bob Mottram committed
    rm -f "$data"
}

function configure_interactive_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    read_config_param XMPP_E2EE
        e2ee_policy=$'optional'
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
            e2ee_policy=$'required'
        fi

        W=(1 $"End-to-end security policy: $e2ee_policy"
           2 $"Add a clearnet to onion domain mapping"
           3 $"Remove a clearnet to onion domain mapping")
        # shellcheck disable=SC2068
        selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"XMPP" --menu $"Choose an operation, or ESC to exit:" 11 60 3 "${W[@]}" 3>&2 2>&1 1>&3)

        if [ ! "$selection" ]; then
            break
        fi

        case $selection in
            1) if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
                   XMPP_E2EE='no'
               else
                   XMPP_E2EE='yes'
               fi
               write_config_param 'XMPP_E2EE' "$XMPP_E2EE"
               xmpp_update_e2e_policy /etc/prosody/conf.avail/xmpp.cfg.lua
               xmpp_update_e2e_policy /etc/prosody/prosody.cfg.lua
               systemctl restart prosody

               e2ee_policy=$'optional'
               if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
                   e2ee_policy=$'required'
               fi

               dialog --title $"xmpp end-to-end security policy" \
                      --msgbox $"The security policy has been changed to $e2ee_policy" 6 70
               ;;
            2) xmpp_add_onion_address_interactive;;
            3) xmpp_remove_onion_address_interactive;;
Bob Mottram's avatar
Bob Mottram committed
function remove_user_xmpp {
    remove_username="$1"
Bob Mottram's avatar
Bob Mottram committed
    "${PROJECT_NAME}-pass" -u "$remove_username" --rmapp xmpp
    if [[ "$ONION_ONLY" != "no" ]]; then
        DOMAIN=$(cat /var/lib/tor/hidden_service_email/hostname)
Bob Mottram's avatar
Bob Mottram committed
    else
        DOMAIN=${HOSTNAME}
Bob Mottram's avatar
Bob Mottram committed
    fi
    prosodyctl deluser "${remove_username}@${DOMAIN}"
Bob Mottram's avatar
Bob Mottram committed

function add_user_xmpp_client {
    new_username="$1"
    new_user_password="$2"

    if [ -f /usr/local/bin/profanity ]; then
        XMPP_CLIENT_DIR=/home/$new_username/.local/share/profanity
        XMPP_CLIENT_ACCOUNTS=$XMPP_CLIENT_DIR/accounts
Bob Mottram's avatar
Bob Mottram committed
        if [ ! -d "$XMPP_CLIENT_DIR" ]; then
            mkdir -p "$XMPP_CLIENT_DIR"
Bob Mottram's avatar
Bob Mottram committed
        if [ ! -d "/home/$new_username/.config/profanity" ]; then
            mkdir -p "/home/$new_username/.config/profanity"
        fi
        MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$new_username" "$new_username@$HOSTNAME")
Bob Mottram's avatar
Bob Mottram committed
        { echo "[${new_username}@${HOSTNAME}]";
          echo 'enabled=true';
          echo "jid=${new_username}@${HOSTNAME}";
          echo "server=$XMPP_ONION_HOSTNAME";
          echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID";
          echo 'resource=profanity';
          echo "muc.service=conference.${HOSTNAME}";
          echo "muc.nick=${new_username}";
          echo 'presence.last=online';
          echo 'presence.login=online';
          echo 'priority.online=0';
          echo 'priority.chat=0';
          echo 'priority.away=0';
          echo 'priority.xa=0';
          echo 'priority.dnd=0'; } > "$XMPP_CLIENT_ACCOUNTS"

        echo '[connection]' > "/home/$new_username/.config/profanity/profrc"
        if [[ $ONION_ONLY != "no" ]]; then
Bob Mottram's avatar
Bob Mottram committed
            echo "account=${new_username}@${XMPP_ONION_HOSTNAME}" >> "/home/$new_username/.config/profanity/profrc"
Bob Mottram's avatar
Bob Mottram committed
            echo "account=${new_username}@${HOSTNAME}" >> "/home/$new_username/.config/profanity/profrc"
Bob Mottram's avatar
Bob Mottram committed
        { echo '';
          echo '[plugins]';
          echo 'load=prof_omemo_plugin.py;';
          echo '';
          echo '[otr]';
          echo 'policy=opportunistic';
          echo 'log=off';
          echo '';
          echo '[pgp]';
          echo 'log=off';
          echo '';
          echo '[ui]';
          echo 'enc.warn=true'; } >> "/home/$new_username/.config/profanity/profrc"

        chown -R "$new_username":"$new_username" "/home/$new_username/.local"
        chown -R "$new_username":"$new_username" "/home/$new_username/.config"
Bob Mottram's avatar
Bob Mottram committed
function add_user_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    new_username="$1"
    new_user_password="$2"

    XMPP_ONION_HOSTNAME=$(cat /var/lib/tor/hidden_service_email/hostname)
Bob Mottram's avatar
Bob Mottram committed
    "${PROJECT_NAME}-pass" -u "$new_username" -a xmpp -p "$new_user_password"
Bob Mottram's avatar
Bob Mottram committed
    if [[ "$ONION_ONLY" != "no" ]]; then
        DOMAIN_NAME=$XMPP_ONION_HOSTNAME
Bob Mottram's avatar
Bob Mottram committed
    else
        DOMAIN_NAME=$HOSTNAME
Bob Mottram's avatar
Bob Mottram committed
    fi
    EMAIL_ADDRESS="$new_username@$DOMAIN_NAME"

    if [ ${#new_user_password} -eq 0 ]; then
Bob Mottram's avatar
Bob Mottram committed
        prosodyctl adduser "$EMAIL_ADDRESS"
Bob Mottram's avatar
Bob Mottram committed
        if ! prosodyctl register "$new_username" "$DOMAIN_NAME" "$new_user_password"; then
    add_user_xmpp_client "$new_username" "$new_user_password"
Bob Mottram's avatar
Bob Mottram committed
    echo '0'
}

function install_interactive_xmpp {
    echo -n ''
function change_password_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    curr_username="$1"
    new_user_password="$2"

    read_config_param DEFAULT_DOMAIN_NAME

Bob Mottram's avatar
Bob Mottram committed
    "${PROJECT_NAME}-pass" -u "$curr_username" -a xmpp -p "$new_user_password"
Bob Mottram's avatar
Bob Mottram committed

    # TODO: this is currently interactive. Really there needs to be a
    # non-interactive password change option for prosodyctl
    clear
    echo ''
    echo $'Currently Prosody requires password changes to be done interactively'
Bob Mottram's avatar
Bob Mottram committed
    prosodyctl passwd "${curr_username}@${DEFAULT_DOMAIN_NAME}"
    if [ -f /usr/local/bin/profanity ]; then
        XMPP_CLIENT_DIR=/home/$curr_username/.local/share/profanity
        XMPP_CLIENT_ACCOUNTS=$XMPP_CLIENT_DIR/accounts
Bob Mottram's avatar
Bob Mottram committed
        if [ -f "$XMPP_CLIENT_ACCOUNTS" ]; then
            sed -i "s|password=.*|password=$new_user_password|g" "$XMPP_CLIENT_ACCOUNTS"
function reconfigure_xmpp {
    echo -n ''
function update_prosody_modules {
Bob Mottram's avatar
Bob Mottram committed
    if [ ! "$1" ]; then
Bob Mottram's avatar
Bob Mottram committed
        if [ ! -d ${XMPP_DIRECTORY}/prosody-modules ]; then
    fi
    if [ ! -d /usr/lib/prosody ]; then
        return
    fi

Bob Mottram's avatar
Bob Mottram committed
    if [ ! -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
        # Obtain the modules
Bob Mottram's avatar
Bob Mottram committed
        if [ -f "$HOME/${PROJECT_NAME}/image_build/$prosody_modules_filename" ]; then
            cp "$HOME/${PROJECT_NAME}/image_build/$prosody_modules_filename" "$INSTALL_DIR"
Bob Mottram's avatar
Bob Mottram committed
            if [ -f "/home/$MY_USERNAME/${PROJECT_NAME}/image_build/$prosody_modules_filename" ]; then
                cp "/home/$MY_USERNAME/${PROJECT_NAME}/image_build/$prosody_modules_filename" "$INSTALL_DIR"
Bob Mottram's avatar
Bob Mottram committed
        if [ -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
            cd "$INSTALL_DIR" || exit 24

            # Check the hash
Bob Mottram's avatar
Bob Mottram committed
            curr_hash=$(sha256sum "$INSTALL_DIR/$prosody_modules_filename" | awk -F ' ' '{print $1}')
            if [[ "$curr_hash" != "$prosody_modules_hash" ]]; then
                echo $'Prosody modules hash does not match'
            else
                # Extract the modules
Bob Mottram's avatar
Bob Mottram committed
                if [ -d "$INSTALL_DIR/prosody-modules" ]; then
                    rm -rf "$INSTALL_DIR/prosody-modules"
                fi
                tar -xzvf $prosody_modules_filename
Bob Mottram's avatar
Bob Mottram committed
                if [ -d "$INSTALL_DIR/prosody-modules" ]; then
Bob Mottram's avatar
Bob Mottram committed
                    if [ ! -d ${XMPP_DIRECTORY}/prosody-modules ]; then
                        mkdir -p ${XMPP_DIRECTORY}/prosody-modules
Bob Mottram's avatar
Bob Mottram committed
                    cp -r "$INSTALL_DIR/prosody-modules/"* ${XMPP_DIRECTORY}/prosody-modules/
Bob Mottram's avatar
Bob Mottram committed
                    cp -r "$INSTALL_DIR/prosody-modules/"* /usr/lib/prosody/modules/
Bob Mottram's avatar
Bob Mottram committed
                    chown -R prosody:prosody ${XMPP_DIRECTORY}/prosody-modules
                    chown -R prosody:prosody /usr/lib/prosody/modules
Bob Mottram's avatar
Bob Mottram committed
                else
                    echo $'Prosody modules not extracted'
Bob Mottram's avatar
Bob Mottram committed
    prosody_add_module 's2s_blacklist' muc
    prosody_add_module 'firewall'
    prosody_add_module 'block_strangers'
Bob Mottram's avatar
Bob Mottram committed
    xmpp_server_blacklist /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
    if grep -q '"mam_muc";' /etc/prosody/prosody.cfg.lua; then
        sed -i '/"mam_muc";/d' /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
    fi
function prosody_daemon_restart_script {
    # On rare occasions the daemon appears to get stuck
    # i.e. still active, but not accepting connections
    # This ensures that it will unstick itself at least once per day
    if [ -f /etc/cron.daily/prosody ]; then
        rm /etc/cron.daily/prosody
    fi
    if [ ! -f /etc/cron.hourly/prosody ]; then
Bob Mottram's avatar
Bob Mottram committed
        { echo '#!/bin/bash';
          echo "is_active=\$(systemctl is-active prosody)";
          echo "if [[ \"\$is_active\" != 'active' ]]; then";
          echo '  systemctl restart prosody'
          echo 'fi'; } > /etc/cron.hourly/prosody
        chmod +x /etc/cron.hourly/prosody
function configure_xmppsend {
    $INSTALL_PACKAGES libstrophe-dev

    if [ ! -d "$INSTALL_DIR" ]; then
        mkdir -p "$INSTALL_DIR"
    fi
    cd "$INSTALL_DIR" || return
    git clone $XMPPSEND_REPO "$INSTALL_DIR/xmppsend"
    cd "$INSTALL_DIR/xmppsend" || return
    git checkout "$XMPPSEND_COMMIT" -b "$XMPPSEND_COMMIT"
    if ! make; then
        echo $'Unable to build xmppsend'
        return
    fi
    make install

    set_completion_param "xmppsend commit" "$XMPPSEND_COMMIT"
}

function upgrade_xmppsend {
    CURR_XMPPSEND_COMMIT=$(get_completion_param "xmppsend commit")
    if [[ "$CURR_XMPPSEND_COMMIT" == "$XMPPSEND_COMMIT" ]]; then
        return
    fi

    if [ ! -d "$INSTALL_DIR/xmppsend" ]; then
        configure_xmppsend
    else
        cd "$INSTALL_DIR/xmppsend" || return
        git stash
        git checkout master
        git pull
        git checkout "$XMPPSEND_COMMIT" -b "$XMPPSEND_COMMIT"
Bob Mottram's avatar
Bob Mottram committed
        if ! make; then
            return
        fi
        make install

        set_completion_param "xmppsend commit" "$XMPPSEND_COMMIT"
    fi

}

Bob Mottram's avatar
Bob Mottram committed
function prosody_set_parameter {
    prosody_param_name="$1"
    prosody_param_value="$2"

    if ! grep -q "${prosody_param_name} " /etc/prosody/prosody.cfg.lua; then
        echo "${prosody_param_name} = ${prosody_param_value};" >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    else
        if ! grep -q "${prosody_param_name} = ${prosody_param_value};" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|${prosody_param_name} .*|${prosody_param_name} = ${prosody_param_value};|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
       fi
    fi
}

function upgrade_xmpp {
Bob Mottram's avatar
Bob Mottram committed
    if [ -d /etc/letsencrypt ]; then
Bob Mottram's avatar
Bob Mottram committed
        prosody_groups=$(groups prosody)
        if [[ "$prosody_groups" != *'ssl-cert'* ]]; then
            usermod -a -G ssl-cert prosody
        fi
Bob Mottram's avatar
Bob Mottram committed
    fi
    read_config_param ONION_ONLY
    prosody_update_onion_certs

    if [[ "$ONION_ONLY" != 'no' ]]; then
        # Disable TLS for onion only versions
        # this makes the user experience a lot slicker
        # because there are no prompts to accept
        # self-signed certs
        xmpp_tls_enabled='-- '
Bob Mottram's avatar
Bob Mottram committed
        xmpp_str="\-\- \"tls\""
        if ! grep -q "$xmpp_str" /etc/prosody/conf.avail/xmpp.cfg.lua; then
            sed -i "s|\"tls\"|${xmpp_tls_enabled}\"tls\"|g" /etc/prosody/conf.avail/xmpp.cfg.lua
            xmpp_restart=1
        fi
Bob Mottram's avatar
Bob Mottram committed
        if ! grep -q "$xmpp_str" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|\"tls\"|${xmpp_tls_enabled}\"tls\"|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi

    read_config_param XMPP_E2EE
Bob Mottram's avatar
Bob Mottram committed
    xmpp_update_e2e_policy /etc/prosody/conf.avail/xmpp.cfg.lua
    xmpp_update_e2e_policy /etc/prosody/prosody.cfg.lua

    prosody_daemon_restart_script
    function_check update_prosody_modules
    update_prosody_modules
    xmpp_onion_addresses /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
    xmpp_contact_info /etc/prosody/prosody.cfg.lua
    xmpp_server_blacklist /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed

Bob Mottram's avatar
Bob Mottram committed
    # add rate limits
    prosody_add_module "limits"
    if ! grep -q 's2sin = {' /etc/prosody/prosody.cfg.lua; then
        { echo 'limits = {';
          echo '    c2s = {';
          echo "        rate = \"${XMPP_MAX_C2S_RATE}kb/s\";";
          echo "        burst = \"2s\";";
          echo '    };';
          echo '    s2sin = {';
          echo "        rate = \"${XMPP_MAX_S2S_RATE}kb/s\";";
          echo "        burst = \"5s\";";
          echo '    };';
          echo '}'; } >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    fi

Bob Mottram's avatar
Bob Mottram committed
    # add word filter to muc
Bob Mottram's avatar
Bob Mottram committed
    prosody_add_module "filter_words"
Bob Mottram's avatar
Bob Mottram committed
    if ! grep -q 'filter_words =' /etc/prosody/prosody.cfg.lua; then
        echo 'filter_words = {}' >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    fi

Bob Mottram's avatar
Bob Mottram committed
    prosody_set_parameter 'http_upload_file_size_limit' '25165824'
Bob Mottram's avatar
Bob Mottram committed
    prosody_set_parameter 'http_upload_expire_after' '60 * 60 * 24 * 7 -- a week'
Bob Mottram's avatar
Bob Mottram committed
    prosodyctl mod_http_upload expire

Bob Mottram's avatar
Bob Mottram committed
    prosody_set_parameter 'muc_room_default_members_only' 'false'
    prosody_set_parameter 'muc_tombstones' 'false'
    # security labels
    prosody_add_module "seclabels"
    prosody_default_security_labels /etc/prosody/prosody.cfg.lua

Bob Mottram's avatar
Bob Mottram committed
    # extra battery saving
    prosody_add_module "csi_compat"
Bob Mottram's avatar
Bob Mottram committed
    prosody_add_module "csi_battery_saver"
    # remove omemo_all_access
    # This isn't needed with prosody 0.11+
    prosody_remove_module "omemo_all_access"

Bob Mottram's avatar
Bob Mottram committed
    # remove muc logging
Bob Mottram's avatar
Bob Mottram committed
    prosody_remove_module "muc_log"
    prosody_remove_module "muc_log_http"
Bob Mottram's avatar
Bob Mottram committed

    # remove any broadcast settings
Bob Mottram's avatar
Bob Mottram committed
    prosody_remove_module "broadcast"
    # handling avatars
    prosody_remove_module "pep_vcard_avatar"
    prosody_remove_module "vcard"
    prosody_add_module "profile"

    if grep -q "/etc/ssl/certs/xmpp.dhparam" /etc/prosody/prosody.cfg.lua; then
        cp /etc/ssl/certs/xmpp.dhparam /etc/prosody/xmpp.dhparam
        chown prosody:prosody /etc/prosody/xmpp.dhparam
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/prosody.cfg.lua
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi

    if grep -q "/etc/ssl/private/xmpp.key" /etc/prosody/prosody.cfg.lua; then
Bob Mottram's avatar
Bob Mottram committed
        if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem" ]; then
            sed -i "s|/etc/ssl/private/xmpp.key|/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem|g" /etc/prosody/prosody.cfg.lua
        fi
    fi

    if grep -q "/etc/ssl/certs/xmpp.crt" /etc/prosody/prosody.cfg.lua; then
Bob Mottram's avatar
Bob Mottram committed
        if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
            sed -i "s|/etc/ssl/certs/xmpp.crt|/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem|g" /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
    curr_prosody_filename=$(grep "prosody_filename" "$COMPLETION_FILE" | awk -F ':' '{print $2}')
    if [[ "$curr_prosody_filename" != "$prosody_filename" ]]; then
Bob Mottram's avatar
Bob Mottram committed
        if [ -d "${INSTALL_DIR}/${prosody_filename}" ]; then
            # ensure that the binaries have not been overwritten
            # by an operating system upgrade
            cd "${INSTALL_DIR}/${prosody_filename}" || exit 46
            xmpp_fix_exists
            make prefix=/usr install
            cd "$INSTALL_DIR" || exit 23
            # Try to get the source from the project repo
Bob Mottram's avatar
Bob Mottram committed
            if [ -f "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
                cp "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
Bob Mottram's avatar
Bob Mottram committed
                if [ -f "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
                    cp "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
                else
                    wget $prosody_nightly_url
                fi
            fi
Bob Mottram's avatar
Bob Mottram committed
            if [ ! -f "${INSTALL_DIR}/${prosody_filename}.tar.gz" ]; then
                echo $"Failed to download prosody nightly $prosody_nightly_url"
                return
Bob Mottram's avatar
Bob Mottram committed
            hash_value=$(sha256sum "${INSTALL_DIR}/${prosody_filename}.tar.gz" | awk -F ' ' '{print $1}')
            if [[ "$hash_value" != "$prosody_nightly_hash" ]]; then
Bob Mottram's avatar
Bob Mottram committed
                rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
                echo $'Unexpected hash value for prosody nightly download'
                return
            fi

Bob Mottram's avatar
Bob Mottram committed
            tar -xzvf "${INSTALL_DIR}/${prosody_filename}.tar.gz"
            cd "${INSTALL_DIR}/${prosody_filename}" || exit 24
            xmpp_fix_exists
            ./configure --ostype=debian --prefix=/usr
            make prefix=/usr
            make prefix=/usr install
            if [ -f /usr/local/bin/prosody ]; then
                echo $'Failed to build prosody nightly to /usr/bin'
Bob Mottram's avatar
Bob Mottram committed
                rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
                rm -rf "${INSTALL_DIR:?}/${prosody_filename}"
Bob Mottram's avatar
Bob Mottram committed
            rm "${INSTALL_DIR:?}/${prosody_filename}.tar.gz"
        # add onion addresses for known servers
        if ! grep -q "onions_map =" /etc/prosody/prosody.cfg.lua; then
            echo '' >> /etc/prosody/prosody.cfg.lua
            xmpp_onion_addresses /etc/prosody/prosody.cfg.lua
Bob Mottram's avatar
Bob Mottram committed
        fi
        set_completion_param "prosody_filename" "${prosody_filename}"
    if [ $xmpp_restart ]; then
Bob Mottram's avatar
Bob Mottram committed
        cp -r "$INSTALL_DIR/prosody-modules/"* ${XMPP_DIRECTORY}/prosody-modules/