Commiting temp work, tor in setup

This commit is contained in:
kexkey
2019-11-30 11:07:56 -05:00
committed by kexkey
parent 38fcb90f55
commit 4fd8f445f4
17 changed files with 411 additions and 65 deletions

17
.vscode/launch.json vendored Normal file
View File

@@ -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": []
}
]
}

View File

@@ -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 && \

View File

@@ -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;
}

View File

@@ -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?

View File

@@ -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,

View File

@@ -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",

View File

@@ -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
<% } %>

View File

@@ -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:

View File

@@ -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

View File

@@ -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
<% } %>

View File

@@ -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"

View File

@@ -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
<% } %>

View File

@@ -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
<% } %>
<% } %>
<% } %>

View File

@@ -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

View File

@@ -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 <b>datalen</b> bytes from <b>data</b> to the file named
<b>fname</b> in the tagged-data format. This format contains a
32-byte header, followed by the data itself. The header is the
NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
of <b>typestring</b> and <b>tag</b> 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!")
}

View File

@@ -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"
}
]

19
dist/setup.sh vendored
View File

@@ -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"