diff --git a/onionr/api.py b/onionr/api.py index e4a0b5c8..b361e959 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -86,6 +86,7 @@ class API: resp.headers['Content-Type'] = 'text/plain' resp.headers["Content-Security-Policy"] = "default-src 'none'" resp.headers['X-Frame-Options'] = 'deny' + resp.headers['X-Content-Type-Options'] = "nosniff" return resp @app.route('/client/') @@ -105,10 +106,6 @@ class API: resp = Response('Goodbye') elif action == 'stats': resp = Response('me_irl') - elif action == 'init': - # generate PGP key - self._core.generateMainPGP() - pass else: resp = Response('(O_o) Dude what? (invalid command)') endTime = math.floor(time.time()) diff --git a/onionr/communicator.py b/onionr/communicator.py index 649822f2..469d1124 100755 --- a/onionr/communicator.py +++ b/onionr/communicator.py @@ -94,6 +94,11 @@ class OnionrCommunicate: if currentDB != False: if lastDB != currentDB: blocks += self.performGet('getBlockHashes', i) + if currentDB != lastDB: + if self._utils.validateHash(currentDB): + self._core.setPeerInfo(i, "blockDBHash", currentDB) + else: + logger.warn("Peer " + i + " returned malformed hash") blockList = blocks.split('\n') for i in blockList: if not self._utils.validateHash(i): @@ -109,15 +114,16 @@ class OnionrCommunicate: if not peer.endswith('.onion') and not peer.endswith('.onion/'): raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion') socksPort = sys.argv[2] - proxies = {'http': 'socks5://127.0.0.1:' + str(socksPort), 'https': 'socks5://127.0.0.1:' + str(socksPort)} + '''We use socks5h to use tor as DNS''' + proxies = {'http': 'socks5h://127.0.0.1:' + str(socksPort), 'https': 'socks5h://127.0.0.1:' + str(socksPort)} headers = {'user-agent': 'PyOnionr'} url = 'http://' + peer + '/public/?action=' + action if data != None: url = url + '&data=' + data try: r = requests.get(url, headers=headers, proxies=proxies) - except requests.exceptions.RequestException: - logger.warn(action + " failed with peer " + peer) + except requests.exceptions.RequestException as e: + logger.warn(action + " failed with peer " + peer + ": " + e) return False return r.text diff --git a/onionr/core.py b/onionr/core.py index 0df2a698..08955225 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -259,12 +259,17 @@ class Core: key = base64.b64encode(os.urandom(32)) return key - def listPeers(self): + def listPeers(self, randomOrder=True): '''Return a list of peers + + randomOrder determines if the list should be in a random order ''' conn = sqlite3.connect(self.peerDB) c = conn.cursor() - peers = c.execute('SELECT * FROM peers;') + if randomOrder: + peers = c.execute('SELECT * FROM peers order by RANDOM();') + else: + peers = c.execute('SELECT * FROM peers;') peerList = [] for i in peers: peerList.append(i[0]) @@ -310,6 +315,14 @@ class Core: iterCount += 1 conn.close() return retVal + def setPeerInfo(self, peer, key, data): + '''update a peer for a key''' + conn = sqlite3.connect(self.peerDB) + c = conn.cursor() + command = (peer,) + # TODO: validate key on whitelist + + c.execute('UPDATE peers SET ' + key + ' = ' + data + ' where id=?', command) def getBlockList(self, unsaved=False): '''get list of our blocks''' diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py index ccb6545a..7c670802 100644 --- a/onionr/netcontroller.py +++ b/onionr/netcontroller.py @@ -38,6 +38,7 @@ class NetController: ''' return def generateTorrc(self): + '''generate a torrc file for our tor instance''' if os.path.exists(self.torConfigLocation): os.remove(self.torConfigLocation) torrcData = '''SocksPort ''' + str(self.socksPort) + ''' @@ -53,7 +54,15 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' '''Start Tor with onion service on port 80 & socks proxy on random port ''' self.generateTorrc() - tor = subprocess.Popen(['tor', '-f', self.torConfigLocation], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if os.path.exists('./tor'): + torBinary = './tor' + else: + torBinary = 'tor' + try: + tor = subprocess.Popen([torBinary, '-f', self.torConfigLocation], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except FileNotFoundError: + logger.error("Tor was not found in your path or the Onionr directory. Install Tor and try again.") + sys.exit(1) # wait for tor to get to 100% bootstrap for line in iter(tor.stdout.readline, b''): if 'Bootstrapped 100%: Done' in line.decode(): @@ -61,7 +70,8 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' elif 'Opening Socks listener' in line.decode(): logger.debug(line.decode()) else: - logger.error('Failed to start Tor') + logger.error('Failed to start Tor. Try killing any other Tor processes owned by this user.') + return False logger.info('Finished starting Tor') self.readyState = True myID = open('data/hs/hostname', 'r') @@ -70,7 +80,7 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' torPidFile = open('data/torPid.txt', 'w') torPidFile.write(str(tor.pid)) torPidFile.close() - return + return True def killTor(self): '''properly kill tor based on pid saved to file''' try: diff --git a/onionr/onionr.py b/onionr/onionr.py index e6376602..f294b56c 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -25,6 +25,11 @@ import gui, api, core from onionrutils import OnionrUtils from netcontroller import NetController +try: + from urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)") + class Onionr: def __init__(self): '''Main Onionr class. This is for the CLI program, and does not handle much of the logic. @@ -104,6 +109,12 @@ class Onionr: os.remove('.onionr-lock') elif command == 'stop': self.killDaemon() + elif command in ('addmsg', 'addmessage'): + while True: + messageToAdd = input('Broadcast message to network: ') + if len(messageToAdd) >= 1: + break + self.onionrCore.setData(messageToAdd) elif command == 'stats': self.showStats() elif command == 'help' or command == '--help': @@ -124,7 +135,8 @@ class Onionr: if not os.environ.get("WERKZEUG_RUN_MAIN") == "true": net = NetController(self.config['CLIENT']['PORT']) logger.info('Tor is starting...') - net.startTor() + if not net.startTor(): + sys.exit(1) logger.info('Started Tor .onion service: ' + logger.colors.underline + net.myID) time.sleep(1) subprocess.Popen(["./communicator.py", "run", str(net.socksPort)]) @@ -148,6 +160,4 @@ class Onionr: def showHelp(self): '''Show help for Onionr''' return - - -Onionr() +Onionr() \ No newline at end of file