diff --git a/doc/EN/app_cryptpad.org b/doc/EN/app_cryptpad.org index 7c5b83f1..f24946a3 100644 --- a/doc/EN/app_cryptpad.org +++ b/doc/EN/app_cryptpad.org @@ -16,6 +16,10 @@ #+END_EXPORT +#+BEGIN_CENTER +[[file:images/cryptpad.jpg]] +#+END_CENTER + This is similar to [[./app_etherpad.html][EtherPad]] but with better security and more document types which can be collaboratively edited in real time. It includes not just text editing but also creating presentations, voting and editing source code. For added security this system is only available via an onion address, so you and your collaborators will need to be using Tor compatible browsers. diff --git a/doc/EN/app_kanboard.org b/doc/EN/app_kanboard.org new file mode 100644 index 00000000..aee56cf1 --- /dev/null +++ b/doc/EN/app_kanboard.org @@ -0,0 +1,39 @@ +#+TITLE: +#+AUTHOR: Bob Mottram +#+EMAIL: bob@freedombone.net +#+KEYWORDS: freedombone, kanboard +#+DESCRIPTION: How to use KanBoard +#+OPTIONS: ^:nil toc:nil +#+HTML_HEAD: + +#+BEGIN_CENTER +[[file:images/logo.png]] +#+END_CENTER + +#+BEGIN_EXPORT html +
+

KanBoard

