From 812f5de7f2d2f6025e0b4923c25f1a367f1463a6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 10:13:58 +0100 Subject: [PATCH 01/15] Beginning of wekan --- src/freedombone-app-gogs | 4 +- src/freedombone-app-wekan | 494 ++++++++++++++++++++++++++++++++ src/freedombone-image-customise | 4 + src/freedombone-utils-meteor | 220 ++++++++++++++ 4 files changed, 720 insertions(+), 2 deletions(-) create mode 100755 src/freedombone-app-wekan create mode 100755 src/freedombone-utils-meteor 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-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..c31ce669 100755 --- a/src/freedombone-image-customise +++ b/src/freedombone-image-customise @@ -1274,6 +1274,10 @@ 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 $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 < Date: Tue, 25 Jul 2017 10:16:19 +0100 Subject: [PATCH 02/15] Update profanity commits --- src/freedombone-app-profanity | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/freedombone-app-profanity b/src/freedombone-app-profanity index 38570412..ff368f2c 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 From f748e4ebcc99a03a4b3f45f061287f25adc792a9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 10:44:21 +0100 Subject: [PATCH 03/15] Don't set profanity gpg key by default so that screen refresh bug doesn't happen --- src/freedombone-app-profanity | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/freedombone-app-profanity b/src/freedombone-app-profanity index ff368f2c..6ad9bdae 100755 --- a/src/freedombone-app-profanity +++ b/src/freedombone-app-profanity @@ -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 From 21d1f73df6759872d07d4ea504ceca1d1bf9f173 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 21:39:27 +0100 Subject: [PATCH 04/15] kanboard app --- src/freedombone-app-kanboard | 575 ++++++++++++++++++++++++++++++++ src/freedombone-image-customise | 9 +- 2 files changed, 580 insertions(+), 4 deletions(-) create mode 100755 src/freedombone-app-kanboard diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard new file mode 100755 index 00000000..5816f960 --- /dev/null +++ b/src/freedombone-app-kanboard @@ -0,0 +1,575 @@ +#!/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. The background image URL can be left blank.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt:" 16 65 2 \ + $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ + $"Code:" 4 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 4 25 33 255 \ + 2> $data + else + dialog --backtitle $"Freedombone Configuration" \ + --title $"KanBoard Configuration" \ + --form $"\nPlease enter your KanBoard details. The background image URL can be left blank.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt:" 16 65 2 \ + $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 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 4p) + 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 + + 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-image-customise b/src/freedombone-image-customise index c31ce669..2d03fab2 100755 --- a/src/freedombone-image-customise +++ b/src/freedombone-image-customise @@ -1274,10 +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 $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 $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 } From ae396b0e631ae896fc84162a70fc5e0d92915cfe Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 21:42:08 +0100 Subject: [PATCH 05/15] code index --- src/freedombone-app-kanboard | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard index 5816f960..137ac752 100755 --- a/src/freedombone-app-kanboard +++ b/src/freedombone-app-kanboard @@ -89,7 +89,7 @@ function install_interactive_kanboard { --title $"KanBoard Configuration" \ --form $"\nPlease enter your KanBoard details. The background image URL can be left blank.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt:" 16 65 2 \ $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ - $"Code:" 4 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 4 25 33 255 \ + $"Code:" 2 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 2 25 33 255 \ 2> $data else dialog --backtitle $"Freedombone Configuration" \ @@ -115,7 +115,7 @@ function install_interactive_kanboard { 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 4p) + KANBOARD_CODE=$(cat $data | sed -n 2p) validate_freedns_code "$KANBOARD_CODE" if [ ! $VALID_CODE ]; then KANBOARD_DOMAIN_NAME= From 59455534adb827e85cff7a6b7a0e61a84df49c34 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 21:46:13 +0100 Subject: [PATCH 06/15] No background image --- src/freedombone-app-kanboard | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard index 137ac752..cf534a96 100755 --- a/src/freedombone-app-kanboard +++ b/src/freedombone-app-kanboard @@ -87,14 +87,14 @@ function install_interactive_kanboard { if [[ $DDNS_PROVIDER == "default@freedns.afraid.org" ]]; then dialog --backtitle $"Freedombone Configuration" \ --title $"KanBoard Configuration" \ - --form $"\nPlease enter your KanBoard details. The background image URL can be left blank.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt:" 16 65 2 \ + --form $"\nPlease enter your KanBoard details.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt." 13 65 2 \ $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ $"Code:" 2 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 2 25 33 255 \ 2> $data else dialog --backtitle $"Freedombone Configuration" \ --title $"KanBoard Configuration" \ - --form $"\nPlease enter your KanBoard details. The background image URL can be left blank.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt:" 16 65 2 \ + --form $"\nPlease enter your KanBoard details.\n\nIMPORTANT: This should be a domain name which is supported by Let's Encrypt." 13 65 2 \ $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ 2> $data fi From dc4f99a74060e54b8253353ba5a78a0f56012746 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 21:51:48 +0100 Subject: [PATCH 07/15] Dialog proportions --- src/freedombone-app-kanboard | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard index cf534a96..2905994e 100755 --- a/src/freedombone-app-kanboard +++ b/src/freedombone-app-kanboard @@ -87,15 +87,15 @@ function install_interactive_kanboard { 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 65 2 \ - $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ - $"Code:" 2 1 "$(grep 'KANBOARD_CODE' temp.cfg | awk -F '=' '{print $2}')" 2 25 33 255 \ + --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 65 2 \ - $"Domain:" 1 1 "$(grep 'KANBOARD_DOMAIN_NAME' temp.cfg | awk -F '=' '{print $2}')" 1 25 33 40 \ + --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=$? From dd04199b4a25cfdd3d8473d241ccea4dabab1f34 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 22:11:03 +0100 Subject: [PATCH 08/15] Install composer --- src/freedombone-app-kanboard | 4 ++++ src/freedombone-app-koel | 14 +------------- src/freedombone-app-movim | 11 ++--------- src/freedombone-utils-web | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/freedombone-app-kanboard b/src/freedombone-app-kanboard index 2905994e..a33da4ef 100755 --- a/src/freedombone-app-kanboard +++ b/src/freedombone-app-kanboard @@ -560,6 +560,10 @@ function install_kanboard { 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 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-utils-web b/src/freedombone-utils-web index 27a29748..242e8a90 100755 --- a/src/freedombone-utils-web +++ b/src/freedombone-utils-web @@ -917,4 +917,20 @@ function create_default_web_site { fi } +function install_composer { + # curl -sS https://getcomposer.org/installer | php + if [ -f ~/${PROJECT_NAME}/image_build/composer_install ]; then + cat ~/${PROJECT_NAME}/image_build/composer_install | php + else + if [ -f /home/$MY_USERNAME/${PROJECT_NAME}/image_build/composer_install ]; then + cat /home/$MY_USERNAME/${PROJECT_NAME}/image_build/composer_install | php + fi + fi + php composer.phar install + if [ ! "$?" = "0" ]; then + echo $'Unable to run composer install' + exit 7252198 + fi +} + # NOTE: deliberately no exit 0 From 351c8fa5b61346c26332f3ea48ed637a623a9658 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 25 Jul 2017 23:26:08 +0100 Subject: [PATCH 09/15] kanboard documentation --- doc/EN/app_kanboard.org | 39 +++++ doc/EN/apps.org | 4 + website/EN/app_kanboard.html | 323 +++++++++++++++++++++++++++++++++++ website/EN/apps.html | 206 +++++++++++----------- 4 files changed, 475 insertions(+), 97 deletions(-) create mode 100644 doc/EN/app_kanboard.org create mode 100644 website/EN/app_kanboard.html 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/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.

