fixed config and other bugs, improved connection server

This commit is contained in:
Kevin Froman 2019-05-15 18:25:36 -05:00
parent 4e3ad27485
commit b582377c8c
11 changed files with 56 additions and 34 deletions

View File

@ -27,10 +27,12 @@ Users are identified by ed25519/curve25519 public keys, which can be used to sig
Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion. Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion.
The whitepaper (subject to change prior to first alpha release) is available [here](docs/whitepaper.md). The whitepaper (subject to change prior to alpha release) is available [here](docs/whitepaper.md).
![node web illustration](docs/onionr-web.png) ![node web illustration](docs/onionr-web.png)
![Tor stinks slide image](docs/tor-stinks-02.png)
## Main Features ## Main Features
* [X] 🌐 Fully p2p/decentralized, no trackers or other single points of failure * [X] 🌐 Fully p2p/decentralized, no trackers or other single points of failure
@ -117,6 +119,4 @@ The 'open source badge' is by Maik Ellerbrock and is licensed under a Creative C
The Onionr logo was created by [Anhar Ismail](https://github.com/anharismail) under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/). The Onionr logo was created by [Anhar Ismail](https://github.com/anharismail) under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).
If you modify and redistribute our code ("forking"), please use a different logo and project name to avoid confusion. Please do not use our logo in a way that makes it seem like we endorse you without our permission. If you modify and redistribute our code ("forking"), please use a different logo and project name to avoid confusion. Please do not use our logo in a way that makes it seem like we endorse you without our permission.
![Tor stinks slide image](docs/tor-stinks-02.png)

View File

@ -81,7 +81,7 @@ class PublicAPI:
def validateRequest(): def validateRequest():
'''Validate request has the correct hostname''' '''Validate request has the correct hostname'''
# If high security level, deny requests to public (HS should be disabled anyway for Tor, but might not be for I2P) # If high security level, deny requests to public (HS should be disabled anyway for Tor, but might not be for I2P)
if config.get('general.security_level', default=0) > 0: if config.get('general.security_level', default=1) > 0:
abort(403) abort(403)
if type(self.torAdder) is None and type(self.i2pAdder) is None: if type(self.torAdder) is None and type(self.i2pAdder) is None:
# abort if our hs addresses are not known # abort if our hs addresses are not known

View File

@ -33,6 +33,7 @@ OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers
config.reload() config.reload()
class OnionrCommunicatorDaemon: class OnionrCommunicatorDaemon:
def __init__(self, onionrInst, proxyPort, developmentMode=config.get('general.dev_mode', False)): def __init__(self, onionrInst, proxyPort, developmentMode=config.get('general.dev_mode', False)):
config.reload()
onionrInst.communicatorInst = self onionrInst.communicatorInst = self
# configure logger and stuff # configure logger and stuff
onionr.Onionr.setupConfig('data/', self = self) onionr.Onionr.setupConfig('data/', self = self)

View File

@ -18,11 +18,13 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import communicator, onionrexceptions import communicator, onionrexceptions
import logger import logger, onionrpeers
def download_blocks_from_communicator(comm_inst): def download_blocks_from_communicator(comm_inst):
assert isinstance(comm_inst, communicator.OnionrCommunicatorDaemon) assert isinstance(comm_inst, communicator.OnionrCommunicatorDaemon)
for blockHash in list(comm_inst.blockQueue): for blockHash in list(comm_inst.blockQueue):
if len(comm_inst.onlinePeers) == 0:
break
triedQueuePeers = [] # List of peers we've tried for a block triedQueuePeers = [] # List of peers we've tried for a block
try: try:
blockPeers = list(comm_inst.blockQueue[blockHash]) blockPeers = list(comm_inst.blockQueue[blockHash])

View File

@ -98,9 +98,6 @@ def check():
if not os.path.exists(os.path.dirname(get_config_file())): if not os.path.exists(os.path.dirname(get_config_file())):
os.makedirs(os.path.dirname(get_config_file())) os.makedirs(os.path.dirname(get_config_file()))
if not os.path.isfile(get_config_file()):
open(get_config_file(), 'a', encoding="utf8").close()
save()
def save(): def save():
''' '''

View File

@ -103,7 +103,7 @@ CookieAuthentication 1
ControlPort ''' + str(controlPort) + ''' ControlPort ''' + str(controlPort) + '''
HashedControlPassword ''' + str(password) + ''' HashedControlPassword ''' + str(password) + '''
''' '''
if config.get('general.security_level') == 0: if config.get('general.security_level', 1) == 0:
torrcData += '''\nHiddenServiceDir ''' + self.dataDir + '''hs/ torrcData += '''\nHiddenServiceDir ''' + self.dataDir + '''hs/
\n''' + hsVer + '''\n \n''' + hsVer + '''\n
HiddenServicePort 80 ''' + self.apiServerIP + ''':''' + str(self.hsPort) HiddenServicePort 80 ''' + self.apiServerIP + ''':''' + str(self.hsPort)

View File

@ -71,7 +71,7 @@ class Onionr:
logger.set_file(os.environ.get('LOG_DIR', 'data') + '/onionr.log') logger.set_file(os.environ.get('LOG_DIR', 'data') + '/onionr.log')
# Load global configuration data # Load global configuration data
data_exists = Onionr.setupConfig(self.dataDir, self = self) data_exists = Onionr.setupConfig(self.dataDir, self)
if netcontroller.torBinary() is None: if netcontroller.torBinary() is None:
logger.error('Tor is not installed') logger.error('Tor is not installed')
@ -122,7 +122,6 @@ class Onionr:
config.set('client.client.port', randomPort, savefile=True) config.set('client.client.port', randomPort, savefile=True)
if type(config.get('client.public.port')) is type(None): if type(config.get('client.public.port')) is type(None):
randomPort = netcontroller.getOpenPort() randomPort = netcontroller.getOpenPort()
print(randomPort)
config.set('client.public.port', randomPort, savefile=True) config.set('client.public.port', randomPort, savefile=True)
if type(config.get('client.participate')) is type(None): if type(config.get('client.participate')) is type(None):
config.set('client.participate', True, savefile=True) config.set('client.participate', True, savefile=True)

View File

@ -50,7 +50,7 @@ def daemon(o_inst):
except FileNotFoundError: except FileNotFoundError:
pass pass
time.sleep(0.5) time.sleep(0.5)
onionr.Onionr.setupConfig('data/', self = o_inst) #onionr.Onionr.setupConfig('data/', self = o_inst)
if o_inst._developmentMode: if o_inst._developmentMode:
logger.warn('DEVELOPMENT MODE ENABLED (NOT RECOMMENDED)', timestamp = False) logger.warn('DEVELOPMENT MODE ENABLED (NOT RECOMMENDED)', timestamp = False)
@ -59,7 +59,7 @@ def daemon(o_inst):
if not net.startTor(): if not net.startTor():
o_inst.onionrUtils.localCommand('shutdown') o_inst.onionrUtils.localCommand('shutdown')
sys.exit(1) sys.exit(1)
if len(net.myID) > 0 and o_inst.onionrCore.config.get('general.security_level') == 0: if len(net.myID) > 0 and o_inst.onionrCore.config.get('general.security_level', 1) == 0:
logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID)) logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID))
else: else:
logger.debug('.onion service disabled') logger.debug('.onion service disabled')