+
+#+END_EXPORT + +Kanbans are one way of managing projects. They're traditionally used in businesses but can also be useful for personal TODO lists or within open source or DIY projects. If you have a list of things which need to be done and want to keep track of progress then this provides a way to do that. + +* Installation +Log into your system with: + +#+begin_src bash +ssh myusername@mydomain -p 2222 +#+end_src + +Using cursor keys, space bar and Enter key select *Administrator controls* and type in your password. + +Select *Add/Remove Apps* then *kanboard*. You will then be asked for a domain name and if you are using FreeDNS also the code for the domain which can be found under *Dynamic DNS* on the FreeDNS site (the random string from "/quick cron example/" which appears after /update.php?/ and before />>/). For more details on obtaining a domain and making it accessible via dynamic DNS see the [[./faq.html][FAQ]]. Typically the domain name you use will be a subdomain, such as /kanban.mydomainname.net/. It will need to be a domain which you have bought somewhere and own and not one of the FreeDNS subdomains, otherwise you won't be able to get a SSL/TLS certificate for it. + +After the install has completed go to *Security settings* and select *Create a new Let's Encrypt certificate* and enter the domain name that you are using for KanBoard. If you're using the "onion only" version of the system then you don't need to do this. If the certificate is obtained successfully then you will see a congratulations message. + +* Initial setup +If you have just obtained a Lets Encrypt certificate as above then go to *About* on the administrator control panel and you should see your KanBoard domain listed there along with an onion address. You can then navigate to your site in a browser. + +The default login is username "admin" and password "admin". Obviously the first thing you'll need to do is log in and change the password, which can be done by going to "My Profile" on the drop down list on the right hand side. + +For more details of how to use KanBoard see the [[https://kanboard.net/documentation][documentation here]]. diff --git a/doc/EN/apps.org b/doc/EN/apps.org index 2642a72d..1cf5704d 100644 --- a/doc/EN/apps.org +++ b/doc/EN/apps.org @@ -75,6 +75,10 @@ Run your own IRC chat channel which can be secured with a password and accessibl * Jitsi Meet Experimental WebRTC video conferencing system, similar to Google Hangouts. This may not be fully functional, but is hoped to be in the near future. +* KanBoard +A simple kanban system for managing projects or TODO lists. + +[[./app_kanboard.html][How to use it]] * Koel Access your music collection from any internet connected device. diff --git a/img/cryptpad.jpg b/img/cryptpad.jpg new file mode 100644 index 00000000..e3669e18 Binary files /dev/null and b/img/cryptpad.jpg differ diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad index 91e5104a..4e32af1a 100755 --- a/src/freedombone-app-cryptpad +++ b/src/freedombone-app-cryptpad @@ -37,7 +37,7 @@ SHOW_ICANN_ADDRESS_ON_ABOUT=0 CRYPTPAD_ONION_PORT=8119 CRYPTPAD_PORT=9003 CRYPTPAD_REPO="https://github.com/xwiki-labs/cryptpad" -CRYPTPAD_COMMIT='ed5b005216be9b9029c1ccd25a5fdc7908ed8730' +CRYPTPAD_COMMIT='76e69f0ba85b0e3e21cad2c3eb0012c2429d4bb8' CRYPTPAD_DIR=/etc/cryptpad cryptpad_variables=(ONION_ONLY) @@ -89,6 +89,9 @@ function upgrade_cryptpad { set_repo_commit $CRYPTPAD_DIR "cryptpad commit" "$CRYPTPAD_COMMIT" $CRYPTPAD_REPO cd $CRYPTPAD_DIR + npm install + chown -R cryptpad:cryptpad $CRYPTPAD_DIR + su -c 'bower install' - cryptpad systemctl start cryptpad } diff --git a/src/freedombone-app-gogs b/src/freedombone-app-gogs index 03b87d76..9a1615a9 100755 --- a/src/freedombone-app-gogs +++ b/src/freedombone-app-gogs @@ -139,7 +139,7 @@ function gogs_create_database { fi function_check create_database - create_database gogs "$GOGS_ADMIN_PASSWORD" + create_database gogs "$GIT_ADMIN_PASSWORD" } function reconfigure_gogs { @@ -302,7 +302,7 @@ function backup_remote_gogs { suspend_site ${GIT_DOMAIN_NAME} function_check backup_database_to_friend - backup_database_to_friend $GOGS_USERNAME + backup_database_to_friend gogs echo $"Obtaining Gogs settings backup" diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard new file mode 100755 index 00000000..a33da4ef --- /dev/null +++ b/src/freedombone-app-kanboard @@ -0,0 +1,579 @@ +#!/bin/bash +# +# .---. . . +# | | | +# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. +# | | (.-' (.-' ( | ( )| | | | )( )| | (.-' +# ' ' --' --' -' - -' ' ' -' -' -' ' - --' +# +# Freedom in the Cloud +# +# kanboard kanban +# +# License +# ======= +# +# Copyright (C) 2017 Bob Mottram +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +VARIANTS='full full-vim social' + +IN_DEFAULT_INSTALL=0 +SHOW_ON_ABOUT=1 + +KANBOARD_DOMAIN_NAME= +KANBOARD_CODE= +KANBOARD_ONION_PORT=8121 +KANBOARD_REPO="https://github.com/kanboard/kanboard" +KANBOARD_COMMIT='7a6b1bc3da0af442e02b5a2dc430a4ded8e7c4ee' +KANBOARD_ADMIN_PASSWORD= + + +kanboard_variables=(ONION_ONLY + KANBOARD_DOMAIN_NAME + KANBOARD_CODE + DDNS_PROVIDER + MY_USERNAME) + +function logging_on_kanboard { + kanboard_configfile=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.php + sed -i "s|define('LOG_FILE'.*|define('LOG_FILE', DATA_DIR.DIRECTORY_SEPARATOR.'debug.log');|g" $kanboard_configfile +} + +function logging_off_kanboard { + kanboard_configfile=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.php + sed -i "s|define('LOG_FILE'.*|define('LOG_FILE', '/dev/null');|g" $kanboard_configfile +} + +function remove_user_kanboard { + remove_username="$1" + + ${PROJECT_NAME}-pass -u $remove_username --rmapp kanboard +} + +function add_user_kanboard { + new_username="$1" + new_user_password="$2" + + ${PROJECT_NAME}-pass -u $new_username -a kanboard -p "$new_user_password" + echo '0' +} + +function install_interactive_kanboard { + if [ ! $ONION_ONLY ]; then + ONION_ONLY='no' + fi + + if [[ $ONION_ONLY != "no" ]]; then + KANBOARD_DOMAIN_NAME='kanboard.local' + else + KANBOARD_DETAILS_COMPLETE= + while [ ! $KANBOARD_DETAILS_COMPLETE ] + do + data=$(tempfile 2>/dev/null) + trap "rm -f $data" 0 1 2 5 15 + if [[ $DDNS_PROVIDER == "default@freedns.afraid.org" ]]; then + dialog --backtitle $"Freedombone Configuration" \ + --title $"KanBoard Configuration" \ + --form $"\nPlease enter your KanBoard details.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt." 13 55 2 \ + $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 15 33 40 \ + $"Code:" 2 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 2 15 33 255 \ + 2> $data + else + dialog --backtitle $"Freedombone Configuration" \ + --title $"KanBoard Configuration" \ + --form $"\nPlease enter your KanBoard details.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt." 13 55 2 \ + $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 15 33 40 \ + 2> $data + fi + sel=$? + case $sel in + 1) exit 1;; + 255) exit 1;; + esac + KANBOARD_DOMAIN_NAME=$(cat $data | sed -n 1p) + if [ $KANBOARD_DOMAIN_NAME ]; then + if [[ $KANBOARD_DOMAIN_NAME == "$HUBZILLA_DOMAIN_NAME" ]]; then + KANBOARD_DOMAIN_NAME="" + fi + TEST_DOMAIN_NAME=$KANBOARD_DOMAIN_NAME + validate_domain_name + if [[ $TEST_DOMAIN_NAME != $KANBOARD_DOMAIN_NAME ]]; then + KANBOARD_DOMAIN_NAME= + dialog --title $"Domain name validation" --msgbox "$TEST_DOMAIN_NAME" 15 50 + else + if [[ $DDNS_PROVIDER == "default@freedns.afraid.org" ]]; then + KANBOARD_CODE=$(cat $data | sed -n 2p) + validate_freedns_code "$KANBOARD_CODE" + if [ ! $VALID_CODE ]; then + KANBOARD_DOMAIN_NAME= + fi + fi + fi + fi + if [ $KANBOARD_DOMAIN_NAME ]; then + KANBOARD_DETAILS_COMPLETE="yes" + fi + done + + # save the results in the config file + write_config_param "KANBOARD_CODE" "$KANBOARD_CODE" + fi + write_config_param "KANBOARD_DOMAIN_NAME" "$KANBOARD_DOMAIN_NAME" + APP_INSTALLED=1 +} + +function change_password_kanboard { + curr_username="$1" + new_user_password="$2" + + read_config_param 'KANBOARD_DOMAIN_NAME' + + ${PROJECT_NAME}-pass -u "$curr_username" -a kanboard -p "$new_user_password" +} + +function kanboard_create_database { + if [ -f $IMAGE_PASSWORD_FILE ]; then + KANBOARD_ADMIN_PASSWORD="$(printf `cat $IMAGE_PASSWORD_FILE`)" + else + if [ ! $KANBOARD_ADMIN_PASSWORD ]; then + KANBOARD_ADMIN_PASSWORD="$(create_password ${MINIMUM_PASSWORD_LENGTH})" + fi + fi + if [ ! $KANBOARD_ADMIN_PASSWORD ]; then + return + fi + + function_check create_database + create_database kanboard "$KANBOARD_ADMIN_PASSWORD" $MY_USERNAME +} + +function reconfigure_kanboard { + echo -n '' +} + +function upgrade_kanboard { + CURR_KANBOARD_COMMIT=$(get_completion_param "kanboard commit") + if [[ "$CURR_KANBOARD_COMMIT" == "$KANBOARD_COMMIT" ]]; then + return + fi + + if grep -q "kanboard domain" $COMPLETION_FILE; then + KANBOARD_DOMAIN_NAME=$(get_completion_param "kanboard domain") + fi + + # update to the next commit + function_check set_repo_commit + set_repo_commit /var/www/$KANBOARD_DOMAIN_NAME/htdocs "kanboard commit" "$KANBOARD_COMMIT" $KANBOARD_REPO + + chown -R www-data:www-data /var/www/${KANBOARD_DOMAIN_NAME}/htdocs +} + + +function backup_local_kanboard { + KANBOARD_DOMAIN_NAME='kanboard' + if grep -q "kanboard domain" $COMPLETION_FILE; then + KANBOARD_DOMAIN_NAME=$(get_completion_param "kanboard domain") + fi + + source_directory=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/backup + if [ ! -d $source_directory ]; then + mkdir $source_directory + fi + cp -p /var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.php $source_directory + + function_check suspend_site + suspend_site ${KANBOARD_DOMAIN_NAME} + + function_check backup_directory_to_usb + dest_directory=kanboardconfig + backup_directory_to_usb $source_directory $dest_directory + + source_directory=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/data + dest_directory=kanboardfile + backup_directory_to_usb $source_directory $dest_directory + + function_check backup_database_to_usb + backup_database_to_usb kanboard + + function_check restart_site + restart_site +} + +function restore_local_kanboard { + if ! grep -q "kanboard domain" $COMPLETION_FILE; then + return + fi + KANBOARD_DOMAIN_NAME=$(get_completion_param "kanboard domain") + if [ $KANBOARD_DOMAIN_NAME ]; then + echo $"Restoring kanboard" + temp_restore_dir=/root/tempkanboard + kanboard_dir=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs + + function_check kanboard_create_database + kanboard_create_database + + restore_database kanboard + if [ -d $temp_restore_dir ]; then + rm -rf $temp_restore_dir + fi + + function_check restore_directory_from_usb + restore_directory_from_usb $temp_restore_dir kanboardconfig + if [ -d $temp_restore_dir ]; then + cp $temp_restore_dir$kanboard_dir/backup/config.php $kanboard_dir/ + chown www-data:www-data $kanboard_dir/config.php + rm -rf $temp_restore_dir + fi + + restore_directory_from_usb $temp_restore_dir kanboardfile + if [ -d $temp_restore_dir ]; then + cp -rp $temp_restore_dir$kanboard_dir/data $kanboard_dir/ + chown -R www-data:www-data $kanboard_dir/data + rm -rf $temp_restore_dir + fi + + kanboard_update_after_restore kanboard ${KANBOARD_DOMAIN_NAME} + + echo $"Restore of kanboard complete" + fi +} + +function backup_remote_kanboard { + KANBOARD_DOMAIN_NAME='kanboard' + if grep -q "kanboard domain" $COMPLETION_FILE; then + KANBOARD_DOMAIN_NAME=$(get_completion_param "kanboard domain") + fi + + source_directory=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/backup + if [ ! -d $source_directory ]; then + mkdir $source_directory + fi + cp -p /var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.php $source_directory + + function_check suspend_site + suspend_site ${KANBOARD_DOMAIN_NAME} + + function_check backup_directory_to_friend + dest_directory=kanboardconfig + backup_directory_to_friend $source_directory $dest_directory + + source_directory=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/data + dest_directory=kanboardfile + backup_directory_to_friend $source_directory $dest_directory + + function_check backup_database_to_friend + backup_database_to_friend kanboard + + function_check restart_site + restart_site +} + +function restore_remote_kanboard { + if ! grep -q "kanboard domain" $COMPLETION_FILE; then + return + fi + KANBOARD_DOMAIN_NAME=$(get_completion_param "kanboard domain") + if [ $KANBOARD_DOMAIN_NAME ]; then + echo $"Restoring kanboard" + temp_restore_dir=/root/tempkanboard + kanboard_dir=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs + + function_check kanboard_create_database + kanboard_create_database + + function_check restore_database_from_friend + restore_database_from_friend kanboard + if [ -d $temp_restore_dir ]; then + rm -rf $temp_restore_dir + fi + + function_check restore_directory_from_friend + restore_directory_from_friend $temp_restore_dir kanboardconfig + if [ -d $temp_restore_dir ]; then + cp $temp_restore_dir$kanboard_dir/backup/config.php $kanboard_dir/ + chown www-data:www-data $kanboard_dir/config.php + rm -rf $temp_restore_dir + fi + + restore_directory_from_friend $temp_restore_dir kanboardfile + if [ -d $temp_restore_dir ]; then + cp -rp $temp_restore_dir$kanboard_dir/data $kanboard_dir/ + chown -R www-data:www-data $kanboard_dir/data + rm -rf $temp_restore_dir + fi + + kanboard_update_after_restore kanboard ${KANBOARD_DOMAIN_NAME} + + echo $"Restore of kanboard complete" + fi +} + +function remove_kanboard { + if [ ${#KANBOARD_DOMAIN_NAME} -eq 0 ]; then + return + fi + read_config_param "KANBOARD_DOMAIN_NAME" + read_config_param "MY_USERNAME" + echo "Removing $KANBOARD_DOMAIN_NAME" + nginx_dissite $KANBOARD_DOMAIN_NAME + remove_certs $KANBOARD_DOMAIN_NAME + + if [ -d /var/www/$KANBOARD_DOMAIN_NAME ]; then + rm -rf /var/www/$KANBOARD_DOMAIN_NAME + fi + if [ -f /etc/nginx/sites-available/$KANBOARD_DOMAIN_NAME ]; then + rm /etc/nginx/sites-available/$KANBOARD_DOMAIN_NAME + fi + function_check drop_database + drop_database kanboard + function_check remove_onion_service + remove_onion_service kanboard ${KANBOARD_ONION_PORT} + remove_app kanboard + remove_completion_param install_kanboard + sed -i '/kanboard/d' $COMPLETION_FILE + remove_backup_database_local kanboard + + function_check remove_ddns_domain + remove_ddns_domain $KANBOARD_DOMAIN_NAME +} + +function install_kanboard { + if [ ! $ONION_ONLY ]; then + ONION_ONLY='no' + fi + + if [ ! $KANBOARD_DOMAIN_NAME ]; then + echo $'No domain name was given for kanboard' + exit 73478 + fi + + kanboard_hourly_script kanboard $KANBOARD_DOMAIN_NAME + + function_check install_mariadb + install_mariadb + + function_check get_mariadb_password + get_mariadb_password + + function_check repair_databases_script + repair_databases_script + + apt-get -yq install php-gettext php-curl php-gd php-mysql git curl + apt-get -yq install memcached php-memcached php-intl exiftool libfcgi0ldbl + + if [ ! -d /var/www/$KANBOARD_DOMAIN_NAME ]; then + mkdir /var/www/$KANBOARD_DOMAIN_NAME + fi + if [ ! -d /var/www/$KANBOARD_DOMAIN_NAME/htdocs ]; then + + if [ -d /repos/kanboard ]; then + mkdir /var/www/$KANBOARD_DOMAIN_NAME/htdocs + cp -r -p /repos/kanboard/. /var/www/$KANBOARD_DOMAIN_NAME/htdocs + cd /var/www/$KANBOARD_DOMAIN_NAME/htdocs + git pull + else + function_check git_clone + git_clone $KANBOARD_REPO /var/www/$KANBOARD_DOMAIN_NAME/htdocs + fi + + if [ ! -d /var/www/$KANBOARD_DOMAIN_NAME/htdocs ]; then + echo $'Unable to clone kanboard repo' + exit 89365 + fi + fi + + cd /var/www/$KANBOARD_DOMAIN_NAME/htdocs + git checkout $KANBOARD_COMMIT -b $KANBOARD_COMMIT + set_completion_param "kanboard commit" "$KANBOARD_COMMIT" + + chmod g+w /var/www/$KANBOARD_DOMAIN_NAME/htdocs + chmod a+w /var/www/$KANBOARD_DOMAIN_NAME/htdocs/data + chown -R www-data:www-data /var/www/$KANBOARD_DOMAIN_NAME/htdocs + + function_check kanboard_create_database + kanboard_create_database + + if [ ! -f "/etc/aliases" ]; then + touch /etc/aliases + fi + if ! grep -q "www-data: root" /etc/aliases; then + echo 'www-data: root' >> /etc/aliases + fi + + function_check add_ddns_domain + add_ddns_domain $KANBOARD_DOMAIN_NAME + + KANBOARD_ONION_HOSTNAME=$(add_onion_service kanboard 80 ${KANBOARD_ONION_PORT}) + + kanboard_nginx_site=/etc/nginx/sites-available/$KANBOARD_DOMAIN_NAME + if [[ $ONION_ONLY == "no" ]]; then + function_check nginx_http_redirect + nginx_http_redirect $KANBOARD_DOMAIN_NAME "index index.php" + echo 'server {' >> $kanboard_nginx_site + echo ' listen 443 ssl;' >> $kanboard_nginx_site + echo ' listen [::]:443 ssl;' >> $kanboard_nginx_site + echo " server_name $KANBOARD_DOMAIN_NAME;" >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + function_check nginx_compress + nginx_compress $KANBOARD_DOMAIN_NAME + echo '' >> $kanboard_nginx_site + echo ' # Security' >> $kanboard_nginx_site + function_check nginx_ssl + nginx_ssl $KANBOARD_DOMAIN_NAME + + function_check nginx_disable_sniffing + nginx_disable_sniffing $KANBOARD_DOMAIN_NAME + + echo ' add_header Strict-Transport-Security max-age=15768000;' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Logs' >> $kanboard_nginx_site + echo ' access_log /dev/null;' >> $kanboard_nginx_site + echo ' error_log /dev/null;' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Root' >> $kanboard_nginx_site + echo " root /var/www/$KANBOARD_DOMAIN_NAME/htdocs;" >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Index' >> $kanboard_nginx_site + echo ' index index.php;' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # PHP' >> $kanboard_nginx_site + echo ' location ~ \.php {' >> $kanboard_nginx_site + echo ' include snippets/fastcgi-php.conf;' >> $kanboard_nginx_site + echo ' fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;' >> $kanboard_nginx_site + echo ' fastcgi_read_timeout 30;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Location' >> $kanboard_nginx_site + echo ' location / {' >> $kanboard_nginx_site + function_check nginx_limits + nginx_limits $KANBOARD_DOMAIN_NAME '15m' + echo ' try_files $uri $uri/ @kanboard;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Fancy URLs' >> $kanboard_nginx_site + echo ' location @kanboard {' >> $kanboard_nginx_site + echo ' rewrite ^(.*)$ /index.php?p=$1 last;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Restrict access that is unnecessary anyway' >> $kanboard_nginx_site + echo ' location ~ /\.(ht|git) {' >> $kanboard_nginx_site + echo ' deny all;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + # DO NOT ENABLE KEYBASE. kanboard really doesn't like having a .well-known directory + echo '}' >> $kanboard_nginx_site + else + echo -n '' > $kanboard_nginx_site + fi + echo 'server {' >> $kanboard_nginx_site + echo " listen 127.0.0.1:$KANBOARD_ONION_PORT default_server;" >> $kanboard_nginx_site + echo " server_name $KANBOARD_ONION_HOSTNAME;" >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + function_check nginx_compress + nginx_compress $KANBOARD_DOMAIN_NAME + echo '' >> $kanboard_nginx_site + function_check nginx_disable_sniffing + nginx_disable_sniffing $KANBOARD_DOMAIN_NAME + echo '' >> $kanboard_nginx_site + echo ' # Logs' >> $kanboard_nginx_site + echo ' access_log /dev/null;' >> $kanboard_nginx_site + echo ' error_log /dev/null;' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Root' >> $kanboard_nginx_site + echo " root /var/www/$KANBOARD_DOMAIN_NAME/htdocs;" >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Index' >> $kanboard_nginx_site + echo ' index index.php;' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # PHP' >> $kanboard_nginx_site + echo ' location ~ \.php {' >> $kanboard_nginx_site + echo ' include snippets/fastcgi-php.conf;' >> $kanboard_nginx_site + echo ' fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;' >> $kanboard_nginx_site + echo ' fastcgi_read_timeout 30;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Location' >> $kanboard_nginx_site + echo ' location / {' >> $kanboard_nginx_site + function_check nginx_limits + nginx_limits $KANBOARD_DOMAIN_NAME '15m' + echo ' try_files $uri $uri/ @kanboard;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Fancy URLs' >> $kanboard_nginx_site + echo ' location @kanboard {' >> $kanboard_nginx_site + echo ' rewrite ^(.*)$ /index.php?p=$1 last;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + echo ' # Restrict access that is unnecessary anyway' >> $kanboard_nginx_site + echo ' location ~ /\.(ht|git) {' >> $kanboard_nginx_site + echo ' deny all;' >> $kanboard_nginx_site + echo ' }' >> $kanboard_nginx_site + echo '' >> $kanboard_nginx_site + # DO NOT ENABLE KEYBASE. kanboard really doesn't like having a .well-known directory + echo '}' >> $kanboard_nginx_site + + function_check configure_php + configure_php + + function_check create_site_certificate + create_site_certificate $KANBOARD_DOMAIN_NAME 'yes' + + # Ensure that the database gets backed up locally, if remote + # backups are not being used + function_check backup_databases_script_header + backup_databases_script_header + + function_check backup_database_local + backup_database_local kanboard + + function_check nginx_ensite + nginx_ensite $KANBOARD_DOMAIN_NAME + + KANBOARD_SERVER=${KANBOARD_DOMAIN_NAME} + if [[ $ONION_ONLY != 'no' ]]; then + KANBOARD_SERVER=${KANBOARD_ONION_HOSTNAME} + fi + + # Create the configuration + kanboard_configfile=/var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.php + cp /var/www/${KANBOARD_DOMAIN_NAME}/htdocs/config.default.php $kanboard_configfile + sed -i "s|define('MAIL_FROM'.*|define('MAIL_FROM', '$MY_EMAIL_ADDRESS');|g" $kanboard_configfile + sed -i "s|define('DB_DRIVER'.*|define('DB_DRIVER', 'mysql');|g" $kanboard_configfile + sed -i "s|define('DB_USERNAME'.*|define('DB_USERNAME', 'root');|g" $kanboard_configfile + sed -i "s|define('DB_PASSWORD'.*|define('DB_PASSWORD', '$MARIADB_PASSWORD');|g" $kanboard_configfile + sed -i "s|define('DB_HOSTNAME'.*|define('DB_HOSTNAME', 'localhost');|g" $kanboard_configfile + sed -i "s|define('DB_NAME'.*|define('DB_NAME', 'kanboard');|g" $kanboard_configfile + sed -i "s|define('DB_PORT'.*|define('DB_PORT', null);|g" $kanboard_configfile + logging_off_kanboard + + initialise_database kanboard /var/www/${KANBOARD_DOMAIN_NAME}/htdocs/app/Schema/Sql/mysql.sql + chown -R www-data:www-data /var/www/${KANBOARD_DOMAIN_NAME}/htdocs + + cd /var/www/${KANBOARD_DOMAIN_NAME}/htdocs + install_composer + + systemctl restart mariadb + systemctl restart php7.0-fpm + systemctl restart nginx + + ${PROJECT_NAME}-pass -u $MY_USERNAME -a kanboard -p "$KANBOARD_ADMIN_PASSWORD" + + set_completion_param "kanboard domain" "$KANBOARD_DOMAIN_NAME" + + APP_INSTALLED=1 +} + +# NOTE: deliberately there is no "exit 0" diff --git a/src/freedombone-app-koel b/src/freedombone-app-koel index 296281b7..95225708 100755 --- a/src/freedombone-app-koel +++ b/src/freedombone-app-koel @@ -715,21 +715,9 @@ function install_koel { install_koel_main cd /var/www/$KOEL_DOMAIN_NAME/htdocs + install_composer - # curl -sS https://getcomposer.org/installer | php - if [ -f ~/freedombone/image_build/composer_install ]; then - cat ~/freedombone/image_build/composer_install | php - else - if [ -f /home/$MY_USERNAME/freedombone/image_build/composer_install ]; then - cat /home/$MY_USERNAME/freedombone/image_build/composer_install | php - fi - fi npm install -g yarn - php composer.phar install - if [ ! "$?" = "0" ]; then - echo $'Unable to run composer install' - exit 7252198 - fi npm install function_check get_mariadb_password diff --git a/src/freedombone-app-movim b/src/freedombone-app-movim index 6cfa3cf7..52f0bb0b 100755 --- a/src/freedombone-app-movim +++ b/src/freedombone-app-movim @@ -383,15 +383,8 @@ function install_movim { # Fix typo sed -i 's|weksocket|websocket|g' app/widgets/AdminTest/admintest.js - # curl -sS https://getcomposer.org/installer | php - if [ -f ~/freedombone/image_build/composer_install ]; then - cat ~/freedombone/image_build/composer_install | php - else - if [ -f /home/$MY_USERNAME/freedombone/image_build/composer_install ]; then - cat /home/$MY_USERNAME/freedombone/image_build/composer_install | php - fi - fi - php composer.phar install + cd /var/www/$MOVIM_DOMAIN_NAME/htdocs + install_composer cd /var/www/$MOVIM_DOMAIN_NAME/htdocs/config cp db.example.inc.php db.inc.php diff --git a/src/freedombone-app-profanity b/src/freedombone-app-profanity index 38570412..6ad9bdae 100755 --- a/src/freedombone-app-profanity +++ b/src/freedombone-app-profanity @@ -34,13 +34,13 @@ IN_DEFAULT_INSTALL=0 SHOW_ON_ABOUT=1 LIBMESODE_REPO="https://github.com/boothj5/libmesode" -LIBMESODE_COMMIT='e3db0e9bfba61b2d82193874343a94a88f910800' +LIBMESODE_COMMIT='b91872cf7e7ed4d2443ab5c622f4cdb395d64dbe' PROFANITY_REPO="https://github.com/boothj5/profanity" -PROFANITY_COMMIT='2fafaec8a7dc9bc01ee894d83214590598b32914' +PROFANITY_COMMIT='f8b855b09f2c4e9b461b0b7854afabbecf6d5b4a' PROFANITY_OMEMO_PLUGIN_REPO="https://github.com/ReneVolution/profanity-omemo-plugin" -PROFANITY_OMEMO_PLUGIN_COMMIT='3ec8ec173656bed9761b740b086123e07c749548' +PROFANITY_OMEMO_PLUGIN_COMMIT='78be0c8367c6379829986755c0d1da287c031234' xmpp_variables=(ONION_ONLY INSTALLED_WITHIN_DOCKER @@ -285,7 +285,11 @@ function install_profanity { echo 'enabled=true' >> $XMPP_CLIENT_ACCOUNTS echo "jid=${MY_USERNAME}@${DEFAULT_DOMAIN_NAME}" >> $XMPP_CLIENT_ACCOUNTS echo "server=$XMPP_ONION_HOSTNAME" >> $XMPP_CLIENT_ACCOUNTS - echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID" >> $XMPP_CLIENT_ACCOUNTS + # There is a bug where profanity doesn't refresh the screen + # after gpg-agent has asked for a password, so for now + # don't set the gpg key by default + #echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID" >> $XMPP_CLIENT_ACCOUNTS + echo "pgp.keyid=" >> $XMPP_CLIENT_ACCOUNTS echo 'resource=profanity' >> $XMPP_CLIENT_ACCOUNTS echo "muc.service=chat.${DEFAULT_DOMAIN_NAME}" >> $XMPP_CLIENT_ACCOUNTS echo "muc.nick=${MY_USERNAME}" >> $XMPP_CLIENT_ACCOUNTS @@ -310,7 +314,11 @@ function install_profanity { fi echo "jid=${MY_USERNAME}@${XMPP_ONION_HOSTNAME}" >> $XMPP_CLIENT_ACCOUNTS echo "server=$XMPP_ONION_HOSTNAME" >> $XMPP_CLIENT_ACCOUNTS - echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID" >> $XMPP_CLIENT_ACCOUNTS + # There is a bug where profanity doesn't refresh the screen + # after gpg-agent has asked for a password, so for now + # don't set the gpg key by default + #echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID" >> $XMPP_CLIENT_ACCOUNTS + echo "pgp.keyid=" >> $XMPP_CLIENT_ACCOUNTS echo 'resource=profanity' >> $XMPP_CLIENT_ACCOUNTS echo "muc.service=${XMPP_ONION_HOSTNAME}" >> $XMPP_CLIENT_ACCOUNTS echo "muc.nick=${MY_USERNAME}" >> $XMPP_CLIENT_ACCOUNTS diff --git a/src/freedombone-app-wekan b/src/freedombone-app-wekan new file mode 100755 index 00000000..d0894e2b --- /dev/null +++ b/src/freedombone-app-wekan @@ -0,0 +1,494 @@ +#!/bin/bash +# +# .---. . . +# | | | +# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. +# | | (.-' (.-' ( | ( )| | | | )( )| | (.-' +# ' ' --' --' -' - -' ' ' -' -' -' ' - --' +# +# Freedom in the Cloud +# +# Wekan kanban +# +# License +# ======= +# +# Copyright (C) 2017 Bob Mottram +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +VARIANTS='' + +IN_DEFAULT_INSTALL=0 +SHOW_ON_ABOUT=0 + +WEKAN_DOMAIN_NAME= +WEKAN_CODE= +WEKAN_PORT=8081 +WEKAN_ONION_PORT=8120 +WEKAN_REPO="https://github.com/wekan/wekan" +WEKAN_COMMIT='dc547c38d1f5ca72729f6d8f81eb03671ca15934' +FLOW_ROUTER_REPO="git://github.com/wekan/flow-router.git" +FLOW_ROUTER_COMMIT='0c1f6423ed9b68eb00cfb1a19492438917a38956' +WEKAN_DIR=/etc/wekan + +wekan_variables=(ONION_ONLY + WEKAN_DOMAIN_NAME + WEKAN_CODE + DDNS_PROVIDER + MY_USERNAME) + +function logging_on_wekan { + echo -n '' +} + +function logging_off_wekan { + echo -n '' +} + +function remove_user_wekan { + remove_username="$1" +} + +function add_user_wekan { + new_username="$1" + new_user_password="$2" + echo '0' +} + +function install_interactive_wekan { + if [[ $ONION_ONLY != "no" ]]; then + GIT_DOMAIN_NAME='wekan.local' + write_config_param "WEKAN_DOMAIN_NAME" "$WEKAN_DOMAIN_NAME" + else + function_check interactive_site_details + interactive_site_details wekan + fi + APP_INSTALLED=1 +} + +function change_password_wekan { + curr_username="$1" + new_user_password="$2" +} + +function reconfigure_wekan { + echo -n '' +} + +function upgrade_wekan { + CURR_WEKAN_COMMIT=$(get_completion_param "wekan commit") + if [[ "$CURR_WEKAN_COMMIT" == "$WEKAN_COMMIT" ]]; then + return + fi + + systemctl stop wekan + + # update to the next commit + function_check set_repo_commit + set_repo_commit $WEKAN_DIR "wekan commit" "$WEKAN_COMMIT" $WEKAN_REPO + + systemctl start wekan +} + +function backup_local_wekan { + source_directory=$WEKAN_DIR/data + if [ -d $source_directory ]; then + systemctl stop wekan + + dest_directory=wekan + function_check suspend_site + suspend_site wekan + + function_check backup_database_to_usb + backup_database_to_usb wekan + + function_check backup_directory_to_usb + backup_directory_to_usb $source_directory $dest_directory + + function_check restart_site + restart_site + + systemctl start wekan + fi +} + +function restore_local_wekan { + if [ -d $WEKAN_DIR ]; then + systemctl stop wekan + + function_check restore_database + restore_database gogs ${WEKAN_DOMAIN_NAME} + + temp_restore_dir=/root/tempwekan + function_check restore_directory_from_usb + restore_directory_from_usb $temp_restore_dir wekan + cp -r $temp_restore_dir$WEKAN_DIR/data/* $WEKAN_DIR/data/ + + systemctl start wekan + fi +} + +function backup_remote_wekan { + if grep -q "wekan domain" $COMPLETION_FILE; then + temp_backup_dir=$WEKAN_DIR/data + if [ -d $temp_backup_dir ]; then + systemctl stop wekan + + function_check suspend_site + suspend_site wekan + + echo $"Backing up Wekan installation" + + function_check backup_database_to_friend + backup_database_to_friend wekan + + function_check backup_directory_to_friend + backup_directory_to_friend $temp_backup_dir wekan + + function_check restart_site + restart_site + + systemctl start wekan + else + echo $"wekan domain specified but not found in ${temp_backup_dir}" + fi + fi +} + +function restore_remote_wekan { + if [ -d $WEKAN_DIR ]; then + systemctl stop wekan + + function_check restore_database_from_friend + restore_database_from_friend wekan + + temp_restore_dir=/root/tempwekan + function_check restore_directory_from_usb + restore_directory_from_friend $temp_restore_dir wekan + cp -r $temp_restore_dir$WEKAN_DIR/data/* $WEKAN_DIR/data/ + + systemctl start wekan + fi +} + +function remove_wekan { + systemctl stop wekan + systemctl disable wekan + if [ -f /etc/systemd/system/wekan.service ]; then + rm /etc/systemd/system/wekan.service + fi + systemctl daemon-reload + + function_check remove_nodejs + remove_nodejs wekan + + nginx_dissite wekan + + if [ -d $WEKAN_DIR ]; then + rm -rf $WEKAN_DIR + fi + if [ -f /etc/nginx/sites-available/wekan ]; then + rm /etc/nginx/sites-available/wekan + fi + function_check drop_database + drop_database wekan + function_check remove_onion_service + remove_onion_service wekan ${WEKAN_ONION_PORT} + remove_app wekan + remove_completion_param install_wekan + sed -i '/wekan/d' $COMPLETION_FILE + + groupdel -f gogs + userdel -r wekan + remove_meteor +} + +function wekan_create_database { + if [ -f ${IMAGE_PASSWORD_FILE} ]; then + WEKAN_ADMIN_PASSWORD="$(printf `cat $IMAGE_PASSWORD_FILE`)" + else + if [ ! ${GIT_ADMIN_PASSWORD} ]; then + WEKAN_ADMIN_PASSWORD="$(create_password ${MINIMUM_PASSWORD_LENGTH})" + fi + fi + if [ ! $WEKAN_ADMIN_PASSWORD ]; then + return + fi + + function_check create_database + create_database gogs "$WEKAN_ADMIN_PASSWORD" +} + +function install_wekan_main { + if [[ $(app_is_installed wekan_main) == "1" ]]; then + return + fi + + if [ ! -d /var/www/wekan ]; then + mkdir /var/www/wekan + fi + if [ -d $WEKAN_DIR ]; then + rm -rf $WEKAN_DIR + fi + + if [ -d /repos/wekan ]; then + mkdir -p $WEKAN_DIR + cp -r -p /repos/wekan/. $WEKAN_DIR + cd $WEKAN_DIR + git pull + else + function_check git_clone + git_clone $WEKAN_REPO $WEKAN_DIR + fi + + if [ ! -d $WEKAN_DIR ]; then + echo $'Unable to clone wekan repo' + exit 783251 + fi + + # an unprivileged user to run as + useradd -d $WEKAN_DIR/ wekan + groupadd wekan + + cd $WEKAN_DIR + git checkout $WEKAN_COMMIT -b $WEKAN_COMMIT + set_completion_param "wekan commit" "$WEKAN_COMMIT" + + chown -R wekan:wekan $WEKAN_DIR + + WEKAN_ONION_HOSTNAME=$(add_onion_service wekan 80 ${WEKAN_ONION_PORT}) + set_completion_param "wekan onion domain" "$WEKAN_ONION_HOSTNAME" + + wekan_nginx_site=/etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + if [[ ${ONION_ONLY} == "no" ]]; then + function_check nginx_http_redirect + nginx_http_redirect ${WEKAN_DOMAIN_NAME} + echo 'server {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' listen 443 ssl;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' listen [::]:443 ssl;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " root /var/www/${WEKAN_DOMAIN_NAME}/htdocs;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " server_name ${WEKAN_DOMAIN_NAME};" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' access_log /dev/null;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " error_log /dev/null;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + function_check nginx_ssl + nginx_ssl ${WEKAN_DOMAIN_NAME} + function_check nginx_disable_sniffing + nginx_disable_sniffing ${WEKAN_DOMAIN_NAME} + echo ' add_header Strict-Transport-Security max-age=0;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' location / {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + function_check nginx_limits + nginx_limits ${WEKAN_DOMAIN_NAME} '15m' + echo " proxy_pass http://localhost:$WEKAN_PORT;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' }' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' fastcgi_buffers 64 4K;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' error_page 403 /core/templates/403.php;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' error_page 404 /core/templates/404.php;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' location = /robots.txt {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' allow all;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' log_not_found off;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' access_log /dev/null;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' }' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + nginx_keybase ${WEKAN_DOMAIN_NAME} + echo '}' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + else + echo -n '' > /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + fi + echo 'server {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " listen 127.0.0.1:${WEKAN_ONION_PORT} default_server;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " root /var/www/$WEKAN_DOMAIN_NAME/htdocs;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " server_name $WEKAN_DOMAIN_NAME;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' access_log /dev/null;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo " error_log /dev/null;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + function_check nginx_disable_sniffing + nginx_disable_sniffing ${WEKAN_DOMAIN_NAME} + echo ' add_header Strict-Transport-Security max-age=0;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' location / {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + function_check nginx_limits + nginx_limits ${WEKAN_DOMAIN_NAME} '15m' + echo " proxy_pass http://localhost:$WEKAN_PORT;" >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' }' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' fastcgi_buffers 64 4K;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' error_page 403 /core/templates/403.php;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' error_page 404 /core/templates/404.php;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' location = /robots.txt {' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' allow all;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' log_not_found off;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' access_log /dev/null;' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo ' }' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + echo '' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + nginx_keybase ${WEKAN_DOMAIN_NAME} + echo '}' >> /etc/nginx/sites-available/${WEKAN_DOMAIN_NAME} + + function_check nginx_ensite + nginx_ensite wekan + + install_completed wekan_main +} + +function install_wekan { + apt-get -qy install build-essential c++ capnproto curl + + function_check install_nodejs + install_nodejs wekan + + install_wekan_main + install_meteor + + cd $WEKAN_DIR + + su -c 'npm install babel-runtime' - wekan + su -c 'npm install node-gyp' - wekan + su -c 'npm install node-pre-gyp' - wekan + su -c 'npm install fibers' - wekan + su -c 'npm install bcrypt' - wekan + su -c 'npm install bson' - wekan + su -c 'npm install es6-promise' - wekan + su -c 'npm install meteor-node-stubs' - wekan + su -c 'npm install winston' - wekan + su -c 'npm install winston-zulip' - wekan + su -c 'npm install xss' - wekan + + # Remove any directories from previous installs + if [ -d $WEKAN_DIR/.meteor ]; then + rm -rf $WEKAN_DIR/.meteor + fi + if [ -d $WEKAN_DIR/app ]; then + rm -rf $WEKAN_DIR/app + fi + if [ -d $WEKAN_DIR/app_build ]; then + rm -rf $WEKAN_DIR/app_build + fi + + # Get additional packages + mkdir -p $WEKAN_DIR/.meteor/packages + chown wekan:wekan --recursive $WEKAN_DIR/.meteor + cd $WEKAN_DIR/.meteor/packages + if [ ! -d /repos/flowrouter ]; then + su -c "git clone --depth 1 -b master $FLOW_ROUTER_REPO kadira-flow-router" - wekan + else + mkdir kadira-flow-router + cp -r -p /repos/flowrouter/. kadira-flow-router + cd kadira-flow-router + git pull + cd .. + fi + cd kadira-flow-router + git checkout $FLOW_ROUTER_COMMIT -b $FLOW_ROUTER_COMMIT + cd .. + if [ ! -d /repos/meteoruseraccounts ]; then + su -c "git clone --depth 1 -b master $METEOR_USERACCOUNTS_REPO meteor-useraccounts-core" - wekan + else + mkdir meteor-useraccounts-core + cp -r -p /repos/meteoruseraccounts/. meteor-useraccounts-core + cd meteor-useraccounts-core + git pull + cd .. + fi + cd meteor-useraccounts-core + git checkout $METEOR_USERACCOUNTS_COMMIT -b $METEOR_USERACCOUNTS_COMMIT + cd .. + if [ ! -f $WEKAN_DIR/.meteor/packages/meteor-useraccounts-core/package.js ]; then + echo $"File not found: $WEKAN_DIR/.meteor/packages/meteor-useraccounts-core/package.js" + exit 7289529 + fi + sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' $WEKAN_DIR/.meteor/packages/meteor-useraccounts-core/package.js + cd $WEKAN_DIR/.meteor + su -c "$WEKAN_DIR/.meteor/meteor -- help" - wekan + + # Build app + if [ ! -d $WEKAN_DIR/app ]; then + echo $'No app subdirectory found' + exit 294569 + fi + cd $WEKAN_DIR/app + su -c "$WEKAN_DIR/.meteor/meteor add standard-minifier-js" - wekan + su -c "$WEKAN_DIR/.meteor/meteor npm install" - wekan + su -c "$WEKAN_DIR/.meteor/meteor build --directory $WEKAN_DIR/app_build" - wekan + cp $WEKAN_DIR/app/fix-download-unicode/cfs_access-point.txt $WEKAN_DIR/app_build/bundle/programs/server/packages/cfs_access-point.js + chown wekan:wekan $WEKAN_DIR/app_build/bundle/programs/server/packages/cfs_access-point.js + sed -i "s|build\/Release\/bson|browser_build\/bson|g" $WEKAN_DIR/app_build/bundle/programs/server/npm/node_modules/meteor/cfs_gridfs/node_modules/mongodb/node_modules/bson/ext/index.js + if [ ! -d $WEKAN_DIR/app_build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt ]; then + echo $"No subdirectory found: $WEKAN_DIR/app_build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt" + exit 479832 + fi + cd $WEKAN_DIR/app_build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt + su -c 'rm -rf node_modules/bcrypt' - wekan + su -c 'npm install bcrypt' - wekan + cd $WEKAN_DIR/app_build/bundle/programs/server/ + su -c 'npm install' - wekan + mv $WEKAN_DIR/app_build/bundle ../build + + if [ ! -f $WEKAN_DIR/build/main.js ]; then + echo $'main.js not found' + exit 7828252 + fi + + # Cleanup + rm -R $WEKAN_DIR/.meteor + rm -R $WEKAN_DIR/app + rm -R $WEKAN_DIR/app_build + + chown -R wekan:wekan $WEKAN_DIR + + function_check install_mariadb + install_mariadb + + function_check get_mariadb_password + get_mariadb_password + + function_check wekan_create_database + wekan_create_database + + # daemon + echo '[Unit]' > /etc/systemd/system/wekan.service + echo 'Description=Wekan' >> /etc/systemd/system/wekan.service + echo 'After=syslog.target' >> /etc/systemd/system/wekan.service + echo 'After=network.target' >> /etc/systemd/system/wekan.service + echo '' >> /etc/systemd/system/wekan.service + echo '[Service]' >> /etc/systemd/system/wekan.service + echo 'User=wekan' >> /etc/systemd/system/wekan.service + echo 'Group=wekan' >> /etc/systemd/system/wekan.service + echo "WorkingDirectory=$WEKAN_DIR" >> /etc/systemd/system/wekan.service + echo "ExecStart=/usr/local/bin/node $WEKAN_DIR/build/main.js" >> /etc/systemd/system/wekan.service + echo 'Environment=PATH=/usr/bin:/usr/local/bin' >> /etc/systemd/system/wekan.service + echo 'Environment=NODE_ENV=production' >> /etc/systemd/system/wekan.service + echo 'Restart=on-failure' >> /etc/systemd/system/wekan.service + echo '' >> /etc/systemd/system/wekan.service + echo '[Install]' >> /etc/systemd/system/wekan.service + echo 'WantedBy=multi-user.target' >> /etc/systemd/system/wekan.service + systemctl enable wekan.service + systemctl daemon-reload + systemctl start wekan.service + + systemctl restart nginx + + set_completion_param "wekan domain" "$WEKAN_DOMAIN_NAME" + + APP_INSTALLED=1 +} + +# NOTE: deliberately there is no "exit 0" diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise index 80853e1e..2d03fab2 100755 --- a/src/freedombone-image-customise +++ b/src/freedombone-image-customise @@ -1274,6 +1274,11 @@ function image_preinstall_repos { git clone $TOXID_REPO $rootdir/repos/toxid git clone $TOXIC_REPO $rootdir/repos/toxic git clone $TURTL_REPO $rootdir/repos/turtl + git clone $KANBOARD_REPO $rootdir/repos/kanboard + #git clone $WEKAN_REPO $rootdir/repos/wekan + #git clone $FLOW_ROUTER_REPO $rootdir/repos/flowrouter + #git clone $METEOR_USERACCOUNTS_REPO $rootdir/repos/meteoruseraccounts + #git clone $METEOR_REPO $rootdir/repos/meteor #git clone $ZERONET_REPO $rootdir/repos/zeronet #git clone $QTOX_REPO $rootdir/repos/qtox } diff --git a/src/freedombone-utils-meteor b/src/freedombone-utils-meteor new file mode 100755 index 00000000..1b14bea6 --- /dev/null +++ b/src/freedombone-utils-meteor @@ -0,0 +1,220 @@ +#!/bin/bash +# +# .---. . . +# | | | +# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. +# | | (.-' (.-' ( | ( )| | | | )( )| | (.-' +# ' ' --' --' -' - -' ' ' -' -' -' ' - --' +# +# Freedom in the Cloud +# +# Functions for installing meteor +# See meteor.com +# +# License +# ======= +# +# Copyright (C) 2017 Bob Mottram +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +METEOR_RELEASE='1.4.4.1' +METEOR_REPO="https://github.com/meteor/meteor" +METEOR_COMMIT='b52c6587d7542c0f27481a3bee8c65be06068ac1' +METEOR_USERACCOUNTS_REPO="git://github.com/meteor-useraccounts/core.git" +METEOR_USERACCOUNTS_COMMIT='2e8986813b51f321f908d2f6211f6f81f76cd627' + +function meteor_cleanUp { + rm -rf "$TARBALL_FILE" + rm -rf "$INSTALL_TMPDIR" +} + +function install_meteor_script { + meteor_dir=$1 + + if [ ! $meteor_dir ]; then + echo $'No meteor install directory specified' + exit 692025 + fi + + if [ ! -d $meteor_dir ]; then + echo $'Meteor install directory not found' + exit 845382 + fi + + if [[ "$(arch)" == "arm"* ]]; then + echo 'meteor does not support ARM' + exit 8362952 + fi + if [[ "$(arch)" == "i386" || "$(arch)" == "x86_32" ]]; then + PLATFORM="os.linux.x86_32" + else + PLATFORM="os.linux.x86_64" + fi + + RELEASE="$METEOR_RELEASE" + + DIR_PREFIX="/usr/local" + + TARBALL_URL="$https://meteorinstall-4168.kxcdn.com/packages-bootstrap/${RELEASE}/meteor-bootstrap-${PLATFORM}.tar.gz" + INSTALL_TMPDIR="$meteor_dir/.meteor-install-tmp" + TARBALL_FILE="$meteor_dir/.meteor-tarball-tmp" + + # Remove temporary files now in case they exist. + meteor_cleanUp + + if [ -d $INSTALL_TMPDIR ]; then + rm -rf $INSTALL_TMPDIR + fi + mkdir "$INSTALL_TMPDIR" + + if [ ! -f ${TARBALL_FILE} ]; then + echo "Downloading Meteor distribution" + # keep trying to curl the file until it works (resuming where possible) + MAX_ATTEMPTS=10 + RETRY_DELAY_SECS=5 + set +e + ATTEMPTS=0 + while [ $ATTEMPTS -lt $MAX_ATTEMPTS ] + do + ATTEMPTS=$((ATTEMPTS + 1)) + + curl --progress-bar --fail --continue-at - \ + "$TARBALL_URL" --output "$TARBALL_FILE" + + if [ $? -eq 0 ] + then + break + fi + + echo "Retrying download in $RETRY_DELAY_SECS seconds..." + sleep $RETRY_DELAY_SECS + done + fi + + if [ ! -f ${TARBALL_FILE} ]; then + echo $'meteor tarball could not be downloaded' + exit 7272452 + fi + + tar -xzf "$TARBALL_FILE" -C "$INSTALL_TMPDIR" -o + + if [ ! -f ${INSTALL_TMPDIR}/.meteor/meteor ]; then + echo $'tarball not extracted' + exit 693252 + fi + + mv "${INSTALL_TMPDIR}/.meteor" "$meteor_dir" + + meteor_cleanUp + + echo '' + echo "Meteor ${RELEASE} has been installed in $meteor_dir/.meteor" + + METEOR_SYMLINK_TARGET="$(readlink "$meteor_dir/.meteor/meteor")" + METEOR_TOOL_DIRECTORY="$(dirname "$METEOR_SYMLINK_TARGET")" + LAUNCHER="$meteor_dir/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor" + + if cp "$LAUNCHER" "$DIR_PREFIX/bin/meteor" >/dev/null 2>&1; then + echo "Writing a launcher script to $DIR_PREFIX/bin/meteor for your convenience." + cat <<"EOF" + +To get started fast: + + $ meteor create ~/my_cool_app + $ cd ~/my_cool_app + $ meteor + +Or see the docs at: + + docs.meteor.com + +EOF + elif type sudo >/dev/null 2>&1; then + echo "Writing a launcher script to $DIR_PREFIX/bin/meteor for your convenience." + echo "This may prompt for your password." + + # New macs (10.9+) don't ship with /usr/local, however it is still in + # the default PATH. We still install there, we just need to create the + # directory first. + # XXX this means that we can run sudo too many times. we should never + # run it more than once if it fails the first time + if [ ! -d "$DIR_PREFIX/bin" ] ; then + sudo mkdir -m 755 "$DIR_PREFIX" || true + sudo mkdir -m 755 "$DIR_PREFIX/bin" || true + fi + + if sudo cp "$LAUNCHER" "$DIR_PREFIX/bin/meteor"; then + cat <<"EOF" + +To get started fast: + + $ meteor create ~/my_cool_app + $ cd ~/my_cool_app + $ meteor + +Or see the docs at: + + docs.meteor.com + +EOF + else + cat < - + @@ -248,6 +248,14 @@ for the JavaScript code in this tag.