From 04bc4393f0fef344295e341e46864329281382e1 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 14:35:30 +0100 Subject: [PATCH 10/15] Bump cryptpad commit --- src/freedombone-app-cryptpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad index 91e5104a..4df586c6 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) From 7a496ecb40ab3abf195e252f598179799b2ab4e9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 14:41:14 +0100 Subject: [PATCH 11/15] Install after cryptpad upgrade --- src/freedombone-app-cryptpad | 1 + 1 file changed, 1 insertion(+) diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad index 4df586c6..a3c7b5a7 100755 --- a/src/freedombone-app-cryptpad +++ b/src/freedombone-app-cryptpad @@ -89,6 +89,7 @@ function upgrade_cryptpad { set_repo_commit $CRYPTPAD_DIR "cryptpad commit" "$CRYPTPAD_COMMIT" $CRYPTPAD_REPO cd $CRYPTPAD_DIR + npm install systemctl start cryptpad } From b7720972cd9fdf2418ead9421e808ae6791ce09c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 14:50:12 +0100 Subject: [PATCH 12/15] Needs bower install --- src/freedombone-app-cryptpad | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad index a3c7b5a7..bb70809e 100755 --- a/src/freedombone-app-cryptpad +++ b/src/freedombone-app-cryptpad @@ -90,6 +90,8 @@ function upgrade_cryptpad { cd $CRYPTPAD_DIR npm install + su -c 'bower install' - cryptpad + chown -R cryptpad:cryptpad $CRYPTPAD_DIR systemctl start cryptpad } From 29bae785aab7bd7435b725f796c9e8fd4e5b4032 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 14:57:26 +0100 Subject: [PATCH 13/15] Upgrade sequence --- src/freedombone-app-cryptpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad index bb70809e..4e32af1a 100755 --- a/src/freedombone-app-cryptpad +++ b/src/freedombone-app-cryptpad @@ -90,8 +90,8 @@ function upgrade_cryptpad { cd $CRYPTPAD_DIR npm install - su -c 'bower install' - cryptpad chown -R cryptpad:cryptpad $CRYPTPAD_DIR + su -c 'bower install' - cryptpad systemctl start cryptpad } From 2469051cd8d40dc77e8d73804b809503d756b114 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 15:17:11 +0100 Subject: [PATCH 14/15] Cryptpad screenshot --- doc/EN/app_cryptpad.org | 4 ++++ img/cryptpad.jpg | Bin 0 -> 29474 bytes website/EN/app_cryptpad.html | 16 ++++++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 img/cryptpad.jpg 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/img/cryptpad.jpg b/img/cryptpad.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2855f6bd205de6d5e3f031c9c368499e89978a42 GIT binary patch literal 29474 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 D#}@pl literal 0 HcmV?d00001 diff --git a/website/EN/app_cryptpad.html b/website/EN/app_cryptpad.html index 095bbb51..f0564961 100644 --- a/website/EN/app_cryptpad.html +++ b/website/EN/app_cryptpad.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + @@ -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:

From f0998ddcbc09e98d32068bb9d717923777fcf5c1 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 27 Jul 2017 15:20:33 +0100 Subject: [PATCH 15/15] Fix typo --- img/cryptpad.jpg | Bin 29474 -> 32768 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/img/cryptpad.jpg b/img/cryptpad.jpg index 2855f6bd205de6d5e3f031c9c368499e89978a42..e3669e189cf990bd1825051453f8f7f84091a47f 100644 GIT binary patch literal 32768 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 sdI}|CL!L{088n`N9)C_<8 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 literal 29474 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 D#}@pl