View File

@ -23,6 +23,9 @@ import core
from . import connectionserver, bootstrapservice from . import connectionserver, bootstrapservice
class OnionrServices: class OnionrServices:
'''
Create a client or server for connecting to peer interfaces
'''
def __init__(self, onionr_core): def __init__(self, onionr_core):
assert isinstance(onionr_core, core.Core) assert isinstance(onionr_core, core.Core)
self._core = onionr_core self._core = onionr_core
@ -32,13 +35,19 @@ class OnionrServices:
return return
def create_server(self, peer, address): def create_server(self, peer, address):
'''
When a client wants to connect, contact their bootstrap address and tell them our
ephemeral address for our service by creating a new ConnectionServer instance
'''
assert self._core._utils.validateID(address) assert self._core._utils.validateID(address)
BOOTSTRAP_TRIES = 10 BOOTSTRAP_TRIES = 10 # How many times to attempt contacting the bootstrap server
TRY_WAIT = 3 TRY_WAIT = 3 # Seconds to wait before trying bootstrap again
# HTTP is fine because .onion/i2p is encrypted/authenticated
base_url = 'http://%s/' % (address,) base_url = 'http://%s/' % (address,)
socks = self._core.config.get('tor.socksport') socks = self._core.config.get('tor.socksport')
for x in range(BOOTSTRAP_TRIES): for x in range(BOOTSTRAP_TRIES):
if self._core._utils.doGetRequest(base_url + 'ping', port=socks, ignoreAPI=True) == 'pong!': if self._core._utils.doGetRequest(base_url + 'ping', port=socks, ignoreAPI=True) == 'pong!':
# if bootstrap sever is online, tell them our service address
connectionserver.ConnectionServer(peer, address, core_inst=self._core) connectionserver.ConnectionServer(peer, address, core_inst=self._core)
else: else:
time.sleep(TRY_WAIT) time.sleep(TRY_WAIT)