CryptPad

+
+ +
+

cryptpad.jpg +

+
+
+

This is similar to EtherPad but with better security and more document types which can be collaboratively edited in real time. It includes not just text editing but also creating presentations, voting and editing source code.

@@ -264,9 +272,9 @@ Enabling someone to edit a document is as simple as sending them the URL via a c Documents are stored locally within the browser of each user and the server just acts as a coordinator. No documents are stored on the server.

-
-

Installation

-
+
+

Installation

+

Log into your system with:

diff --git a/website/EN/app_kanboard.html b/website/EN/app_kanboard.html new file mode 100644 index 00000000..4a3b1f55 --- /dev/null +++ b/website/EN/app_kanboard.html @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + +
+ +
+
+
+ +
+

logo.png +

+
+
+ +
+

KanBoard

+
+ +

+Kanbans are one way of managing projects. They're traditionally used in businesses but can also be useful for personal TODO lists or within open source or DIY projects. If you have a list of things which need to be done and want to keep track of progress then this provides a way to do that. +

+ +
+

Installation

+
+

+Log into your system with: +

+ +
+
ssh myusername@mydomain -p 2222
+
+
+ +

+Using cursor keys, space bar and Enter key select Administrator controls and type in your password. +

+ +

+Select Add/Remove Apps then kanboard. You will then be asked for a domain name and if you are using FreeDNS also the code for the domain which can be found under Dynamic DNS on the FreeDNS site (the random string from "quick cron example" which appears after update.php? and before >>). For more details on obtaining a domain and making it accessible via dynamic DNS see the FAQ. Typically the domain name you use will be a subdomain, such as kanban.mydomainname.net. It will need to be a domain which you have bought somewhere and own and not one of the FreeDNS subdomains, otherwise you won't be able to get a SSL/TLS certificate for it. +

