From 0ee275371735ab3eabf91cad8a9f25634523ab5b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 10:09:18 +0100
Subject: [PATCH 01/31] Retire the goog, except as the lastest resort. You know
what I'm sayin
---
src/freedombone-app-pihole | 10 +++++++---
src/freedombone-image | 4 ++--
src/freedombone-image-makefile | 4 ++--
src/freedombone-utils-dns | 4 ++--
4 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/src/freedombone-app-pihole b/src/freedombone-app-pihole
index 7b9a8c6b..23f43a80 100755
--- a/src/freedombone-app-pihole
+++ b/src/freedombone-app-pihole
@@ -135,7 +135,7 @@ function pihole_change_upstream_dns {
data=$(tempfile 2>/dev/null)
trap "rm -f $data" 0 1 2 5 15
dialog --backtitle $"Ad Blocker Upstream DNS" \
- --radiolist $"Pick a domain name service (DNS):" 25 50 16 \
+ --radiolist $"Pick a domain name service (DNS):" 26 50 17 \
1 $"Digital Courage" on \
2 $"German Privacy Foundation 1" off \
3 $"German Privacy Foundation 2" off \
@@ -151,7 +151,8 @@ function pihole_change_upstream_dns {
13 $"PowerNS" off \
14 $"ValiDOM" off \
15 $"Freie Unzensierte" off \
- 16 $"Google" off 2> $data
+ 16 $"DNS.Watch" off \
+ 17 $"Google" off 2> $data
sel=$?
case $sel in
1) exit 1;;
@@ -203,7 +204,10 @@ function pihole_change_upstream_dns {
15) PIHOLE_DNS1='85.25.149.144'
PIHOLE_DNS2='87.106.37.196'
;;
- 16) PIHOLE_DNS1='8.8.8.8'
+ 16) PIHOLE_DNS1='84.200.69.80'
+ PIHOLE_DNS2='84.200.70.40'
+ ;;
+ 17) PIHOLE_DNS1='8.8.8.8'
PIHOLE_DNS2='4.4.4.4'
;;
255) exit 1;;
diff --git a/src/freedombone-image b/src/freedombone-image
index f5b4fc99..17a57ee8 100755
--- a/src/freedombone-image
+++ b/src/freedombone-image
@@ -87,8 +87,8 @@ NAMESERVER1='213.73.91.35'
NAMESERVER2='85.214.20.141'
NAMESERVER3='213.73.91.35'
NAMESERVER4='85.214.73.63'
-NAMESERVER5='8.8.8.8'
-NAMESERVER6='4.4.4.4'
+NAMESERVER5='84.200.69.80'
+NAMESERVER6='84.200.70.40'
# An optional freedombone configuration file
CONFIG_FILENAME=
diff --git a/src/freedombone-image-makefile b/src/freedombone-image-makefile
index a8cbe02b..59729f4e 100755
--- a/src/freedombone-image-makefile
+++ b/src/freedombone-image-makefile
@@ -64,8 +64,8 @@ NAMESERVER1 ?= '213.73.91.35'
NAMESERVER2 ?= '85.214.20.141'
NAMESERVER3 ?= '213.73.91.35'
NAMESERVER4 ?= '85.214.73.63'
-NAMESERVER5 ?= '8.8.8.8'
-NAMESERVER6 ?= '4.4.4.4'
+NAMESERVER5 ?= '84.200.69.80'
+NAMESERVER6 ?= '84.200.70.40'
# Using taskset to pin build process to single core. This is a
# workaround for a qemu-user-static issue that causes builds to
diff --git a/src/freedombone-utils-dns b/src/freedombone-utils-dns
index 31a30ab7..7c5c5b84 100755
--- a/src/freedombone-utils-dns
+++ b/src/freedombone-utils-dns
@@ -33,8 +33,8 @@ NAMESERVER1='213.73.91.35'
NAMESERVER2='85.214.20.141'
NAMESERVER3='213.73.91.35'
NAMESERVER4='85.214.73.63'
-NAMESERVER5='8.8.8.8'
-NAMESERVER6='4.4.4.4'
+NAMESERVER5='84.200.69.80'
+NAMESERVER6='84.200.70.40'
# parameters used when adding a new domain
DDNS_PROVIDER="default@freedns.afraid.org"
From b584bed3a59f03a64328f5cc2509d4a8cd4ed51a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 10:18:39 +0100
Subject: [PATCH 02/31] Another DNS option, for added diversity
---
src/freedombone-app-pihole | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/freedombone-app-pihole b/src/freedombone-app-pihole
index 23f43a80..437a1255 100755
--- a/src/freedombone-app-pihole
+++ b/src/freedombone-app-pihole
@@ -135,7 +135,7 @@ function pihole_change_upstream_dns {
data=$(tempfile 2>/dev/null)
trap "rm -f $data" 0 1 2 5 15
dialog --backtitle $"Ad Blocker Upstream DNS" \
- --radiolist $"Pick a domain name service (DNS):" 26 50 17 \
+ --radiolist $"Pick a domain name service (DNS):" 27 50 18 \
1 $"Digital Courage" on \
2 $"German Privacy Foundation 1" off \
3 $"German Privacy Foundation 2" off \
@@ -152,7 +152,8 @@ function pihole_change_upstream_dns {
14 $"ValiDOM" off \
15 $"Freie Unzensierte" off \
16 $"DNS.Watch" off \
- 17 $"Google" off 2> $data
+ 17 $"uncensoreddns.org" off \
+ 18 $"Google" off 2> $data
sel=$?
case $sel in
1) exit 1;;
@@ -207,7 +208,10 @@ function pihole_change_upstream_dns {
16) PIHOLE_DNS1='84.200.69.80'
PIHOLE_DNS2='84.200.70.40'
;;
- 17) PIHOLE_DNS1='8.8.8.8'
+ 17) PIHOLE_DNS1='91.239.100.100'
+ PIHOLE_DNS2='89.233.43.71'
+ ;;
+ 18) PIHOLE_DNS1='8.8.8.8'
PIHOLE_DNS2='4.4.4.4'
;;
255) exit 1;;
From 45acf8738a6df0d37922ee588a43b6533a393c61 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 10:25:23 +0100
Subject: [PATCH 03/31] Add a scary warning if you choose Google DNS
---
src/freedombone-app-pihole | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/freedombone-app-pihole b/src/freedombone-app-pihole
index 437a1255..fa095ae3 100755
--- a/src/freedombone-app-pihole
+++ b/src/freedombone-app-pihole
@@ -213,6 +213,8 @@ function pihole_change_upstream_dns {
;;
18) PIHOLE_DNS1='8.8.8.8'
PIHOLE_DNS2='4.4.4.4'
+ dialog --title $"WARNING" \
+ --msgbox $"\nGoogle's main purpose for providing DNS resolvers is to spy upon people and know which sites they are visiting.\n\nThis is something to consider, and you should only really be using Google DNS as a last resort if other resolvers are unavailable." 12 60
;;
255) exit 1;;
esac
From f5ddd9ce480732299fc95d3a9e5e3c77ae56505a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 10:51:49 +0100
Subject: [PATCH 04/31] Another dns resolver
---
src/freedombone-app-pihole | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/freedombone-app-pihole b/src/freedombone-app-pihole
index fa095ae3..0ce715a0 100755
--- a/src/freedombone-app-pihole
+++ b/src/freedombone-app-pihole
@@ -135,7 +135,7 @@ function pihole_change_upstream_dns {
data=$(tempfile 2>/dev/null)
trap "rm -f $data" 0 1 2 5 15
dialog --backtitle $"Ad Blocker Upstream DNS" \
- --radiolist $"Pick a domain name service (DNS):" 27 50 18 \
+ --radiolist $"Pick a domain name service (DNS):" 28 50 19 \
1 $"Digital Courage" on \
2 $"German Privacy Foundation 1" off \
3 $"German Privacy Foundation 2" off \
@@ -153,7 +153,8 @@ function pihole_change_upstream_dns {
15 $"Freie Unzensierte" off \
16 $"DNS.Watch" off \
17 $"uncensoreddns.org" off \
- 18 $"Google" off 2> $data
+ 18 $"Lorraine Data Network" off \
+ 19 $"Google" off 2> $data
sel=$?
case $sel in
1) exit 1;;
@@ -211,7 +212,10 @@ function pihole_change_upstream_dns {
17) PIHOLE_DNS1='91.239.100.100'
PIHOLE_DNS2='89.233.43.71'
;;
- 18) PIHOLE_DNS1='8.8.8.8'
+ 18) PIHOLE_DNS1='80.67.188.188'
+ PIHOLE_DNS2='89.234.141.66'
+ ;;
+ 19) PIHOLE_DNS1='8.8.8.8'
PIHOLE_DNS2='4.4.4.4'
dialog --title $"WARNING" \
--msgbox $"\nGoogle's main purpose for providing DNS resolvers is to spy upon people and know which sites they are visiting.\n\nThis is something to consider, and you should only really be using Google DNS as a last resort if other resolvers are unavailable." 12 60
From 82842b0ccbddf098cdf9f55fb9bf1337f329b2fb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 11:25:52 +0100
Subject: [PATCH 05/31] Missing bracket
---
doc/EN/index.org | 2 +-
website/EN/index.html | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/EN/index.org b/doc/EN/index.org
index 893757a5..2c31773d 100644
--- a/doc/EN/index.org
+++ b/doc/EN/index.org
@@ -45,7 +45,7 @@ After installation it's possible that you might want some advice on how to run y
If you find bugs, or want to add a new app to this system see the [[./devguide.html][Developers Guide]].
-Ready made disk images which can be copied onto USB or microSD drives are [[./downloads/v3][available here].
+Ready made disk images which can be copied onto USB or microSD drives are [[./downloads/v3][available here]].
#+BEGIN_CENTER
This site can also be accessed via a Tor browser at http://pazyv7nkllp76hqr.onion. This documentation is under the [[https://www.gnu.org/licenses/fdl-1.3.txt][GNU Free Documentation License version 1.3]]
diff --git a/website/EN/index.html b/website/EN/index.html
index 4ad49b2e..215f5992 100644
--- a/website/EN/index.html
+++ b/website/EN/index.html
@@ -3,7 +3,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
+
@@ -300,7 +300,7 @@ If you find bugs, or want to add a new app to this system see the available here.
From 080eb8e947f850a817f4a433bf21ff93199f9097 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 11:27:22 +0100
Subject: [PATCH 06/31] Use current directory for images
---
doc/EN/index.org | 2 +-
website/EN/index.html | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/EN/index.org b/doc/EN/index.org
index 2c31773d..f48edf86 100644
--- a/doc/EN/index.org
+++ b/doc/EN/index.org
@@ -45,7 +45,7 @@ After installation it's possible that you might want some advice on how to run y
If you find bugs, or want to add a new app to this system see the [[./devguide.html][Developers Guide]].
-Ready made disk images which can be copied onto USB or microSD drives are [[./downloads/v3][available here]].
+Ready made disk images which can be copied onto USB or microSD drives are [[./downloads/current][available here]].
#+BEGIN_CENTER
This site can also be accessed via a Tor browser at http://pazyv7nkllp76hqr.onion. This documentation is under the [[https://www.gnu.org/licenses/fdl-1.3.txt][GNU Free Documentation License version 1.3]]
diff --git a/website/EN/index.html b/website/EN/index.html
index 215f5992..b72e8704 100644
--- a/website/EN/index.html
+++ b/website/EN/index.html
@@ -3,7 +3,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
+
@@ -300,7 +300,7 @@ If you find bugs, or want to add a new app to this system see the available here.
+Ready made disk images which can be copied onto USB or microSD drives are available here.
From 15d003e3f118adfc6cf697bc6d14db38358fac09 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 15 Oct 2017 23:48:01 +0100
Subject: [PATCH 07/31] Remove package check
---
src/freedombone-utils-guile | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/freedombone-utils-guile b/src/freedombone-utils-guile
index 16e9756c..752cfac8 100755
--- a/src/freedombone-utils-guile
+++ b/src/freedombone-utils-guile
@@ -50,6 +50,7 @@ function install_8sync {
export GUILE_CFLAGS="-I${GUILE_BASE_PATH}/include"
export GUILE_LIBS="-L${GUILE_BASE_PATH}/lib -lguile -lqthreads -ldl -ltermcap -lsocket -lnsl -lm"
./bootstrap.sh
+ sed -i 's|PKG_CHECK_MODULES|##PKG_CHECK_MODULES|g' configure
configure
make
make install
From 1bbbda7c07d5dbbf4f562a64481c85572aa819ed Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 18:39:29 +0100
Subject: [PATCH 08/31] Install cryptpad on mesh clients
---
src/freedombone-app-cryptpad | 156 ++++++++++++++++++++++++++++++++
src/freedombone-image-customise | 1 +
src/freedombone-image-mesh | 22 +++++
src/freedombone-utils-guile | 1 +
4 files changed, 180 insertions(+)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index 135fa962..83b7d257 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -215,6 +215,162 @@ function remove_cryptpad {
userdel -r cryptpad
}
+function mesh_install_cryptpad {
+ if [[ $VARIANT != "meshclient" && $VARIANT != "meshusb" ]]; then
+ return
+ fi
+
+ if [ ! -d $rootdir/var/www/cryptpad ]; then
+ mkdir $rootdir/var/www/cryptpad
+ fi
+ if [ -d $rootdir$CRYPTPAD_DIR ]; then
+ rm -rf $rootdir$CRYPTPAD_DIR
+ fi
+
+ git_clone $CRYPTPAD_REPO $rootdir$CRYPTPAD_DIR
+
+ if [ ! -d $rootdir$CRYPTPAD_DIR ]; then
+ echo $'Unable to clone cryptpad repo'
+ exit 783251
+ fi
+
+ # an unprivileged user to run as
+ chroot "$rootdir" useradd -d $CRYPTPAD_DIR/ cryptpad
+
+ cd $rootdir$CRYPTPAD_DIR
+ git checkout $CRYPTPAD_COMMIT -b $CRYPTPAD_COMMIT
+
+ chroot "$rootdir" chown -R cryptpad:cryptpad $CRYPTPAD_DIR
+
+ cryptpad_nginx_site=$rootdir/etc/nginx/sites-available/cryptpad
+ echo 'server {' > $cryptpad_nginx_site
+ echo " listen 80 default_server;" >> $cryptpad_nginx_site
+ echo " server_name P${PEER_ID}.local;" >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' # Logs' >> $cryptpad_nginx_site
+ echo ' access_log /dev/null;' >> $cryptpad_nginx_site
+ echo ' error_log /dev/null;' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' # Root' >> $cryptpad_nginx_site
+ echo " root $CRYPTPAD_DIR;" >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' index index.html;' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' add_header X-XSS-Protection "1; mode=block";' >> $cryptpad_nginx_site
+ echo ' add_header X-Content-Type-Options nosniff;' >> $cryptpad_nginx_site
+ echo ' add_header X-Frame-Options SAMEORIGIN;' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' if ($uri = /pad/inner.html) {' >> $cryptpad_nginx_site
+ echo " set \$scriptSrc \"'self' 'unsafe-eval' 'unsafe-inline'\";" >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location = /cryptpad_websocket {' >> $cryptpad_nginx_site
+ echo " proxy_pass http://localhost:$CRYPTPAD_PORT;" >> $cryptpad_nginx_site
+ echo ' proxy_set_header X-Real-IP $remote_addr;' >> $cryptpad_nginx_site
+ echo ' proxy_set_header Host $host;' >> $cryptpad_nginx_site
+ echo ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' # WebSocket support (nginx 1.4)' >> $cryptpad_nginx_site
+ echo ' proxy_http_version 1.1;' >> $cryptpad_nginx_site
+ echo ' proxy_set_header Upgrade $http_upgrade;' >> $cryptpad_nginx_site
+ echo ' proxy_set_header Connection upgrade;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+
+ echo ' location ^~ /customize.dist/ {' >> $cryptpad_nginx_site
+ echo ' # This is needed in order to prevent infinite recursion between /customize/ and the root' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo ' location ^~ /customize/ {' >> $cryptpad_nginx_site
+ echo ' rewrite ^/customize/(.*)$ $1 break;' >> $cryptpad_nginx_site
+ echo ' try_files /customize/$uri /customize.dist/$uri;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo ' location = /api/config {' >> $cryptpad_nginx_site
+ echo ' default_type text/javascript;' >> $cryptpad_nginx_site
+ echo ' rewrite ^.*$ /customize/api/config break;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /blob/ {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /register/ {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /login/ {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /about.html {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /contact.html {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /contact.html {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ^~ /what-is-cryptpad.html {' >> $cryptpad_nginx_site
+ echo ' try_files $uri =404;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media)$ {' >> $cryptpad_nginx_site
+ echo ' rewrite ^(.*)$ $1/ redirect;' >> $cryptpad_nginx_site
+ echo ' }' >> $cryptpad_nginx_site
+ echo '' >> $cryptpad_nginx_site
+ echo ' try_files /www/$uri /www/$uri/index.html /customize/$uri;' >> $cryptpad_nginx_site
+ echo '}' >> $cryptpad_nginx_site
+ ln -s $cryptpad_nginx_site $rootdir/etc/nginx/sites-enabled/cryptpad
+
+ cd $rootdir$CRYPTPAD_DIR
+
+ get_npm_arch
+
+ cat < $rootdir/usr/bin/install_cryptpad
+#!/bin/bash
+cd $CRYPTPAD_DIR
+npm install --arch=$NPM_ARCH --build-from-source
+npm install --arch=$NPM_ARCH -g bower@1.8.0
+chown -R cryptpad:cryptpad $CRYPTPAD_DIR
+su -c 'bower install' - cryptpad
+cp config.example.js config.js
+EOF
+
+ if [ ! -f $rootdir$CRYPTPAD_DIR/config.js ]; then
+ echo $'Cryptpad config file not found'
+ exit 628252
+ fi
+
+ sed -i "s|httpPort:.*|httpPort: $CRYPTPAD_PORT,|g" $rootdir$CRYPTPAD_DIR/config.js
+ sed -i "s|// domain:|domain:|g" $rootdir$CRYPTPAD_DIR/config.js
+ sed -i 's|openFileLimit:.*|openFileLimit: 1024,|g' $rootdir$CRYPTPAD_DIR/config.js
+ sed -i "s|domain:.*|domain: 'http://P${PEER_ID}.local',|g" $rootdir$CRYPTPAD_DIR/config.js
+
+ chroot "$rootdir" chown -R cryptpad:cryptpad $CRYPTPAD_DIR
+
+ # daemon
+ echo '[Unit]' > $rootdir/etc/systemd/system/cryptpad.service
+ echo 'Description=Cryptpad' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'After=syslog.target' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'After=network.target' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo '' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo '[Service]' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'User=cryptpad' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'Group=cryptpad' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo "WorkingDirectory=$CRYPTPAD_DIR" >> $rootdir/etc/systemd/system/cryptpad.service
+ echo "ExecStart=/usr/local/bin/node $CRYPTPAD_DIR/server.js" >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'Environment=PATH=/usr/bin:/usr/local/bin' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'Environment=NODE_ENV=production' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'Restart=on-failure' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo '' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo '[Install]' >> $rootdir/etc/systemd/system/cryptpad.service
+ echo 'WantedBy=multi-user.target' >> $rootdir/etc/systemd/system/cryptpad.service
+ chroot "$rootdir" systemctl enable cryptpad.service
+}
+
function install_cryptpad_main {
if [[ $(app_is_installed cryptpad_main) == "1" ]]; then
return
diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise
index 2c8769e1..ce92d438 100755
--- a/src/freedombone-image-customise
+++ b/src/freedombone-image-customise
@@ -697,6 +697,7 @@ initialise_mesh() {
install_tox
install_web_server
install_pelican
+ mesh_install_cryptpad
if [ $ENABLE_ZERONET ]; then
install_zeronet
fi
diff --git a/src/freedombone-image-mesh b/src/freedombone-image-mesh
index a9699a34..783f6375 100755
--- a/src/freedombone-image-mesh
+++ b/src/freedombone-image-mesh
@@ -85,6 +85,24 @@ VPN_MESH_TLS_PORT=653
SCUTTLEBOT_PORT=8010
+CRYPTPAD_PORT=9003
+CRYPTPAD_DIR=/etc/cryptpad
+
+function enable_cryptpad {
+ if [ ! -d $CRYPTPAD_DIR ]; then
+ return
+ fi
+ if [ ! -d $CRYPTPAD_DIR/customize/api ]; then
+ mkdir -p $CRYPTPAD_DIR/customize/api
+ fi
+ wget 127.0.0.1:$CRYPTPAD_PORT/api/config -O $CRYPTPAD_DIR/customize/api/config
+ if [ ! -f $CRYPTPAD_DIR/customize/api/config ]; then
+ echo $'Unable to wget api/config'
+ exit 89252
+ fi
+ chown -R cryptpad:cryptpad $CRYPTPAD_DIR
+}
+
# Debian stretch has a problem where the formerly predictable wlan0 and eth0
# device names get assigned random names. This is a hacky workaround.
# Also adding net.ifnames=0 to kernel options on bootloader may work.
@@ -873,12 +891,16 @@ if [ -f $MESH_INSTALL_SETUP ]; then
#create_ram_disk 1
#setup_amnesic_data
change_avahi_name
+ if [ -d $CRYPTPAD_DIR ]; then
+ systemctl start cryptpad
+ fi
configure_toxcore
create_tox_user
#setup_tahoelafs
mesh_setup_vpn
initialise_scuttlebot_pub
setup_ipfs
+ enable_cryptpad
mesh_amnesic
make_root_read_only
diff --git a/src/freedombone-utils-guile b/src/freedombone-utils-guile
index 752cfac8..3f22334a 100755
--- a/src/freedombone-utils-guile
+++ b/src/freedombone-utils-guile
@@ -54,6 +54,7 @@ function install_8sync {
configure
make
make install
+ export GUILE_LOAD_COMPILED_PATH="$INSTALL_DIR/8sync"
}
function install_guile {
From 8f13c6e193301e57603fb1d2597882c61ba6a0f0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 20:12:10 +0100
Subject: [PATCH 09/31] Preparing for cryptpad icon
---
src/freedombone-app-cryptpad | 3 +++
src/freedombone-image-customise | 17 +++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index 83b7d257..9f8c30b8 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -226,6 +226,9 @@ function mesh_install_cryptpad {
if [ -d $rootdir$CRYPTPAD_DIR ]; then
rm -rf $rootdir$CRYPTPAD_DIR
fi
+ if [ -f $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png ]; then
+ cp $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png $rootdir/etc/cryptpad/icon_cryptpad.png
+ fi
git_clone $CRYPTPAD_REPO $rootdir$CRYPTPAD_DIR
diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise
index ce92d438..70c1ad8b 100755
--- a/src/freedombone-image-customise
+++ b/src/freedombone-image-customise
@@ -928,6 +928,23 @@ if [ \$no_of_users -gt 0 ]; then
chmod +x /home/$MY_USERNAME/Desktop/Users.desktop
chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/Desktop/Users.desktop
+ if [ ! -f /home/$MY_USERNAME/Desktop/cryptpad.desktop ]; then
+ echo '[Desktop Entry]' > /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo 'Name=CryptPad' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo 'Type=Application' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo 'Comment=Realtime collaborative editing of documents' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo "Exec=$BROWSER http://127.0.0.1" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo "Icon=/etc/cryptpad/icon_cryptpad.png" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo 'Terminal=false' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo 'Categories=Application;' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ chmod +x /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ else
+ if grep -q "Offline" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
+ sed -i 's|Name=.*|Name=CryptPad|g' /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ fi
+ fi
+
if [ ! -f /home/$MY_USERNAME/Desktop/social.desktop ]; then
echo '[Desktop Entry]' > /home/$MY_USERNAME/Desktop/social.desktop
echo 'Name=Social' >> /home/$MY_USERNAME/Desktop/social.desktop
From 7f8609a3aa57481c4730dbd1fb3853220378ade4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 20:24:09 +0100
Subject: [PATCH 10/31] Importing gpg full public keys from the control panel
---
src/freedombone-controlpanel-user | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/src/freedombone-controlpanel-user b/src/freedombone-controlpanel-user
index 5f4fb93c..42487622 100755
--- a/src/freedombone-controlpanel-user
+++ b/src/freedombone-controlpanel-user
@@ -439,7 +439,7 @@ function add_gpg_key {
trap "rm -f $data" 0 1 2 5 15
dialog --title $"Add someone's PGP/GPG key" \
--backtitle $"Freedombone User Control Panel" \
- --inputbox $"Enter their email address or Key ID below" 8 60 2>$data
+ --inputbox $"Enter their email address, Key ID or full key below" 8 60 2>$data
sel=$?
case $sel in
0)
@@ -448,18 +448,29 @@ function add_gpg_key {
address_is_valid=
- if [[ $ADD_EMAIL_ADDRESS == *"@"* && $ADD_EMAIL_ADDRESS == *"."* ]]; then
+ if [[ "$ADD_EMAIL_ADDRESS" == *"@"* && "$ADD_EMAIL_ADDRESS" == *"."* ]]; then
address_is_valid=1
- else
- if [[ $ADD_EMAIL_ADDRESS == "0x"* ]]; then
- address_is_valid=1
- fi
fi
+ if [[ "$ADD_EMAIL_ADDRESS" == "0x"* ]]; then
+ address_is_valid=1
+ fi
+ publicstr=$"BEGIN PGP PUBLIC KEY BLOCK"
+ if [[ "$ADD_EMAIL_ADDRESS" == *"$publicstr"* ]]; then
+ address_is_valid=1
+ fi
+
if [ $address_is_valid ]; then
clear
- gpg --search-keys "$ADD_EMAIL_ADDRESS"
- gpg_set_trust "$ADD_EMAIL_ADDRESS"
+ if [[ "$ADD_EMAIL_ADDRESS" == *"$publicstr"* ]]; then
+ echo "$ADD_EMAIL_ADDRESS" | gpg --import
+ dialog --title $"Add someone's PGP/GPG key" \
+ --backtitle $"Freedombone User Control Panel" \
+ --msgbox $"GPG public key was imported" 6 50
+ else
+ gpg --search-keys "$ADD_EMAIL_ADDRESS"
+ gpg_set_trust "$ADD_EMAIL_ADDRESS"
+ fi
else
dialog --title $"Unrecognised email address" \
--backtitle $"Freedombone User Control Panel" \
From 66595013373c187031ed73caccf8d7fa3b90db2d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 20:28:04 +0100
Subject: [PATCH 11/31] Extra large input box
---
src/freedombone-controlpanel-user | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/freedombone-controlpanel-user b/src/freedombone-controlpanel-user
index 42487622..10fb31af 100755
--- a/src/freedombone-controlpanel-user
+++ b/src/freedombone-controlpanel-user
@@ -439,7 +439,7 @@ function add_gpg_key {
trap "rm -f $data" 0 1 2 5 15
dialog --title $"Add someone's PGP/GPG key" \
--backtitle $"Freedombone User Control Panel" \
- --inputbox $"Enter their email address, Key ID or full key below" 8 60 2>$data
+ --inputbox $"Enter their email address, Key ID or full key below" 8 999999 2>$data
sel=$?
case $sel in
0)
From 75b72cb787344636f79023ff5493e6b1942674da Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 21:05:15 +0100
Subject: [PATCH 12/31] Use editbox
---
src/freedombone-controlpanel-user | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/freedombone-controlpanel-user b/src/freedombone-controlpanel-user
index 10fb31af..59db36a8 100755
--- a/src/freedombone-controlpanel-user
+++ b/src/freedombone-controlpanel-user
@@ -437,9 +437,9 @@ function refresh_gpg_keys {
function add_gpg_key {
data=$(tempfile 2>/dev/null)
trap "rm -f $data" 0 1 2 5 15
- dialog --title $"Add someone's PGP/GPG key" \
+ dialog --title $"Enter email address, Key ID or full key below" \
--backtitle $"Freedombone User Control Panel" \
- --inputbox $"Enter their email address, Key ID or full key below" 8 999999 2>$data
+ --editbox $data 8 60
sel=$?
case $sel in
0)
@@ -459,7 +459,6 @@ function add_gpg_key {
address_is_valid=1
fi
-
if [ $address_is_valid ]; then
clear
if [[ "$ADD_EMAIL_ADDRESS" == *"$publicstr"* ]]; then
@@ -479,6 +478,7 @@ function add_gpg_key {
fi
;;
esac
+ rm $data
}
function remove_gpg_key {
From e928240e98131449c339f9a86bfebc78bd760df3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 21:09:12 +0100
Subject: [PATCH 13/31] Save public key to file
---
src/freedombone-controlpanel-user | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/freedombone-controlpanel-user b/src/freedombone-controlpanel-user
index 59db36a8..3f257aad 100755
--- a/src/freedombone-controlpanel-user
+++ b/src/freedombone-controlpanel-user
@@ -439,7 +439,7 @@ function add_gpg_key {
trap "rm -f $data" 0 1 2 5 15
dialog --title $"Enter email address, Key ID or full key below" \
--backtitle $"Freedombone User Control Panel" \
- --editbox $data 8 60
+ --editbox $data 8 60 2>$data
sel=$?
case $sel in
0)
From 333c4d7656e4313ff89fd4d8c3f508ecefd4a5f0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 23 Oct 2017 23:13:13 +0100
Subject: [PATCH 14/31] cryptpad icon
---
img/icon_cryptpad.png | Bin 0 -> 1792 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 img/icon_cryptpad.png
diff --git a/img/icon_cryptpad.png b/img/icon_cryptpad.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f7714fe511c2fb83cbf6fa96870768be7fa2403
GIT binary patch
literal 1792
zcmah~XH?UN77rtX05ygU0slZsnH7DqSAq#7h=dXGAs`WyjnWX2AvGijK~|WGl^sPM
zP(ij>P@oLiNXslT0x}wwAYoLR9>4V4yXW5DI`^FW@g_Pt*h<0`;UEx5l1RWg3%FY_
z+b|IUTKPr!3CPpYo{Yz*cL>@ev+1k&H|FN%{@V)l*F=E-x4tfyG$~gI4hhkm9b7<|
zrE%YXjQ0gw9Eb&0CJ2mJD8VfZ1QM6}XM{kHpU4YBD2;d#51oU{$x5j0^>t{2KoArW
zhb2c$^75uqON}9*?fdk8<8=c_z9w)u|FMGIP^HA^{NbBMx-(
zf1;KVtu6)kH?tHi}+A~3S)18hMt{b1eN+dLl)IWT*}6R>xcx;moIKT8rGO8xfk&x`Eu?$F1TAgM!&qXX!K_F{xS*
zM}K+un`7BfVUu9&7bmIPV})Wb59bq)_lN8khrn1rih{qCVkAimGO^$vh7{USi14V8LJ#BC_r^oCzjhw
z=SK6=g`V=4p13oP`m#Y9(@A^_BS=rH#K#)fiy*e{WZWVO%8lU6er`08?sk$F4`d#D
zNe;>b`_TE_m0AW$6zxNcui19OI@i7X33i#BY?_%Y+|
z6I<)a00VHO2qoSuiTR3!bZTX!g@MRkKJ0sAUnifmPV9Eg33!D($FPbDv!7_muJ8e)~_K8qtshl>!J
z0^9$i`a_fDlM<7tJ#xcByW{XxW+XdMXd4mYlUqqSc9N9grt+uXK)I@S50~ngLM*aP
z#7pPm6WfTS_=+4yNKeK4=}%d+lyg{WPQjS8&buE0H_14cY!#MT*AJc(P;?MOKk&Wq
z@S-O9ArA{rwQ6xM;;%Q6&L--?4B5K6FCg1H!jX#1>!;ZjBGe>tYPrWXgE{9B6;70k
zcLA{3DnxX`W*}KprrR#!*HfB+Z+66ueHfJDQJ%XYj}AXumeGw_XT%j^^8?-aYBO>K
z%%+i5VAx%`>zGb#W83!6Nn4Y~q#+3L(l1hEUhsY)ShGoCpnYiT={TCd`D_T?JnPz4
zqov>F7JPvOWGaSF$Dw9ol(KyaW&ay(PZ%Hgm8FeGPjsELPD5+oaexAIkSs>J{~!5(
zJjNmV5sBAFn=OB$sa8W1Hapj=&!_66OI~M|!WMAfvOs84)rx*%tuP^lxO3F-?eNY_
z25#(*88T$B`(D&=y<02TC5iLMI0WO(9m(tHyH+&c5AiVwZsb0acK7-b{d<1Ki3dz2
zxr};;(ayVDr^akbYe}ZNgFQiL4HuHue!pgBUJbS1&{oJ5oxk!t(*CV>$ZV}gN#zkI
zc?7Lo`jct?TIM@QRXry@V{)-%wLss~q0;2R@e88(Tt%wFYuzHJrG+$}%OUOPpV$7
zM>1>WO0z>+;4qK-CBsnXo9^8TuWEHT3o!7j`u?Q()B3hnA
Date: Tue, 24 Oct 2017 11:05:35 +0100
Subject: [PATCH 15/31] Copy icon after directory creation
---
src/freedombone-app-cryptpad | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index 9f8c30b8..c675a1b3 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -226,9 +226,6 @@ function mesh_install_cryptpad {
if [ -d $rootdir$CRYPTPAD_DIR ]; then
rm -rf $rootdir$CRYPTPAD_DIR
fi
- if [ -f $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png ]; then
- cp $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png $rootdir/etc/cryptpad/icon_cryptpad.png
- fi
git_clone $CRYPTPAD_REPO $rootdir$CRYPTPAD_DIR
@@ -237,6 +234,10 @@ function mesh_install_cryptpad {
exit 783251
fi
+ if [ -f $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png ]; then
+ cp $rootdir/root/$PROJECT_NAME/img/icon_cryptpad.png $rootdir$CRYPTPAD_DIR/icon_cryptpad.png
+ fi
+
# an unprivileged user to run as
chroot "$rootdir" useradd -d $CRYPTPAD_DIR/ cryptpad
From 25dfda1493d7f5d8fb44eedc32ca3f6f81cff383 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 11:30:46 +0100
Subject: [PATCH 16/31] Run cryptpad install script for mesh
---
src/freedombone-app-cryptpad | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index c675a1b3..88ea5c11 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -342,12 +342,16 @@ chown -R cryptpad:cryptpad $CRYPTPAD_DIR
su -c 'bower install' - cryptpad
cp config.example.js config.js
EOF
+ chmod +x $rootdir/usr/bin/install_cryptpad
+ chroor "$rootdir" /usr/bin/install_cryptpad
if [ ! -f $rootdir$CRYPTPAD_DIR/config.js ]; then
echo $'Cryptpad config file not found'
exit 628252
fi
+ rm $rootdir/usr/bin/install_cryptpad
+
sed -i "s|httpPort:.*|httpPort: $CRYPTPAD_PORT,|g" $rootdir$CRYPTPAD_DIR/config.js
sed -i "s|// domain:|domain:|g" $rootdir$CRYPTPAD_DIR/config.js
sed -i 's|openFileLimit:.*|openFileLimit: 1024,|g' $rootdir$CRYPTPAD_DIR/config.js
From feb629211f5192b466a7b5b0b82941704633642c Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 11:31:43 +0100
Subject: [PATCH 17/31] Typo
---
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 88ea5c11..301f4f67 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -343,7 +343,7 @@ su -c 'bower install' - cryptpad
cp config.example.js config.js
EOF
chmod +x $rootdir/usr/bin/install_cryptpad
- chroor "$rootdir" /usr/bin/install_cryptpad
+ chroot "$rootdir" /usr/bin/install_cryptpad
if [ ! -f $rootdir$CRYPTPAD_DIR/config.js ]; then
echo $'Cryptpad config file not found'
From 92bb07ce341f9304613f3d070a854283bd63fa2b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 13:30:57 +0100
Subject: [PATCH 18/31] Duplicate entry
---
src/freedombone-app-cryptpad | 8 --------
1 file changed, 8 deletions(-)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index 301f4f67..6528b1fb 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -313,10 +313,6 @@ function mesh_install_cryptpad {
echo ' try_files $uri =404;' >> $cryptpad_nginx_site
echo ' }' >> $cryptpad_nginx_site
echo '' >> $cryptpad_nginx_site
- echo ' location ^~ /contact.html {' >> $cryptpad_nginx_site
- echo ' try_files $uri =404;' >> $cryptpad_nginx_site
- echo ' }' >> $cryptpad_nginx_site
- echo '' >> $cryptpad_nginx_site
echo ' location ^~ /what-is-cryptpad.html {' >> $cryptpad_nginx_site
echo ' try_files $uri =404;' >> $cryptpad_nginx_site
echo ' }' >> $cryptpad_nginx_site
@@ -484,10 +480,6 @@ function install_cryptpad_main {
echo ' try_files $uri =404;' >> $cryptpad_nginx_site
echo ' }' >> $cryptpad_nginx_site
echo '' >> $cryptpad_nginx_site
- echo ' location ^~ /contact.html {' >> $cryptpad_nginx_site
- echo ' try_files $uri =404;' >> $cryptpad_nginx_site
- echo ' }' >> $cryptpad_nginx_site
- echo '' >> $cryptpad_nginx_site
echo ' location ^~ /what-is-cryptpad.html {' >> $cryptpad_nginx_site
echo ' try_files $uri =404;' >> $cryptpad_nginx_site
echo ' }' >> $cryptpad_nginx_site
From 460eece8cfcc481cae3db8d90384744787336557 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 13:34:17 +0100
Subject: [PATCH 19/31] Link within chroot
---
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 6528b1fb..4ac6c6bb 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -323,7 +323,7 @@ function mesh_install_cryptpad {
echo '' >> $cryptpad_nginx_site
echo ' try_files /www/$uri /www/$uri/index.html /customize/$uri;' >> $cryptpad_nginx_site
echo '}' >> $cryptpad_nginx_site
- ln -s $cryptpad_nginx_site $rootdir/etc/nginx/sites-enabled/cryptpad
+ chroot "$rootdir" ln -s /etc/nginx/sites-available/cryptpad /etc/nginx/sites-enabled/cryptpad
cd $rootdir$CRYPTPAD_DIR
From 14e21bc6ddc0495e4f5f5e15a6ae3b6b8b3b74a0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 13:53:27 +0100
Subject: [PATCH 20/31] Set up the web server for cryptpad on the mesh
---
src/freedombone-app-cryptpad | 1 -
src/freedombone-image-mesh | 5 +++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/freedombone-app-cryptpad b/src/freedombone-app-cryptpad
index 4ac6c6bb..5f648627 100755
--- a/src/freedombone-app-cryptpad
+++ b/src/freedombone-app-cryptpad
@@ -323,7 +323,6 @@ function mesh_install_cryptpad {
echo '' >> $cryptpad_nginx_site
echo ' try_files /www/$uri /www/$uri/index.html /customize/$uri;' >> $cryptpad_nginx_site
echo '}' >> $cryptpad_nginx_site
- chroot "$rootdir" ln -s /etc/nginx/sites-available/cryptpad /etc/nginx/sites-enabled/cryptpad
cd $rootdir$CRYPTPAD_DIR
diff --git a/src/freedombone-image-mesh b/src/freedombone-image-mesh
index 783f6375..ad9e6604 100755
--- a/src/freedombone-image-mesh
+++ b/src/freedombone-image-mesh
@@ -92,6 +92,11 @@ function enable_cryptpad {
if [ ! -d $CRYPTPAD_DIR ]; then
return
fi
+
+ # Set up the web server
+ ln -s /etc/nginx/sites-available/cryptpad /etc/nginx/sites-enabled/cryptpad
+ rm /etc/nginx/sites-enabled/default
+
if [ ! -d $CRYPTPAD_DIR/customize/api ]; then
mkdir -p $CRYPTPAD_DIR/customize/api
fi
From ce49d06d1837e38bc602b3eb8471de25cdb6cbda Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 14:05:26 +0100
Subject: [PATCH 21/31] Use hostname when opening cryptpad from desktop icon
So that copying and pasting a link to a document makes sense
---
src/freedombone-image-customise | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise
index 70c1ad8b..1fa38c24 100755
--- a/src/freedombone-image-customise
+++ b/src/freedombone-image-customise
@@ -933,13 +933,16 @@ if [ \$no_of_users -gt 0 ]; then
echo 'Name=CryptPad' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Type=Application' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Comment=Realtime collaborative editing of documents' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
- echo "Exec=$BROWSER http://127.0.0.1" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo "Exec=$BROWSER http://${HOSTNAME}.local" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo "Icon=/etc/cryptpad/icon_cryptpad.png" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Terminal=false' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Categories=Application;' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
chmod +x /home/$MY_USERNAME/Desktop/cryptpad.desktop
chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/Desktop/cryptpad.desktop
else
+ if ! grep -q "${HOSTNAME}.local" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
+ sed -i "s|Exec=.*|Exec=$BROWSER http://${HOSTNAME}.local|g" /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ fi
if grep -q "Offline" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
sed -i 's|Name=.*|Name=CryptPad|g' /home/$MY_USERNAME/Desktop/cryptpad.desktop
fi
From c2aa4d210de4069fe6dc690fd18f15b50a2f9556 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 24 Oct 2017 23:35:47 +0100
Subject: [PATCH 22/31] Add an icon to VPN connect to another mesh
---
img/avatars/connect.jpg | Bin 0 -> 6404 bytes
src/freedombone-image-customise | 12 ++
src/freedombone-image-mesh | 9 +-
src/freedombone-mesh-connect | 230 ++++++++++++++++++++++++++++++++
4 files changed, 250 insertions(+), 1 deletion(-)
create mode 100644 img/avatars/connect.jpg
create mode 100755 src/freedombone-mesh-connect
diff --git a/img/avatars/connect.jpg b/img/avatars/connect.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c68690da067e59ed0fba2aab7f325d6b0eda4d9d
GIT binary patch
literal 6404
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
literal 0
HcmV?d00001
diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise
index 1fa38c24..ffa51d2e 100755
--- a/src/freedombone-image-customise
+++ b/src/freedombone-image-customise
@@ -982,6 +982,18 @@ if [ \$no_of_users -gt 0 ]; then
# fi
#fi
+ if [ ! -f /home/$MY_USERNAME/Desktop/vpn.desktop ]; then
+ echo '[Desktop Entry]' > /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'Type=Application' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'Name=Connect Meshes' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'Comment=Connect to another mesh network via the internet' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'Exec=mate-terminal -e /usr/local/bin/${PROJECT_NAME}-mesh-connect' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'Icon=/usr/share/${PROJECT_NAME}/avatars/connect.jpg' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ echo 'StartupNotify=false' >> /home/$MY_USERNAME/Desktop/vpn.desktop
+ chmod +x /home/$MY_USERNAME/Desktop/vpn.desktop
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/Desktop/vpn.desktop
+ fi
+
if [ -f /tmp/.ipfs-users ]; then
echo '[Desktop Entry]' > /home/$MY_USERNAME/Desktop/sites.desktop
echo 'Type=Application' >> /home/$MY_USERNAME/Desktop/sites.desktop
diff --git a/src/freedombone-image-mesh b/src/freedombone-image-mesh
index ad9e6604..7148304a 100755
--- a/src/freedombone-image-mesh
+++ b/src/freedombone-image-mesh
@@ -784,7 +784,7 @@ function generate_stunnel_keys {
cp /etc/stunnel/stunnel.pem /home/$MY_USERNAME/stunnel.pem
cp /etc/stunnel/stunnel.p12 /home/$MY_USERNAME/stunnel.p12
- chown $MY_USERNAME:$MY_USERNAME $prefix$userhome/stunnel*
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/stunnel*
echo "stunnel keys created" >> /var/log/${PROJECT_NAME}.log
}
@@ -797,6 +797,13 @@ function mesh_setup_vpn {
generate_stunnel_keys
sed -i 's|tun-mtu .*|tun-mtu 1532|g' /home/$MY_USERNAME/client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/stunnel*
+
+ # create an archive of the vpn client files
+ cd /home/$MY_USERNAME
+ tar -czvf vpn.tar.gz stunnel* client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/vpn.tar.gz
systemctl restart openvpn
}
diff --git a/src/freedombone-mesh-connect b/src/freedombone-mesh-connect
new file mode 100755
index 00000000..32aec07c
--- /dev/null
+++ b/src/freedombone-mesh-connect
@@ -0,0 +1,230 @@
+#!/bin/bash
+#
+# .---. . .
+# | | |
+# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-.
+# | | (.-' (.-' ( | ( )| | | | )( )| | (.-'
+# ' ' --' --' -' - -' ' ' -' -' -' ' - --'
+#
+# Freedom in the Cloud
+#
+# Blogging functions for mesh clients
+#
+# License
+# =======
+#
+# 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 .
+
+PROJECT_NAME='freedombone'
+
+export TEXTDOMAIN=${PROJECT_NAME}-mesh-blog
+export TEXTDOMAINDIR="/usr/share/locale"
+
+MY_USERNAME='fbone'
+
+OPENVPN_SERVER_NAME="server"
+OPENVPN_KEY_FILENAME='client.ovpn'
+VPN_COUNTRY_CODE="US"
+VPN_AREA="Apparent Free Speech Zone"
+VPN_LOCATION="Freedomville"
+VPN_ORGANISATION="Freedombone"
+VPN_UNIT="Freedombone Unit"
+STUNNEL_PORT=3439
+VPN_TLS_PORT=553
+VPN_MESH_TLS_PORT=653
+
+function vpn_generate_keys {
+ # generate host keys
+ if [ ! -f /etc/openvpn/dh2048.pem ]; then
+ ${PROJECT_NAME}-dhparam -o /etc/openvpn/dh2048.pem
+ fi
+ if [ ! -f /etc/openvpn/dh2048.pem ]; then
+ echo $'vpn dhparams were not generated' >> /var/log/${PROJECT_NAME}.log
+ exit 73724523
+ fi
+ cp /etc/openvpn/dh2048.pem /etc/openvpn/easy-rsa/keys/dh2048.pem
+
+ cd /etc/openvpn/easy-rsa
+ . ./vars
+ ./clean-all
+ vpn_openssl_version='1.0.0'
+ if [ ! -f openssl-${vpn_openssl_version}.cnf ]; then
+ echo $"openssl-${vpn_openssl_version}.cnf was not found" >> /var/log/${PROJECT_NAME}.log
+ exit 7392353
+ fi
+ cp openssl-${vpn_openssl_version}.cnf openssl.cnf
+
+ if [ -f /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.crt ]; then
+ rm /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.crt
+ fi
+ if [ -f /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.key ]; then
+ rm /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.key
+ fi
+ if [ -f /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.csr ]; then
+ rm /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.csr
+ fi
+ sed -i 's| --interact||g' build-key-server
+ sed -i 's| --interact||g' build-ca
+ ./build-ca
+ ./build-key-server ${OPENVPN_SERVER_NAME}
+ if [ ! -f /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.crt ]; then
+ echo $'OpenVPN crt not found' >> /var/log/${PROJECT_NAME}.log
+ exit 7823352
+ fi
+ server_cert=$(cat /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.crt)
+ if [ ${#server_cert} -lt 10 ]; then
+ cat /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.crt
+ echo $'Server cert generation failed' >> /var/log/${PROJECT_NAME}.log
+ exit 3284682
+ fi
+
+ if [ ! -f /etc/openvpn/easy-rsa/keys/${OPENVPN_SERVER_NAME}.key ]; then
+ echo $'OpenVPN key not found' >> /var/log/${PROJECT_NAME}.log
+ exit 6839436
+ fi
+ if [ ! -f /etc/openvpn/easy-rsa/keys/ca.key ]; then
+ echo $'OpenVPN ca not found' >> /var/log/${PROJECT_NAME}.log
+ exit 7935203
+ fi
+ cp /etc/openvpn/easy-rsa/keys/{$OPENVPN_SERVER_NAME.crt,$OPENVPN_SERVER_NAME.key,ca.crt} /etc/openvpn
+
+ create_user_vpn_key ${MY_USERNAME}
+}
+
+function generate_stunnel_keys {
+ echo "Creating stunnel keys" >> /var/log/${PROJECT_NAME}.log
+ openssl req -x509 -nodes -days 3650 -sha256 \
+ -subj "/O=$VPN_ORGANISATION/OU=$VPN_UNIT/C=$VPN_COUNTRY_CODE/ST=$VPN_AREA/L=$VPN_LOCATION/CN=$HOSTNAME" \
+ -newkey rsa:2048 -keyout /etc/stunnel/key.pem \
+ -out /etc/stunnel/cert.pem
+ if [ ! -f /etc/stunnel/key.pem ]; then
+ echo $'stunnel key not created' >> /var/log/${PROJECT_NAME}.log
+ exit 793530
+ fi
+ if [ ! -f /etc/stunnel/cert.pem ]; then
+ echo $'stunnel cert not created' >> /var/log/${PROJECT_NAME}.log
+ exit 204587
+ fi
+ chmod 400 /etc/stunnel/key.pem
+ chmod 640 /etc/stunnel/cert.pem
+
+ cat /etc/stunnel/key.pem /etc/stunnel/cert.pem >> /etc/stunnel/stunnel.pem
+ chmod 640 /etc/stunnel/stunnel.pem
+
+ openssl pkcs12 -export -out /etc/stunnel/stunnel.p12 -inkey /etc/stunnel/key.pem -in /etc/stunnel/cert.pem -passout pass:
+ if [ ! -f /etc/stunnel/stunnel.p12 ]; then
+ echo $'stunnel pkcs12 not created' >> /var/log/${PROJECT_NAME}.log
+ exit 639353
+ fi
+ chmod 640 /etc/stunnel/stunnel.p12
+
+ cp /etc/stunnel/stunnel.pem /home/$MY_USERNAME/stunnel.pem
+ cp /etc/stunnel/stunnel.p12 /home/$MY_USERNAME/stunnel.p12
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/stunnel*
+ echo "stunnel keys created" >> /var/log/${PROJECT_NAME}.log
+}
+
+function mesh_setup_vpn {
+ vpn_generate_keys
+
+ cp /etc/stunnel/stunnel-client.conf /home/$MY_USERNAME/stunnel-client.conf
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/stunnel*
+
+ generate_stunnel_keys
+
+ sed -i 's|tun-mtu .*|tun-mtu 1532|g' /home/$MY_USERNAME/client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/stunnel*
+
+ # create an archive of the vpn client files
+ cd /home/$MY_USERNAME
+ tar -czvf vpn.tar.gz stunnel* client.ovpn
+ chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/vpn.tar.gz
+
+ if [ -f vpn.tar.gz ]; then
+ dialog --title $"Generate VPN client keys" \
+ --msgbox $"\nNew VPN client keys have been generated in the /home/fbone directory.\n\nYou can find it by selecting \"Places\" then \"Home Directory\" on the top menu bar. Transmit the vpn.tar.gz file to whoever is running the other mesh network so that they can connect to yours.\n\nThey should uncompress vpn.tar.gz to their /home/fbone directory, then connect using your IP address or domain name." 15 70
+ fi
+}
+
+function connect_to_vpn {
+ dialog --title $"VPN Connect to another mesh network" \
+ --backtitle $"Freedombone Mesh" \
+ --defaultno \
+ --yesno $"\nHave you received the vpn.tar.gz file from the other mesh administrator and uncompressed it into the /home/fbone directory?" 10 70
+ sel=$?
+ case $sel in
+ 1) return;;
+ 255) return;;
+ esac
+
+ data=$(tempfile 2>/dev/null)
+ trap "rm -f $data" 0 1 2 5 15
+ dialog --title $"VPN Connect to another mesh network" \
+ --backtitle $"Freedombone Mesh" \
+ --inputbox $'Enter the IP address or domain name of the other mesh.' 10 60 2>$data
+ sel=$?
+ case $sel in
+ 0)
+ ip_or_domain=$(<$data)
+ if [ ${#ip_or_domain} -gt 1 ]; then
+ if [[ "$ip_or_domain" == *'.'* ]]; then
+
+ if [ ! -f ~/client.ovpn ]; then
+ rm $data
+ exit 1
+ fi
+ if [ ! -f ~/stunnel.pem ]; then
+ rm $data
+ exit 1
+ fi
+ if [ ! -f ~/stunnel.p12 ]; then
+ rm $data
+ exit 1
+ fi
+
+ sed -i "s|route .*|route $ip_or_domain 255.255.255.255 net_gateway|g" ~/client.ovpn
+
+ clear
+ cd ~/
+ sudo stunnel stunnel-client.conf
+ sudo openvpn client.ovpn
+ fi
+ fi
+ ;;
+ esac
+
+ rm $data
+}
+
+data=$(tempfile 2>/dev/null)
+trap "rm -f $data" 0 1 2 5 15
+dialog --backtitle $"Freedombone Mesh" \
+ --title $"Connect to another mesh network" \
+ --radiolist $"Choose an operation:" 10 75 2 \
+ 1 $"Connect to another mesh network" on \
+ 2 $"Generate VPN keys for another mesh network to connect to me" off 2> $data
+sel=$?
+case $sel in
+ 1) exit 1;;
+ 255) exit 1;;
+esac
+case $(cat $data) in
+ 1) rm $data
+ connect_to_vpn;;
+ 2) rm $data
+ mesh_setup_vpn;;
+esac
+
+exit 0
From 62bea42aca3c6ed85b8d19ae1f712bf57929499e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 25 Oct 2017 13:29:07 +0100
Subject: [PATCH 23/31] vpn tls port on mesh
---
src/freedombone-mesh-connect | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/freedombone-mesh-connect b/src/freedombone-mesh-connect
index 32aec07c..ab38bccb 100755
--- a/src/freedombone-mesh-connect
+++ b/src/freedombone-mesh-connect
@@ -41,7 +41,6 @@ VPN_LOCATION="Freedomville"
VPN_ORGANISATION="Freedombone"
VPN_UNIT="Freedombone Unit"
STUNNEL_PORT=3439
-VPN_TLS_PORT=553
VPN_MESH_TLS_PORT=653
function vpn_generate_keys {
@@ -154,7 +153,7 @@ function mesh_setup_vpn {
if [ -f vpn.tar.gz ]; then
dialog --title $"Generate VPN client keys" \
- --msgbox $"\nNew VPN client keys have been generated in the /home/fbone directory.\n\nYou can find it by selecting \"Places\" then \"Home Directory\" on the top menu bar. Transmit the vpn.tar.gz file to whoever is running the other mesh network so that they can connect to yours.\n\nThey should uncompress vpn.tar.gz to their /home/fbone directory, then connect using your IP address or domain name." 15 70
+ --msgbox $"\nNew VPN client keys have been generated in the /home/fbone directory.\n\nYou can find it by selecting \"Places\" then \"Home Directory\" on the top menu bar. Transmit the vpn.tar.gz file to whoever is running the other mesh network so that they can connect to yours.\n\nThey should uncompress vpn.tar.gz to their /home/fbone directory, forward port $VPN_MESH_TLS_PORT then connect using your IP address or domain name." 15 70
fi
}
@@ -162,7 +161,7 @@ function connect_to_vpn {
dialog --title $"VPN Connect to another mesh network" \
--backtitle $"Freedombone Mesh" \
--defaultno \
- --yesno $"\nHave you received the vpn.tar.gz file from the other mesh administrator and uncompressed it into the /home/fbone directory?" 10 70
+ --yesno $"\nHave you received the vpn.tar.gz file from the other mesh administrator, uncompressed it into the /home/fbone directory and also forwarded port $VPN_MESH_TLS_PORT from your internet router to this system?" 10 70
sel=$?
case $sel in
1) return;;
From f5a8c426451471e14d7a3e4e4f54a93361419039 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 25 Oct 2017 13:37:53 +0100
Subject: [PATCH 24/31] Setting vpn tls port from control panel
---
src/freedombone-app-vpn | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/freedombone-app-vpn b/src/freedombone-app-vpn
index f10ad362..dda7b38b 100755
--- a/src/freedombone-app-vpn
+++ b/src/freedombone-app-vpn
@@ -123,7 +123,7 @@ function vpn_change_tls_port {
VPN_TLS_PORT=$tlsport
write_config_param "VPN_TLS_PORT" "$VPN_TLS_PORT"
sed -i "s|accept =.*|accept = $VPN_TLS_PORT|g" /etc/stunnel/stunnel.conf
- sed -i "s|accept =.*|accept = $VPN_TLS_PORT|g" /etc/stunnel/stunnel-client.conf
+ sed -i "s|connect =.*|connect = :$VPN_TLS_PORT|g" /etc/stunnel/stunnel-client.conf
for d in /home/*/ ; do
USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
From ef686e62644a7a0b5a49c0c4e20c76fb69534f4a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 25 Oct 2017 14:02:19 +0100
Subject: [PATCH 25/31] Handle firewall when changing vpn tls port
---
src/freedombone-app-vpn | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/src/freedombone-app-vpn b/src/freedombone-app-vpn
index dda7b38b..0d0f051b 100755
--- a/src/freedombone-app-vpn
+++ b/src/freedombone-app-vpn
@@ -106,13 +106,17 @@ function install_interactive_vpn {
}
function vpn_change_tls_port {
- EXISTING_VPN_TLS_PORT=$VPN_TLS_PORT
+ if ! grep -q "VPN-TLS" $FIREWALL_CONFIG; then
+ EXISTING_VPN_TLS_PORT=443
+ else
+ EXISTING_VPN_TLS_PORT=$(cat $FIREWALL_CONFIG | grep "VPN-TLS" | awk -F '=' '{print $2}')
+ fi
data=$(tempfile 2>/dev/null)
trap "rm -f $data" 0 1 2 5 15
dialog --title $"VPN Configuration" \
--backtitle $"Freedombone Control Panel" \
- --inputbox $'Change TLS port' 10 50 $VPN_TLS_PORT 2>$data
+ --inputbox $'Change TLS port' 10 50 $EXISTING_VPN_TLS_PORT 2>$data
sel=$?
case $sel in
0)
@@ -134,17 +138,29 @@ function vpn_change_tls_port {
done
if [ $VPN_TLS_PORT -eq 443 ]; then
+ if [[ "$PREVIOUS_VPN_TLS_PORT" != "443" ]]; then
+ firewall_remove VPN-TLS ${EXISTING_VPN_TLS_PORT}
+ fi
systemctl stop nginx
systemctl disable nginx
else
+ if [[ "$PREVIOUS_VPN_TLS_PORT" != "$VPN_TLS_PORT" ]]; then
+ firewall_remove VPN-TLS ${EXISTING_VPN_TLS_PORT}
+ firewall_add VPN-TLS ${VPN_TLS_PORT} tcp
+ fi
systemctl enable nginx
systemctl restart nginx
fi
systemctl restart stunnel
- dialog --title $"VPN Configuration" \
- --msgbox $"TLS port changed to $VPN_TLS_PORT" 6 60
+ if [ $VPN_TLS_PORT -eq 443 ]; then
+ dialog --title $"VPN Configuration" \
+ --msgbox $"TLS port changed to ${VPN_TLS_PORT}. Forward this port from your internet router." 10 60
+ else
+ dialog --title $"VPN Configuration" \
+ --msgbox $"TLS port changed to ${VPN_TLS_PORT}. Forward this port from your internet router." 10 60
+ fi
fi
fi
;;
From b1d03ec817e46aff9d1ab0aff7d0e2a360c52602 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 25 Oct 2017 17:22:31 +0100
Subject: [PATCH 26/31] cryptpad hostname
---
src/freedombone-image-customise | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/freedombone-image-customise b/src/freedombone-image-customise
index ffa51d2e..3240ea2c 100755
--- a/src/freedombone-image-customise
+++ b/src/freedombone-image-customise
@@ -897,7 +897,7 @@ function configure_user_interface {
#!/bin/bash
ethernet_connected=\$(cat /sys/class/net/eth0/carrier)
users_list=\$(lstox | awk -F ' ' '{\$1=""; print \$0}' | sed -e 's/^[[:space:]]*//' | sort -d | uniq)
-if [ ! \$users_list ]; then
+if [ \${#users_list} -eq 0 ]; then
no_of_users=0
else
no_of_users=\$(echo "\$users_list" | wc -l)
@@ -933,15 +933,15 @@ if [ \$no_of_users -gt 0 ]; then
echo 'Name=CryptPad' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Type=Application' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Comment=Realtime collaborative editing of documents' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
- echo "Exec=$BROWSER http://${HOSTNAME}.local" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ echo "Exec=$BROWSER http://\${HOSTNAME}.local" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo "Icon=/etc/cryptpad/icon_cryptpad.png" >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Terminal=false' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
echo 'Categories=Application;' >> /home/$MY_USERNAME/Desktop/cryptpad.desktop
chmod +x /home/$MY_USERNAME/Desktop/cryptpad.desktop
chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/Desktop/cryptpad.desktop
else
- if ! grep -q "${HOSTNAME}.local" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
- sed -i "s|Exec=.*|Exec=$BROWSER http://${HOSTNAME}.local|g" /home/$MY_USERNAME/Desktop/cryptpad.desktop
+ if ! grep -q "\${HOSTNAME}.local" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
+ sed -i "s|Exec=.*|Exec=$BROWSER http://\${HOSTNAME}.local|g" /home/$MY_USERNAME/Desktop/cryptpad.desktop
fi
if grep -q "Offline" /home/$MY_USERNAME/Desktop/cryptpad.desktop; then
sed -i 's|Name=.*|Name=CryptPad|g' /home/$MY_USERNAME/Desktop/cryptpad.desktop
From 76a3f0a5332ea1b7f9fdf385fc69de9fa26a7803 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 25 Oct 2017 17:41:13 +0100
Subject: [PATCH 27/31] cryptpad images
---
img/mesh_cryptpad1.jpg | Bin 0 -> 114786 bytes
img/mesh_cryptpad2.jpg | Bin 0 -> 79804 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 img/mesh_cryptpad1.jpg
create mode 100644 img/mesh_cryptpad2.jpg
diff --git a/img/mesh_cryptpad1.jpg b/img/mesh_cryptpad1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5c6984c4f75467f1b00c1ac10407a3797b281cff
GIT binary patch
literal 114786
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
Z$<&b^VOC@Z`0>~r2_Wr!_nErgx{?*ZpNKL}~tf
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