View File

@ -22,6 +22,7 @@ from gevent.pywsgi import WSGIServer, WSGIHandler
from stem.control import Controller from stem.control import Controller
from flask import Flask from flask import Flask
import core, logger, httpapi import core, logger, httpapi
import onionrexceptions
from netcontroller import getOpenPort from netcontroller import getOpenPort
import api import api
from . import httpheaders from . import httpheaders
@ -66,11 +67,23 @@ class ConnectionServer:
with Controller.from_port(port=core_inst.config.get('tor.controlPort')) as controller: with Controller.from_port(port=core_inst.config.get('tor.controlPort')) as controller:
# Connect to the Tor process for Onionr # Connect to the Tor process for Onionr
controller.authenticate(core_inst.config.get('tor.controlpassword')) controller.authenticate(core_inst.config.get('tor.controlpassword'))
# Create the v3 onion service # Create the v3 onion service for the peer to connect to
response = controller.create_ephemeral_hidden_service({80: service_port}, await_publication = True, key_type='NEW', key_content = 'ED25519-V3') response = controller.create_ephemeral_hidden_service({80: service_port}, await_publication = True, key_type='NEW', key_content = 'ED25519-V3')
self.core_inst.keyStore.put('dc-' + response.service_id, self.core_inst._utils.bytesToStr(peer))
self.core_inst._utils.doPostRequest('http://' + address + '/bs/' + response.service_id, port=socks) try:
logger.info('hosting on %s with %s' % (response.service_id, peer)) for x in range(3):
http_server.serve_forever() attempt = self.core_inst._utils.doPostRequest('http://' + address + '/bs/' + response.service_id, port=socks)
self.core_inst.keyStore.delete('dc-' + response.service_id) if attempt == 'success':
http_server.stop() break
else:
raise ConnectionError
except ConnectionError:
# Re-raise
raise ConnectionError('Could not reach %s bootstrap address %s' % (peer, address))
else:
# If no connection error, create the service and save it to local global key store
self.core_inst.keyStore.put('dc-' + response.service_id, self.core_inst._utils.bytesToStr(peer))
logger.info('hosting on %s with %s' % (response.service_id, peer))
http_server.serve_forever()
http_server.stop()
self.core_inst.keyStore.delete('dc-' + response.service_id)

View File

@ -3,21 +3,22 @@ import config, logger
def setup_config(dataDir, o_inst = None): def setup_config(dataDir, o_inst = None):
data_exists = os.path.exists(dataDir) data_exists = os.path.exists(dataDir)
if not data_exists: if not data_exists:
os.mkdir(dataDir) os.mkdir(dataDir)
config.reload()
if not os.path.exists(config._configfile):
if os.path.exists('static-data/default_config.json'):
# this is the default config, it will be overwritten if a config file already exists. Else, it saves it
with open('static-data/default_config.json', 'r') as configReadIn:
config.set_config(json.loads(configReadIn.read()))
else:
# the default config file doesn't exist, try hardcoded config
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
if os.path.exists('static-data/default_config.json'):
# this is the default config, it will be overwritten if a config file already exists. Else, it saves it
with open('static-data/default_config.json', 'r') as configReadIn:
config.set_config(json.loads(configReadIn.read()))
else:
# the default config file doesn't exist, try hardcoded config
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
if not data_exists:
config.save() config.save()
config.reload() # this will read the configuration file into memory
settings = 0b000 settings = 0b000
if config.get('log.console.color', True): if config.get('log.console.color', True):