+ +

+After the install has completed go to Security settings and select Create a new Let's Encrypt certificate and enter the domain name that you are using for KanBoard. If you're using the "onion only" version of the system then you don't need to do this. If the certificate is obtained successfully then you will see a congratulations message. +

+
+
+ +
+

Initial setup

+
+

+If you have just obtained a Lets Encrypt certificate as above then go to About on the administrator control panel and you should see your KanBoard domain listed there along with an onion address. You can then navigate to your site in a browser. +

+ +

+The default login is username "admin" and password "admin". Obviously the first thing you'll need to do is log in and change the password, which can be done by going to "My Profile" on the drop down list on the right hand side. +

+ +

+For more details of how to use KanBoard see the documentation here. +

+
+
+
+
+ + + + +
+ + diff --git a/website/EN/apps.html b/website/EN/apps.html index b7a386b3..15168e14 100644 --- a/website/EN/apps.html +++ b/website/EN/apps.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + @@ -264,9 +264,9 @@ The base install of the system just contains an email server and Mutt client, bu
-
-

CryptPad

-
+
+

CryptPad

+

Collaborate on editing documents, presentations and source code, or vote on things. All with a good level of security.

@@ -276,9 +276,9 @@ Collaborate on editing documents, presentations and source code, or vote on thin

