diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..c23774c
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch",
+ "type": "go",
+ "request": "launch",
+ "mode": "auto",
+ "program": "${fileDirname}",
+ "env": {},
+ "args": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/cyphernodeconf_docker/Dockerfile b/cyphernodeconf_docker/Dockerfile
index e51c158..aefacdc 100644
--- a/cyphernodeconf_docker/Dockerfile
+++ b/cyphernodeconf_docker/Dockerfile
@@ -1,8 +1,24 @@
+FROM golang:1.13-alpine3.10 as builder
+
+RUN apk add git build-base
+
+RUN mkdir -p /go/src/torgen
+
+COPY torgen/torgen.go /go/src/torgen
+
+WORKDIR /go/src/torgen
+
+RUN go get
+
+RUN go build torgen.go
+RUN chmod +x /go/src/torgen/torgen
+
FROM node:12.2.0-alpine
ENV EDITOR=/usr/bin/nano
COPY . /app
+COPY --from=builder /go/src/torgen/torgen /app/torgen
WORKDIR /app
RUN mkdir /data && \
diff --git a/cyphernodeconf_docker/lib/app.js b/cyphernodeconf_docker/lib/app.js
index c9cced2..fd9fe4c 100644
--- a/cyphernodeconf_docker/lib/app.js
+++ b/cyphernodeconf_docker/lib/app.js
@@ -22,6 +22,7 @@ const SplashScreen = require( './splashScreen.js' );
const ansi = require( './ansi.js' );
const features = require('../features.json');
+const torifyables = require('../torifyables.json');
const uaCommentRegexp = /^[a-zA-Z0-9 \.,:_\-\?\/@]+$/; // TODO: look for spec of unsafe chars
const userRegexp = /^[a-zA-Z0-9\._\-]+$/;
@@ -56,6 +57,7 @@ module.exports = class App {
constructor() {
this.features = features;
+ this.torifyables = torifyables;
if( fs.existsSync(path.join('/data', destinationDirName, 'exitStatus.sh')) ) {
fs.unlinkSync(path.join('/data', destinationDirName, 'exitStatus.sh'));
@@ -224,6 +226,9 @@ module.exports = class App {
feature.checked = this.isChecked( 'features', feature.value );
}
+ for( let torifyable of this.torifyables ) {
+ torifyable.checked = this.isChecked( 'torifyables', torifyable.value );
+ }
}
async startWizard() {
@@ -397,6 +402,10 @@ module.exports = class App {
feature.checked = this.isChecked( 'features', feature.value );
}
+ for( let torifyable of this.torifyables ) {
+ torifyable.checked = this.isChecked( 'torifyables', torifyable.value );
+ }
+
const cert = new Cert();
const gatekeeper_cns = cert.cns( this.config.data.gatekeeper_cns );
@@ -638,6 +647,10 @@ module.exports = class App {
return this.features;
}
+ torifyableChoices() {
+ return this.torifyables;
+ }
+
setupDir() {
return this.sessionData.setupDir;
}
diff --git a/cyphernodeconf_docker/prompters/040_tor.js b/cyphernodeconf_docker/prompters/040_tor.js
index 8a85198..198f440 100644
--- a/cyphernodeconf_docker/prompters/040_tor.js
+++ b/cyphernodeconf_docker/prompters/040_tor.js
@@ -10,15 +10,68 @@ const prefix = function() {
return chalk.green(capitalise(name)+': ');
};
+const featureCondition = function(props) {
+ return props.features && props.features.indexOf( name ) != -1;
+};
+
module.exports = {
name: function() {
return name;
},
prompts: function( utils ) {
- return [
- ];
+ return [{
+ // https://github.com/SBoudrias/Inquirer.js#question
+ // input, confirm, list, rawlist, expand, checkbox, password, editor
+ when: featureCondition,
+ type: 'checkbox',
+ name: 'torifyables',
+ message: prefix()+'What features do you want to TORify?'+utils.getHelp('torifyables'),
+ choices: utils.torifyableChoices()
+ }];
+ },
+ {
+ when: featureCondition,
+ type: 'checkbox',
+ name: 'clearnet',
+ default: utils.getDefault( 'clearnet' ),
+ message: prefix()+'What features do you want to allow using clearnet?'+utils.getHelp('clearnet'),
+ choices: [{
+ name: "Bitcoin Node",
+ value: "clearnet_bitcoinnode"
+ },{
+ name: "LN Node",
+ value: "clearnet_lnnode"
+ }]
},
templates: function( props ) {
return [ 'torrc' ];
}
};
+
+// Do you want to access Cyphernode via a TOR Hidden Service?
+// Do you want to access Cyphernode also via clearnet?
+// Do you want your Bitcoin node to use TOR?
+// Do you want your Bitcoin node to also use clearnet?
+// Do you want your LN node to use TOR?
+// Do you want your LN node to also use clearnet?
+// Do you want your OTS client to use TOR?
+// Do you want your Cyphernode callbacks (address watches, TXID watches and OTS notifications) to perform through TOR?
+
+// Do you want TOR?
+// What do you want to TOR?
+// - Cyphernode as Hidden Service
+// - Bitcoin Node
+// - LN Node
+// - OTS stamp, upgrade and verify
+// - OTS Callbacks (webhooks)
+// - Address Watches Callbacks (webhooks)
+// - TXID Watches Callbacks (webhooks)
+
+Certain services can also use clearnet. What do you want to allow to use clearnet?
+- Bitcoin Node
+- LN Node
+
+Do you want to announce your LN node onion address and/or IP address?
+
+What is your public IP address?
+
diff --git a/cyphernodeconf_docker/prompters/100_lightning.js b/cyphernodeconf_docker/prompters/100_lightning.js
index 97a5c1d..501b63f 100644
--- a/cyphernodeconf_docker/prompters/100_lightning.js
+++ b/cyphernodeconf_docker/prompters/100_lightning.js
@@ -60,7 +60,7 @@ module.exports = {
default: utils.getDefault( 'lightning_external_ip' ),
filter: utils.trimFilter,
validate: utils.ipOrFQDNValidator,
- message: prefix()+'What external ip does your lightning node have?'+utils.getHelp('lightning_external_ip'),
+ message: prefix()+'What external IP does your lightning node have?'+utils.getHelp('lightning_external_ip'),
},
{
when: featureCondition,
diff --git a/cyphernodeconf_docker/schema/config-v0.2.3.json b/cyphernodeconf_docker/schema/config-v0.2.3.json
index 55e18c2..16622a4 100644
--- a/cyphernodeconf_docker/schema/config-v0.2.3.json
+++ b/cyphernodeconf_docker/schema/config-v0.2.3.json
@@ -100,6 +100,8 @@
"then": {
"required": [
"tor_datapath"
+ "torifyables",
+ "clearnet"
]
}
},
@@ -193,6 +195,56 @@
]
}
},
+ "torifyables": {
+ "$id": "#/properties/torifyables",
+ "type": "array",
+ "title": "The TORified features of this cyphernode",
+ "default": [],
+ "items": {
+ "$id": "#/properties/torifyables/items",
+ "type": "string",
+ "enum": [
+ "tor_hiddenservice",
+ "tor_bitcoinnode",
+ "tor_lnnode",
+ "tor_otsoperations",
+ "tor_otswebhooks",
+ "tor_addrwatcheswebhooks",
+ "tor_txidwatcheswebhooks"
+ ],
+ "title": "The TORified feature",
+ "default": "",
+ "examples": [
+ "tor_hiddenservice",
+ "tor_bitcoinnode",
+ "tor_lnnode",
+ "tor_otsoperations",
+ "tor_otswebhooks",
+ "tor_addrwatcheswebhooks",
+ "tor_txidwatcheswebhooks"
+ ]
+ }
+ },
+ "clearnet": {
+ "$id": "#/properties/clearnet",
+ "type": "array",
+ "title": "The clearnet-allowed TORified features of this cyphernode",
+ "default": [],
+ "items": {
+ "$id": "#/properties/clearnet/items",
+ "type": "string",
+ "enum": [
+ "clearnet_bitcoinnode",
+ "clearnet_lnnode"
+ ],
+ "title": "The clearnet-allowed TORified feature",
+ "default": "",
+ "examples": [
+ "clearnet_bitcoinnode",
+ "clearnet_lnnode"
+ ]
+ }
+ },
"net": {
"$id": "#/properties/net",
"type": "string",
diff --git a/cyphernodeconf_docker/templates/bitcoin/bitcoin.conf b/cyphernodeconf_docker/templates/bitcoin/bitcoin.conf
index db3710e..0ea411a 100644
--- a/cyphernodeconf_docker/templates/bitcoin/bitcoin.conf
+++ b/cyphernodeconf_docker/templates/bitcoin/bitcoin.conf
@@ -15,10 +15,12 @@ txindex=1
zmqpubrawblock=tcp://0.0.0.0:18501
zmqpubrawtx=tcp://0.0.0.0:18502
-<% if ( features.indexOf('tor') !== -1 ) { %>
+<% if ( features.indexOf('tor_bitcoinnode') !== -1 ) { %>
#tor
proxy=tor:9050
-#onlynet=onion
+<% if ( features.indexOf('clearnet_bitcoinnode') == -1 ) { %>
+onlynet=onion
+<% } %>
listen=1
<% } %>
diff --git a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml
index e5977b9..7806399 100644
--- a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml
+++ b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml
@@ -2,6 +2,54 @@ version: "3"
services:
+ <% if ( features.indexOf('tor') !== -1 ) { %>
+ ##########################
+ # TOR #
+ ##########################
+
+ tor:
+ image: cyphernode/tor:<%= tor_version %>
+ # Sleeping 7 seconds to let lightning and traefik start
+ command: $USER sh -c 'sleep 7 ; export HOME=/tor ; tor -f /tor/torrc'
+ volumes:
+ - "<%= tor_datapath %>:/tor"
+ restart: always
+ networks:
+ - cyphernodenet
+ - cyphernodeappsnet
+# deploy:
+# placement:
+# constraints: [node.hostname==dev]
+ <% } %>
+
+ <% if ( features.indexOf('lightning') !== -1 && lightning_implementation === 'c-lightning' ) { %>
+ ##########################
+ # LIGHTNING #
+ ##########################
+
+ lightning:
+ image: cyphernode/clightning:<%= lightning_version %>
+ command: $USER sh -c 'while [ ! -f "/bitcoin_monitor/up" ]; do echo "bitcoin not ready" ; sleep 10 ; done ; echo "bitcoin ready!" ; lightningd'
+ <% if( lightning_expose ) { %>
+ ports:
+ - "9735:9735"
+ <% } %>
+ volumes:
+ - "<%= lightning_datapath %>:/.lightning"
+ - "<%= bitcoin_datapath %>/bitcoin-client.conf:/.bitcoin/bitcoin.conf:ro"
+ - bitcoin_monitor:/bitcoin_monitor:ro
+ networks:
+ - cyphernodenet
+ restart: always
+ <% if ( features.indexOf('tor') !== -1 ) { %>
+ depends_on:
+ - tor
+ <% } %>
+# deploy:
+# placement:
+# constraints: [node.hostname==dev]
+ <% } %>
+
<% if( bitcoin_mode === 'internal' ) { %>
##########################
# BITCOIN #
@@ -249,51 +297,6 @@ services:
# placement:
# constraints: [node.hostname==dev]
- <% if ( features.indexOf('tor') !== -1 ) { %>
- ##########################
- # TOR #
- ##########################
-
- tor:
- image: cyphernode/tor:<%= tor_version %>
- command: $USER sh -c 'export HOME=/tor && tor -f /tor/torrc'
- volumes:
- - "<%= tor_datapath %>:/tor"
- restart: always
- networks:
- - cyphernodenet
- - cyphernodeappsnet
-# deploy:
-# placement:
-# constraints: [node.hostname==dev]
- <% } %>
-
- <% if ( features.indexOf('lightning') !== -1 && lightning_implementation === 'c-lightning' ) { %>
- ##########################
- # LIGHTNING #
- ##########################
-
- lightning:
- image: cyphernode/clightning:<%= lightning_version %>
- command: $USER sh -c 'while [ ! -f "/bitcoin_monitor/up" ]; do echo "bitcoin not ready" ; sleep 10 ; done ; echo "bitcoin ready!" ; lightningd'
- <% if( lightning_expose ) { %>
- ports:
- - "9735:9735"
- <% } %>
- volumes:
- - "<%= lightning_datapath %>:/.lightning"
- - "<%= bitcoin_datapath %>/bitcoin-client.conf:/.bitcoin/bitcoin.conf:ro"
- - bitcoin_monitor:/bitcoin_monitor:ro
- networks:
- - cyphernodenet
- restart: always
- depends_on:
- - bitcoin
-# deploy:
-# placement:
-# constraints: [node.hostname==dev]
- <% } %>
-
volumes:
bitcoin_monitor:
diff --git a/cyphernodeconf_docker/templates/installer/start.sh b/cyphernodeconf_docker/templates/installer/start.sh
index 8b50e21..297046f 100644
--- a/cyphernodeconf_docker/templates/installer/start.sh
+++ b/cyphernodeconf_docker/templates/installer/start.sh
@@ -56,7 +56,6 @@ fi
export USER=$(id -u <%= default_username %>):$(id -g <%= default_username %>)
<% } %>
-export ARCH=$(uname -m)
current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)"
<% if (docker_mode == 'swarm') { %>
@@ -67,4 +66,11 @@ docker-compose -f $current_path/docker-compose.yaml up -d --remove-orphans
start_apps
+export ARCH=$(uname -m)
+case "${ARCH}" in arm*)
+ printf "\r\n\033[1;31mSince we're on a slow RPi, let's give Docker 60 more seconds before performing our tests...\033[0m\r\n\r\n"
+ sleep 60
+;;
+esac
+
. ./testdeployment.sh
diff --git a/cyphernodeconf_docker/templates/installer/stop.sh b/cyphernodeconf_docker/templates/installer/stop.sh
index 0141273..9ac13ab 100644
--- a/cyphernodeconf_docker/templates/installer/stop.sh
+++ b/cyphernodeconf_docker/templates/installer/stop.sh
@@ -49,12 +49,10 @@ stop_apps() {
. ./.cyphernodeconf/installer/config.sh
stop_apps
-<% if (docker_mode == 'swarm') { %>
export USER=$(id -u):$(id -g)
-export ARCH=$(uname -m)
+
+<% if (docker_mode == 'swarm') { %>
docker stack rm cyphernode
<% } else if(docker_mode == 'compose') { %>
-export USER=$(id -u):$(id -g)
-export ARCH=$(uname -m)
docker-compose -f $current_path/docker-compose.yaml down
<% } %>
diff --git a/cyphernodeconf_docker/templates/installer/testdeployment.sh b/cyphernodeconf_docker/templates/installer/testdeployment.sh
index d08ea2e..1353721 100644
--- a/cyphernodeconf_docker/templates/installer/testdeployment.sh
+++ b/cyphernodeconf_docker/templates/installer/testdeployment.sh
@@ -49,16 +49,8 @@ fi
export USER=$(id -u <%= default_username %>):$(id -g <%= default_username %>)
<% } %>
-export ARCH=$(uname -m)
current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)"
-arch=$(uname -m)
-case "${arch}" in arm*)
- printf "\r\n\033[1;31mSince we're on a slow RPi, let's give Docker 60 more seconds before performing our tests...\033[0m\r\n\r\n"
- sleep 60
-;;
-esac
-
# Will test if Cyphernode is fully up and running...
docker run --rm -it -v $current_path/testfeatures.sh:/testfeatures.sh \
-v <%= gatekeeper_datapath %>:/gatekeeper \
@@ -85,4 +77,8 @@ fi
printf "\r\n\033[0;92mDepending on your current location and DNS settings, point your favorite browser to one of the following URLs to access Cyphernode's status page:\r\n"
printf "\r\n"
printf "\033[0;95m<% cns.forEach(cn => { %><%= ('https://' + cn + '/welcome\\r\\n') %><% }) %>\033[0m\r\n"
+<% if ( features.indexOf('tor') !== -1 ) { %>
+printf "\033[0;92mYou can also use TOR Browser and navigate to your onion address:\r\n"
+printf "\033[0;95mhttps://${TOR_HOSTNAME}/welcome\033[0m\r\n\r\n"
+<% } %>
printf "\033[0;92mUse 'admin' as the username with the configuration password you selected at the beginning of the configuration process.\r\n\r\n\033[0m"
diff --git a/cyphernodeconf_docker/templates/installer/testfeatures.sh b/cyphernodeconf_docker/templates/installer/testfeatures.sh
index 82a9523..f17456e 100644
--- a/cyphernodeconf_docker/templates/installer/testfeatures.sh
+++ b/cyphernodeconf_docker/templates/installer/testfeatures.sh
@@ -440,3 +440,6 @@ result="{${result}]}"
echo "${result}" > /gatekeeper/installation.json
echo "EXIT_STATUS=${finalreturncode}" > /dist/exitStatus.sh
+<% if (features.indexOf('tor') != -1) { %>
+echo "TOR_HOSTNAME=$(cat /dist/cyphernode/tor/hidden_service/hostname)" >> /dist/exitStatus.sh
+<% } %>
diff --git a/cyphernodeconf_docker/templates/lightning/c-lightning/config b/cyphernodeconf_docker/templates/lightning/c-lightning/config
index 501b731..e4df753 100644
--- a/cyphernodeconf_docker/templates/lightning/c-lightning/config
+++ b/cyphernodeconf_docker/templates/lightning/c-lightning/config
@@ -16,13 +16,23 @@ rgb=<%= lightning_nodecolor %>
addr=0.0.0.0:9735
-<% if ( features.indexOf('tor') !== -1 ) { %>
+<% if ( features.indexOf('tor_lnnode') !== -1 ) { %>
#tor
proxy=tor:9050
-#always-use-proxy=true
+<% if ( features.indexOf('clearnet_lnnode') == -1 ) { %>
+always-use-proxy=true
+<% } %>
#disable-dns
<% } else { %>
<% if( locals.lightning_external_ip ) { %>
announce-addr=<%= locals.lightning_external_ip %>:9735
<% } %>
<% } %>
+<% if (lightning_announce) { %>
+ <% if ( features.indexOf('tor_lnnode') !== -1 ) { %>
+ announce-addr=<%= locals.lightning_external_ip %>:1234
+ <% if ( features.indexOf('clearnet_lnnode') == -1 ) { %>
+ announce-addr=onionaddress:9735
+ <% } %>
+ <% } %>
+<% } %>
diff --git a/cyphernodeconf_docker/templates/tor/torrc b/cyphernodeconf_docker/templates/tor/torrc
index 77fa950..18a09eb 100644
--- a/cyphernodeconf_docker/templates/tor/torrc
+++ b/cyphernodeconf_docker/templates/tor/torrc
@@ -1,3 +1,4 @@
+<% if ( features.indexOf('tor_hiddenservice') !== -1 ) { %>
HiddenServiceDir /tor/hidden_service/
HiddenServiceVersion 3
HiddenServicePort 80 traefik:80
@@ -5,5 +6,7 @@ HiddenServicePort 443 traefik:443
<% if ( features.indexOf('lightning') !== -1 ) { %>
HiddenServicePort 1234 lightning:9735
<% } %>
+<% } %>
+
SocksPort 0.0.0.0:9050
ExitPolicy reject *:* # no exits allowed
diff --git a/cyphernodeconf_docker/torgen/torgen.go b/cyphernodeconf_docker/torgen/torgen.go
new file mode 100644
index 0000000..8eab44a
--- /dev/null
+++ b/cyphernodeconf_docker/torgen/torgen.go
@@ -0,0 +1,125 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 kexkey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILIT * Y, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package main
+
+import (
+ "bytes"
+ "encoding/base32"
+ "fmt"
+ "os"
+ "path"
+ "strings"
+
+ "crypto/ed25519"
+ "crypto/sha512"
+
+ "golang.org/x/crypto/sha3"
+)
+
+func main() {
+
+ path := path.Clean(os.Args[1])
+ fmt.Println("path=" + path)
+
+ /**
+ About the key files format: https://gitweb.torproject.org/tor.git/tree/src/lib/crypt_ops/crypto_format.c?h=tor-0.4.1.6#n34
+
+ Write the datalen bytes from data to the file named
+ fname in the tagged-data format. This format contains a
+ 32-byte header, followed by the data itself. The header is the
+ NUL-padded string "== typestring: tag ==". The length
+ of typestring and tag must therefore be no more than
+ 24.
+
+ About the secret key format: https://gitweb.torproject.org/tor.git/tree/src/lib/crypt_ops/crypto_ed25519.h?h=tor-0.4.1.6#n29
+
+ Note that we store secret keys in an expanded format that doesn't match
+ the format from standard ed25519. Ed25519 stores a 32-byte value k and
+ expands it into a 64-byte H(k), using the first 32 bytes for a multiplier
+ of the base point, and second 32 bytes as an input to a hash function
+ for deriving r. But because we implement key blinding, we need to store
+ keys in the 64-byte expanded form.
+ **/
+
+ // Key pair generation
+ fmt.Println("Generating ed25519 keys...")
+ publicKey, privateKey, _ := ed25519.GenerateKey(nil)
+
+ // Convert seed to expanded private key...
+ // Ref.: https://gitweb.torproject.org/tor.git/tree/src/ext/ed25519/donna/ed25519_tor.c?h=tor-0.4.1.6#n61
+ // Ref.: https://gitweb.torproject.org/tor.git/tree/src/ext/curve25519_donna/README?h=tor-0.4.1.6#n28
+ fmt.Println("Converting keys for TOR...")
+ h := sha512.Sum512(privateKey[:32])
+ h[0] &= 248
+ h[31] &= 127
+ h[31] |= 64
+
+ // Create the Tor Hidden Service private key file
+ fmt.Println("Creating secret file...")
+ var fileBytes bytes.Buffer
+ fileBytes.Write([]byte("== ed25519v1-secret: type0 =="))
+ fileBytes.Write(bytes.Repeat([]byte{0x00}, 3))
+ fileBytes.Write(h[:])
+
+ prvFile, _ := os.Create(path + "/hs_ed25519_secret_key")
+ fileBytes.WriteTo(prvFile)
+ prvFile.Close()
+
+ // Create the Tor Hidden Service public key file
+ fmt.Println("Creating public file...")
+ fileBytes.Reset()
+ fileBytes.Write([]byte("== ed25519v1-public: type0 =="))
+ fileBytes.Write(bytes.Repeat([]byte{0x00}, 3))
+ fileBytes.Write([]byte(publicKey))
+
+ pubFile, _ := os.Create(path + "/hs_ed25519_public_key")
+ fileBytes.WriteTo(pubFile)
+ pubFile.Close()
+
+ // From https://github.com/rdkr/oniongen-go
+ // checksum = H(".onion checksum" || pubkey || version)
+ fmt.Println("Creating onion address...")
+ var checksumBytes bytes.Buffer
+ checksumBytes.Write([]byte(".onion checksum"))
+ checksumBytes.Write([]byte(publicKey))
+ checksumBytes.Write([]byte{0x03})
+ checksum := sha3.Sum256(checksumBytes.Bytes())
+
+ // onion_address = base32(pubkey || checksum || version)
+ var onionAddressBytes bytes.Buffer
+ onionAddressBytes.Write([]byte(publicKey))
+ onionAddressBytes.Write([]byte(checksum[:2]))
+ onionAddressBytes.Write([]byte{0x03})
+ onionAddress := base32.StdEncoding.EncodeToString(onionAddressBytes.Bytes())
+
+ // Create the Tor Hidden Service hostname file
+ fmt.Println("Creating onion address file...")
+ nameFile, _ := os.Create(path + "/hostname")
+ nameFile.WriteString(strings.ToLower(onionAddress) + ".onion\n")
+ nameFile.Close()
+
+ fmt.Println("Done!")
+
+}
diff --git a/cyphernodeconf_docker/torifyables.json b/cyphernodeconf_docker/torifyables.json
new file mode 100644
index 0000000..93da55d
--- /dev/null
+++ b/cyphernodeconf_docker/torifyables.json
@@ -0,0 +1,30 @@
+[
+ {
+ "name": "Cyphernode as Hidden Service",
+ "value": "tor_hiddenservice"
+ },
+ {
+ "name": "Bitcoin Node",
+ "value": "tor_bitcoinnode"
+ },
+ {
+ "name": "LN Node",
+ "value": "tor_lnnode"
+ },
+ {
+ "name": "OTS stamp, upgrade and verify",
+ "value": "tor_otsoperations"
+ },
+ {
+ "name": "OTS Callbacks (webhooks)",
+ "value": "tor_otswebhooks"
+ },
+ {
+ "name": "Address Watches Callbacks (webhooks)",
+ "value": "tor_addrwatcheswebhooks"
+ },
+ {
+ "name": "TXID Watches Callbacks (webhooks)",
+ "value": "tor_txidwatcheswebhooks"
+ }
+]
diff --git a/dist/setup.sh b/dist/setup.sh
index 9297d32..680c91e 100755
--- a/dist/setup.sh
+++ b/dist/setup.sh
@@ -721,6 +721,22 @@ install() {
fi
}
+manage_tor_keys() {
+ until [ -f hostname ] && [ -f hs_ed25519_secret_key ] && [ -f hs_ed25519_public_key ]
+do
+ sleep 0.1
+ max=$(($max-1))
+ if [[ $max == 0 ]]
+ then
+ # Kill Tor on timeout and exit with error code 1.
+ kill -9 $pid >/dev/null 2>&1
+ rm -f torrc hostname hs_ed25519_secret_key hs_ed25519_public_key
+ popd >/dev/null 2>&1
+ exit 1
+ fi
+done
+}
+
CONFIGURE=0
INSTALL=0
RECREATE=0
@@ -813,6 +829,9 @@ if [[ $CONFIGURE == 1 ]]; then
configure $RECREATE
fi
+# If TOR is installed, we want to create the Hidden Serivce hostname now to make it
+# available to LN and whatever needs it at this point...
+manage_tor_keys
if [[ -f "$cyphernodeconf_filepath/installer/config.sh" ]]; then
. "$cyphernodeconf_filepath/installer/config.sh"