Initial Tor integration option

This commit is contained in:
Keith Mukai 2019-10-19 18:37:02 -05:00
parent 07d8b10fba
commit 63a77be2d3
6 changed files with 148 additions and 2 deletions

3
.env_example Normal file
View file

@ -0,0 +1,3 @@
# The cleartext password that was entered into:
# $ tor --hash-password "your-tor-passphrase"
TOR_PASSWORD=your-tor-passphrase

9
.flaskenv Normal file
View file

@ -0,0 +1,9 @@
PORT=25441
# If you want to serve over a Tor hidden service, also set FLASK_ENV=production.
# (The autoreloading in 'development' mode causes problems with the Tor connector)
CONNECT_TOR=False
#FLASK_ENV=production
FLASK_ENV=development

6
.gitignore vendored
View file

@ -1 +1,5 @@
*.pyc
__pycache__
*.pyc
.env
.tor_service_key

View file

@ -15,6 +15,12 @@ from specter import Specter, purposes, addrtypes
from datetime import datetime
import urllib
from pathlib import Path
env_path = Path('.') / '.flaskenv'
from dotenv import load_dotenv
load_dotenv(env_path)
if getattr(sys, 'frozen', False):
template_folder = os.path.join(sys._MEIPASS, 'templates')
static_folder = os.path.join(sys._MEIPASS, 'static')
@ -483,4 +489,11 @@ if __name__ == '__main__':
if os.path.isfile(filename):
extra_files.append(filename)
app.run(port=25441, debug=debug, extra_files=extra_files)
if os.getenv('CONNECT_TOR', False):
from tor import tor_util
tor_util.run_on_hidden_service(app, port=os.getenv('PORT'), debug=debug, extra_files=extra_files)
else:
app.run(port=os.getenv('PORT'), debug=debug, extra_files=extra_files)

80
tor/README.md Normal file
View file

@ -0,0 +1,80 @@
## Running Specter Desktop over a Tor hidden service
Specter Desktop protects your security and privacy by running on a local server that only talks to your own bitcoin node. But what if you need to check a wallet balance or generate and sign transactions when you're away from your home network?
Configuring your router to let you VPN into your home network is probably the easiest solution.
But you can also make Specter Desktop available outside of your network via a Tor hidden service. A hidden service generates a secret .onion address that only you know and which can be accessed from a Tor browser from anywhere in the world. This does not require any port forwarding on your router.
### Security note
Tor support, like Specter Desktop as a whole, should be treated as a work-in-progress that is not yet vetted as being fully secure.
### Install Tor service
Install Tor on the same server that you'll be running Specter Desktop:
* [Debian / Ubuntu](https://2019.www.torproject.org/docs/debian.html.en)
* [macOS](https://2019.www.torproject.org/docs/tor-doc-osx.html.en)
### Configure Tor authentication
```
$ tor --hash-password "your-tor-passphrase"
```
That returns a password hash such as:
```
16:CE9058DA89498A4160373C70FF7FFF70CC2E20B6788FC48F5C35B2E85B
```
Update your `torrc` config file (usually `/etc/tor/torrc` or `/usr/local/etc/tor/torrc` on macOS Homebrew installs). Uncomment the `ControlPort` line as well as the `HashedControlPassword` line. Remember to paste in your own hashed password result from above.
```
## The port on which Tor will listen for local connections from Tor
## controller applications, as documented in control-spec.txt.
ControlPort 9051
## If you enable the controlport, be sure to enable one of these
## authentication methods, to prevent attackers from accessing it.
HashedControlPassword 16:CE9058DA89498A4160373C70FF7FFF70CC2E20B6788FC48F5C35B2E85B
#CookieAuthentication 1
```
Restart the Tor service:
* `sudo /etc/init.d/tor restart` on linux
* `brew services restart tor` on macOS Homebrew installs
### Configure Specter Desktop to connect to Tor
Update the `.flaskenv` file in the project root. Set `CONNECT_TOR` to 'True' and set `FLASK_ENV` to 'production':
```
PORT=25441
# If you want to serve over a Tor hidden service, also set FLASK_ENV=production.
# (The autoreloading in 'development' mode causes problems with the Tor connector)
CONNECT_TOR=False
FLASK_ENV=production
#FLASK_ENV=development
```
### Specify Tor secrets
The Tor password that we hashed above will need to be shared with Specter Desktop.
Copy the example `.env_example` file:
```
$ cp .env_example .env
```
And then edit `.env` and specify `TOR_PASSWORD`:
```
# The cleartext password that was entered into:
# $ tor --hash-password "your-tor-passphrase"
TOR_PASSWORD=your-tor-passphrase
```
### Launch with Tor
Now just start Specter Desktop as usual:
```
$ python server.py
```
Amongst the startup output you'll see:
```
* Connecting to tor
Started a new hidden service with the address of abcd1234efgh5678.onion
```
Point a Tor browser at that onion address and you will have (reasonably?) secure access to your Specter Desktop from anywhere in the world!

37
tor/tor_util.py Normal file
View file

@ -0,0 +1,37 @@
import os
import stem
from stem.control import Controller
from dotenv import load_dotenv
load_dotenv() # Load the secrets from .env
def run_on_hidden_service(app, port, debug, extra_files):
with Controller.from_port() as controller:
print(' * Connecting to tor')
controller.authenticate(os.getenv('TOR_PASSWORD'))
key_path = os.path.expanduser('.tor_service_key')
tor_service_id = None
if not os.path.exists(key_path):
service = controller.create_ephemeral_hidden_service({80: port}, await_publication = True)
tor_service_id = service.service_id
print("Started a new hidden service with the address of %s.onion" % tor_service_id)
with open(key_path, 'w') as key_file:
key_file.write('%s:%s' % (service.private_key_type, service.private_key))
else:
with open(key_path) as key_file:
key_type, key_content = key_file.read().split(':', 1)
service = controller.create_ephemeral_hidden_service({80: port}, key_type = key_type, key_content = key_content, await_publication = True)
tor_service_id = service.service_id
print("Resumed %s.onion" % tor_service_id)
try:
app.run(port=port, debug=debug, extra_files=extra_files)
finally:
if tor_service_id:
print(" * Shutting down our hidden service")
controller.remove_ephemeral_hidden_service(tor_service_id)