-
-

DLNA

-
+
+

DLNA

+

Enables you to use the system as a music server which any DLNA compatible devices can connect to within your home network.

@@ -288,9 +288,9 @@ Enables you to use the system as a music server which any DLNA compatible device

-
-

Dokuwiki

-
+
+

Dokuwiki

+

A databaseless wiki system.

@@ -300,9 +300,9 @@ A databaseless wiki system.

-
-

Emacs

-
+
+

Emacs

+

If you use the Mutt client to read your email then this will set it up to use emacs for composing new mail.

@@ -312,9 +312,9 @@ If you use the Mutt client to read your email then this will set it up to use em

-
-

Etherpad

-
+
+

Etherpad

+

Collaborate on creating documents in real time. Maybe you're planning a holiday with other family members or creating documentation for a Free Software project along with other volunteers. Etherpad is hard to beat for simplicity and speed. Only users of the system will be able to access it.

@@ -324,9 +324,9 @@ Collaborate on creating documents in real time. Maybe you're planning a holiday

-
-

Friendica

-
+
+

Friendica

+

Federated social network system.

@@ -336,9 +336,9 @@ Federated social network system.

-
-

Ghost

-
+
+

Ghost

+

Modern looking blogging system.

@@ -348,9 +348,9 @@ Modern looking blogging system.

