diff --git a/onionr/api.py b/onionr/api.py index 146d43c5..94c7eeaa 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -22,7 +22,7 @@ from flask import request, Response, abort, send_from_directory from multiprocessing import Process from gevent.pywsgi import WSGIServer import sys, random, threading, hmac, hashlib, base64, time, math, os, json -from core import Core +import core from onionrblockapi import Block import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config @@ -69,7 +69,7 @@ class API: logger.debug('%s not in %s' % (path, mimetypes)) return 'text/plain' - def __init__(self, debug): + def __init__(self, debug, API_VERSION): ''' Initialize the api server, preping variables for later use @@ -88,7 +88,7 @@ class API: self.debug = debug self._privateDelayTime = 3 - self._core = Core() + self._core = core.Core() self._crypto = onionrcrypto.OnionrCrypto(self._core) self._utils = onionrutils.OnionrUtils(self._core) app = flask.Flask(__name__) @@ -133,7 +133,7 @@ class API: resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'" resp.headers['X-Frame-Options'] = 'deny' resp.headers['X-Content-Type-Options'] = "nosniff" - resp.headers['server'] = 'Onionr' + resp.headers['api'] = API_VERSION # reset to text/plain to help prevent browser attacks self.mimeType = 'text/plain' diff --git a/onionr/onionr.py b/onionr/onionr.py index 80737bde..eb56fb7c 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -30,7 +30,6 @@ import webbrowser from threading import Thread import api, core, config, logger, onionrplugins as plugins, onionrevents as events import onionrutils -from onionrutils import OnionrUtils from netcontroller import NetController from onionrblockapi import Block import onionrproofs, onionrexceptions, onionrusers @@ -98,7 +97,7 @@ class Onionr: logger.set_level(logger.LEVEL_INFO) self.onionrCore = core.Core() - self.onionrUtils = OnionrUtils(self.onionrCore) + self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore) # Handle commands @@ -636,7 +635,7 @@ class Onionr: ''' communicatorDaemon = './communicator2.py' - apiThread = Thread(target=api.API, args=(self.debug,)) + apiThread = Thread(target=api.API, args=(self.debug,API_VERSION)) apiThread.start() try: time.sleep(3) diff --git a/onionr/onionrexceptions.py b/onionr/onionrexceptions.py index f3cefe36..d450e3ae 100644 --- a/onionr/onionrexceptions.py +++ b/onionr/onionrexceptions.py @@ -65,6 +65,9 @@ class MissingPort(Exception): class InvalidAddress(Exception): pass +class InvalidAPIVersion(Exception): + pass + # file exceptions class DiskAllocationReached(Exception): diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index a17d27bc..5cc79e90 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -22,6 +22,7 @@ import getpass, sys, requests, os, socket, hashlib, logger, sqlite3, config, bin import nacl.signing, nacl.encoding from onionrblockapi import Block import onionrexceptions +from onionr import API_VERSION from defusedxml import minidom import onionrevents import pgpwords, onionrusers, storagecounter @@ -614,11 +615,16 @@ class OnionrUtils: try: proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)} r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30)) + # Check server is using same API version as us + if r.headers['api'] != str(API_VERSION): + raise onionrexceptions.InvalidAPIVersion retData = r.text except KeyboardInterrupt: raise KeyboardInterrupt except ValueError as e: logger.debug('Failed to make request', error = e) + except onionrexceptions.InvalidAPIVersion: + logger.debug("Node is using different API version :(") except requests.exceptions.RequestException as e: if not 'ConnectTimeoutError' in str(e) and not 'Request rejected or failed' in str(e): logger.debug('Error: %s' % str(e))