-
-

GNU Social

-
+
+

GNU Social

+

Federated social network. You can "remote follow" other users within the GNU Social federation.

@@ -360,9 +360,9 @@ Federated social network. You can "remote follow" other users within the

-
-

Gogs

-
+
+

Gogs

+

Lightweight git project hosting system. You can mirror projects from Github, or if Github turns evil then just host your own projects while retaining the familiar fork-and-pull workflow. If you can use Github then you can also use Gogs.

@@ -372,9 +372,9 @@ Lightweight git project hosting system. You can mirror projects from Github, or

-
-

HTMLy

-
+
+

HTMLy

+

Databaseless blogging system. Quite simple and with a markdown-like format.

@@ -384,9 +384,9 @@ Databaseless blogging system. Quite simple and with a markdown-like format.

-
-

Hubzilla

-
+
+

Hubzilla

+

Web publishing platform with social network like features and good privacy controls so that it's possible to specify who can see which content. Includes photo albums, calendar, wiki and file storage.

@@ -396,9 +396,9 @@ Web publishing platform with social network like features and good privacy contr

-
-

IRC Server (ngirc)

-
+
+

IRC Server (ngirc)

+

Run your own IRC chat channel which can be secured with a password and accessible via an onion address. A bouncer is included so that you can receive messages sent while you were offline. Works with Hexchat and other popular clients.

@@ -408,18 +408,30 @@ Run your own IRC chat channel which can be secured with a password and accessibl

-
-

Jitsi Meet

-
+
+

Jitsi Meet

+

Experimental WebRTC video conferencing system, similar to Google Hangouts. This may not be fully functional, but is hoped to be in the near future.

-
-

Koel

-
+
+

KanBoard

+
+

+A simple kanban system for managing projects or TODO lists. +

+ +

+How to use it +

+
+
+
+

Koel

+

Access your music collection from any internet connected device.

@@ -429,9 +441,9 @@ Access your music collection from any internet connected device.

-
-

Lychee

-
+
+

Lychee

+

Make your photo albums available on the web.

@@ -441,9 +453,9 @@ Make your photo albums available on the web.

-
-

Mailpile

-
+
+

Mailpile

+

Modern email client which supports GPG encryption.

@@ -453,9 +465,9 @@ Modern email client which supports GPG encryption.

-
-

Matrix

-
+
+

Matrix

+

Multi-user chat with some security and moderation controls.

@@ -465,9 +477,9 @@ Multi-user chat with some security and moderation controls.

-
-

Mediagoblin

-
+
+

Mediagoblin

+

Publicly host video and audio files so that you don't need to use YouTube/Vimeo/etc.

@@ -477,9 +489,9 @@ Publicly host video and audio files so that you don't need to use YouTube/Vimeo/

-
-

Mumble

-
+
+

Mumble

+

The popular VoIP and text chat system. Say goodbye to old-fashioned telephony conferences with silly dial codes. Also works well on mobile.

@@ -489,9 +501,9 @@ The popular VoIP and text chat system. Say goodbye to old-fashioned telephony co

-
-

NextCloud

-
+
+

NextCloud

+

Store files on your server and sync them with laptops or mobile devices. Includes many plugins including videoconferencing and collaborative document editing.

@@ -501,9 +513,9 @@ Store files on your server and sync them with laptops or mobile devices. Include

-
-

PI-Hole

-
+
+

PI-Hole

+

The black hole for web adverts. Block adverts at the domain name level within your local network. It can significantly reduce bandwidth, speed up page load times and protect your systems from being tracked by spyware.

@@ -513,9 +525,9 @@ The black hole for web adverts. Block adverts at the domain name level within yo

-
-

PostActiv

-
+
+

PostActiv

+

An alternative federated social networking system compatible with GNU Social. It includes some optimisations and fixes currently not available within the main GNU Social project.

@@ -525,9 +537,9 @@ An alternative federated social networking system compatible with GNU Social. It

-
-

Profanity

-
+
+

Profanity

+

A shell based XMPP client which you can run on the Freedombone server via ssh.

@@ -537,9 +549,9 @@ A shell based XMPP client which you can run on the Freedombone server via ssh.

-
-

Riot Web

-
+
+

Riot Web

+

A browser based user interface for the Matrix federated communications system, including WebRTC audio and video chat.

@@ -549,9 +561,9 @@ A browser based user interface for the Matrix federated communications system, i

-
-

SearX

-
+
+

SearX

+

A metasearch engine for customised and private web searches.

@@ -561,9 +573,9 @@ A metasearch engine for customised and private web searches.

-
-

tt-rss

-
+
+

tt-rss

+

Private RSS reader. Pulls in RSS/Atom feeds via Tor and is only accessible via an onion address. Have "the right to read" without the Surveillance State knowing what you're reading. Also available with a user interface suitable for viewing on mobile devices via a browser such as OrFox.

@@ -573,9 +585,9 @@ Private RSS reader. Pulls in RSS/Atom feeds via Tor and is only accessible via a

-
-

Syncthing

-
+
+

Syncthing

+

Possibly the best way to synchronise files across all of your devices. Once it has been set up it "just works" with no user intervention needed.

@@ -585,9 +597,9 @@ Possibly the best way to synchronise files across all of your devices. Once it h

-
-

Tahoe-LAFS

-
+
+

Tahoe-LAFS

+

Robust and encrypted storage of files on one or more server.

@@ -597,9 +609,9 @@ Robust and encrypted storage of files on one or more server.

-
-

Tox

-
+
+

Tox

+

Client and bootstrap node for the Tox chat/VoIP system.

@@ -609,9 +621,9 @@ Client and bootstrap node for the Tox chat/VoIP system.

-
-

Turtl

-
+
+

Turtl

+

A system for privately creating and sharing notes and images, similar to Evernote but without the spying.

@@ -621,18 +633,18 @@ A system for privately creating and sharing notes and images, similar to Evernot

-
-

Vim

-
+
+

Vim

+

If you use the Mutt client to read your email then this will set it up to use vim for composing new mail.

-
-

XMPP

-
+
+

XMPP

+

Chat server which can be used together with client such as Gajim or Conversations to provide end-to-end content security and also onion routed metadata security. Includes advanced features such as client state notification to save battery power on your mobile devices, support for seamless roaming between networks and message carbons so that you can receive the same messages while being simultaneously logged in to your account on more than one device.