コード例 #1
0
    def testSymmetric(self):
        dataString = "this is a secret message"
        dataBytes = dataString.encode()
        myCore = core.Core()
        crypto = onionrcrypto.OnionrCrypto(myCore)
        key = key = b"tttttttttttttttttttttttttttttttt"

        logger.info("Encrypting: " + dataString, timestamp=True)
        encrypted = crypto.symmetricEncrypt(dataString,
                                            key,
                                            returnEncoded=True)
        logger.info(encrypted, timestamp=True)
        logger.info('Decrypting encrypted string:', timestamp=True)
        decrypted = crypto.symmetricDecrypt(encrypted,
                                            key,
                                            encodedMessage=True)
        logger.info(decrypted, timestamp=True)
        self.assertTrue(True)
コード例 #2
0
    def __init__(self):
        '''
            Initialize Core Onionr library
        '''
        self.queueDB = 'data/queue.db'
        self.peerDB = 'data/peers.db'
        self.blockDB = 'data/blocks.db'
        self.blockDataLocation = 'data/blocks/'
        self.addressDB = 'data/address.db'

        if not os.path.exists('data/'):
            os.mkdir('data/')
        if not os.path.exists('data/blocks/'):
            os.mkdir('data/blocks/')
        if not os.path.exists(self.blockDB):
            self.createBlockDB()

        self._utils = onionrutils.OnionrUtils(self)
        # Initialize the crypto object
        self._crypto = onionrcrypto.OnionrCrypto(self)

        return
コード例 #3
0
ファイル: core.py プロジェクト: InvisaMage/onionr
    def __init__(self, torPort=0):
        '''
            Initialize Core Onionr library
        '''
        # set data dir
        self.dataDir = os.environ.get('ONIONR_HOME',
                                      os.environ.get('DATA_DIR', 'data/'))
        if not self.dataDir.endswith('/'):
            self.dataDir += '/'

        try:
            self.onionrInst = None
            self.queueDB = self.dataDir + 'queue.db'
            self.peerDB = self.dataDir + 'peers.db'
            self.blockDB = self.dataDir + 'blocks.db'
            self.blockDataLocation = self.dataDir + 'blocks/'
            self.blockDataDB = self.blockDataLocation + 'block-data.db'
            self.publicApiHostFile = self.dataDir + 'public-host.txt'
            self.privateApiHostFile = self.dataDir + 'private-host.txt'
            self.addressDB = self.dataDir + 'address.db'
            self.hsAddress = ''
            self.i2pAddress = config.get('i2p.own_addr', None)
            self.bootstrapFileLocation = 'static-data/bootstrap-nodes.txt'
            self.bootstrapList = []
            self.requirements = onionrvalues.OnionrValues()
            self.torPort = torPort
            self.dataNonceFile = self.dataDir + 'block-nonces.dat'
            self.dbCreate = dbcreator.DBCreator(self)
            self.forwardKeysFile = self.dataDir + 'forward-keys.db'
            self.keyStore = simplekv.DeadSimpleKV(self.dataDir +
                                                  'cachedstorage.dat',
                                                  refresh_seconds=5)

            # Socket data, defined here because of multithreading constraints with gevent
            self.killSockets = False
            self.startSocket = {}
            self.socketServerConnData = {}
            self.socketReasons = {}
            self.socketServerResponseData = {}

            self.usageFile = self.dataDir + 'disk-usage.txt'
            self.config = config

            self.maxBlockSize = 10000000  # max block size in bytes

            if not os.path.exists(self.dataDir):
                os.mkdir(self.dataDir)
            if not os.path.exists(self.dataDir + 'blocks/'):
                os.mkdir(self.dataDir + 'blocks/')
            if not os.path.exists(self.blockDB):
                self.createBlockDB()
            if not os.path.exists(self.forwardKeysFile):
                self.dbCreate.createForwardKeyDB()
            if not os.path.exists(self.peerDB):
                self.createPeerDB()
            if not os.path.exists(self.addressDB):
                self.createAddressDB()

            if os.path.exists(self.dataDir + '/hs/hostname'):
                with open(self.dataDir + '/hs/hostname', 'r') as hs:
                    self.hsAddress = hs.read().strip()

            # Load bootstrap address list
            if os.path.exists(self.bootstrapFileLocation):
                with open(self.bootstrapFileLocation, 'r') as bootstrap:
                    bootstrap = bootstrap.read()
                for i in bootstrap.split('\n'):
                    self.bootstrapList.append(i)
            else:
                logger.warn('Warning: address bootstrap file not found ' +
                            self.bootstrapFileLocation)

            self.use_subprocess = powchoice.use_subprocess(self)
            self._utils = onionrutils.OnionrUtils(self)
            # Initialize the crypto object
            self._crypto = onionrcrypto.OnionrCrypto(self)
            self._blacklist = onionrblacklist.OnionrBlackList(self)
            self.serializer = serializeddata.SerializedData(self)

        except Exception as error:
            logger.error('Failed to initialize core Onionr library.',
                         error=error)
            logger.fatal('Cannot recover from error.')
            sys.exit(1)
        return
コード例 #4
0
ファイル: communicator.py プロジェクト: anharismail/onionr
    def __init__(self, debug, developmentMode):
        '''
            OnionrCommunicate

            This class handles communication with nodes in the Onionr network.
        '''

        self._core = core.Core()
        self._utils = onionrutils.OnionrUtils(self._core)
        self._crypto = onionrcrypto.OnionrCrypto(self._core)
        self._netController = netcontroller.NetController(
            0)  # arg is the HS port but not needed rn in this file

        self.newHashes = {
        }  # use this to not keep hashes around too long if we cant get their data
        self.keepNewHash = 12
        self.ignoredHashes = []

        self.highFailureAmount = 7

        self.communicatorThreads = 0
        self.maxThreads = 75
        self.processBlocksThreads = 0
        self.lookupBlocksThreads = 0

        self.blocksProcessing = [
        ]  # list of blocks currently processing, to avoid trying a block twice at once in 2 seperate threads
        self.peerStatus = {
        }  # network actions (active requests) for peers used mainly to prevent conflicting actions in threads

        self.communicatorTimers = {
        }  # communicator timers, name: rate (in seconds)
        self.communicatorTimerCounts = {}
        self.communicatorTimerFuncs = {}

        self.registerTimer('blockProcess', 20)
        self.registerTimer('highFailure', 10)
        self.registerTimer('heartBeat', 10)
        self.registerTimer('pex', 120)
        logger.debug('Communicator debugging enabled.')

        with open('data/hs/hostname', 'r') as torID:
            todID = torID.read()

        apiRunningCheckRate = 10
        apiRunningCheckCount = 0

        self.peerData = {
        }  # Session data for peers (recent reachability, speed, etc)

        if os.path.exists(self._core.queueDB):
            self._core.clearDaemonQueue()

        # Loads in and starts the enabled plugins
        plugins.reload()

        while True:
            command = self._core.daemonQueue()
            # Process blocks based on a timer
            self.timerTick()
            # TODO: migrate below if statements to be own functions which are called in the above timerTick() function
            if self.communicatorTimers[
                    'highFailure'] == self.communicatorTimerCounts[
                        'highFailure']:
                self.communicatorTimerCounts['highFailure'] = 0
                for i in self.peerData:
                    if self.peerData[i]['failCount'] >= self.highFailureAmount:
                        self.peerData[i]['failCount'] -= 1
            if self.communicatorTimers['pex'] == self.communicatorTimerCounts[
                    'pex']:
                pT1 = threading.Thread(target=self.getNewPeers, name="pT1")
                pT1.start()
                pT2 = threading.Thread(target=self.getNewPeers, name="pT2")
                pT2.start()
                self.communicatorTimerCounts[
                    'pex'] = 0  # TODO: do not reset timer if low peer count
            if self.communicatorTimers[
                    'heartBeat'] == self.communicatorTimerCounts['heartBeat']:
                logger.debug('Communicator heartbeat')
                self.communicatorTimerCounts['heartBeat'] = 0
            if self.communicatorTimers[
                    'blockProcess'] == self.communicatorTimerCounts[
                        'blockProcess']:
                lT1 = threading.Thread(target=self.lookupBlocks,
                                       name="lt1",
                                       args=(True, ))
                lT2 = threading.Thread(target=self.lookupBlocks,
                                       name="lt2",
                                       args=(True, ))
                lT3 = threading.Thread(target=self.lookupBlocks,
                                       name="lt3",
                                       args=(True, ))
                lT4 = threading.Thread(target=self.lookupBlocks,
                                       name="lt4",
                                       args=(True, ))
                pbT1 = threading.Thread(target=self.processBlocks,
                                        name='pbT1',
                                        args=(True, ))
                pbT2 = threading.Thread(target=self.processBlocks,
                                        name='pbT2',
                                        args=(True, ))
                pbT3 = threading.Thread(target=self.processBlocks,
                                        name='pbT3',
                                        args=(True, ))
                pbT4 = threading.Thread(target=self.processBlocks,
                                        name='pbT4',
                                        args=(True, ))
                if (self.maxThreads - 8) >= threading.active_count():
                    lT1.start()
                    lT2.start()
                    lT3.start()
                    lT4.start()
                    pbT1.start()
                    pbT2.start()
                    pbT3.start()
                    pbT4.start()
                    self.communicatorTimerCounts['blockProcess'] = 0
                else:
                    logger.debug(threading.active_count())
                    logger.debug('Too many threads.')
            if command != False:
                if command[0] == 'shutdown':
                    logger.info('Daemon received exit command.',
                                timestamp=True)
                    break
                elif command[0] == 'announceNode':
                    announceAttempts = 3
                    announceAttemptCount = 0
                    announceVal = False
                    logger.info('Announcing node to ' + command[1],
                                timestamp=True)
                    while not announceVal:
                        announceAttemptCount += 1
                        announceVal = self.performGet(
                            'announce',
                            command[1],
                            data=self._core.hsAdder.replace('\n', ''),
                            skipHighFailureAddress=True)
                        logger.info(announceVal)
                        if announceAttemptCount >= announceAttempts:
                            logger.warn('Unable to announce to ' + command[1])
                            break
                elif command[0] == 'runCheck':
                    logger.info('Status check; looks good.')
                    open('data/.runcheck', 'w+').close()
                elif command[0] == 'kex':
                    self.pexCount = pexTimer - 1
                elif command[0] == 'event':
                    # todo
                    pass
                elif command[0] == 'checkCallbacks':
                    try:
                        data = json.loads(command[1])

                        logger.info(
                            'Checking for callbacks with connection %s...' %
                            data['id'])

                        self.check_callbacks(
                            data, config.get('dc_execcallbacks', True))

                        events.event('incoming_direct_connection',
                                     data={
                                         'callback': True,
                                         'communicator': self,
                                         'data': data
                                     })
                    except Exception as e:
                        logger.error(
                            'Failed to interpret callbacks for checking', e)
                elif command[0] == 'incomingDirectConnection':
                    try:
                        data = json.loads(command[1])

                        logger.info('Handling incoming connection %s...' %
                                    data['id'])

                        self.incoming_direct_connection(data)

                        events.event('incoming_direct_connection',
                                     data={
                                         'callback': False,
                                         'communicator': self,
                                         'data': data
                                     })
                    except Exception as e:
                        logger.error('Failed to handle callbacks for checking',
                                     e)

            apiRunningCheckCount += 1

            # check if local API is up
            if apiRunningCheckCount > apiRunningCheckRate:
                if self._core._utils.localCommand('ping') != 'pong':
                    for i in range(4):
                        if self._utils.localCommand('ping') == 'pong':
                            apiRunningCheckCount = 0
                            break  # break for loop
                        time.sleep(1)
                    else:
                        # This executes if the api is NOT detected to be running
                        logger.error(
                            'Daemon detected API crash (or otherwise unable to reach API after long time), stopping...'
                        )
                        break  # break main daemon loop
                apiRunningCheckCount = 0

            time.sleep(1)

        self._netController.killTor()
        return
コード例 #5
0
ファイル: api.py プロジェクト: 20esaua/onionr
    def __init__(self, debug):
        '''
            Initialize the api server, preping variables for later use

            This initilization defines all of the API entry points and handlers for the endpoints and errors
            This also saves the used host (random localhost IP address) to the data folder in host.txt
        '''

        config.reload()

        if config.get('devmode', True):
            self._developmentMode = True
            logger.set_level(logger.LEVEL_DEBUG)
        else:
            self._developmentMode = False
            logger.set_level(logger.LEVEL_INFO)

        self.debug = debug
        self._privateDelayTime = 3
        self._core = Core()
        self._crypto = onionrcrypto.OnionrCrypto(self._core)
        self._utils = onionrutils.OnionrUtils(self._core)
        app = flask.Flask(__name__)
        bindPort = int(config.get('client')['port'])
        self.bindPort = bindPort
        self.clientToken = config.get('client')['client_hmac']
        if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
            logger.debug('Your HMAC token: ' + logger.colors.underline +
                         self.clientToken)

        if not debug and not self._developmentMode:
            hostNums = [
                random.randint(1, 255),
                random.randint(1, 255),
                random.randint(1, 255)
            ]
            self.host = '127.' + str(hostNums[0]) + '.' + str(
                hostNums[1]) + '.' + str(hostNums[2])
        else:
            self.host = '127.0.0.1'
        hostFile = open('data/host.txt', 'w')
        hostFile.write(self.host)
        hostFile.close()

        @app.before_request
        def beforeReq():
            '''
                Simply define the request as not having yet failed, before every request.
            '''
            self.requestFailed = False

            return

        @app.after_request
        def afterReq(resp):
            if not self.requestFailed:
                resp.headers['Access-Control-Allow-Origin'] = '*'
            else:
                resp.headers['server'] = 'Onionr'
            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/')
        def private_handler():
            startTime = math.floor(time.time())
            # we should keep a hash DB of requests (with hmac) to prevent replays
            action = request.args.get('action')
            #if not self.debug:
            token = request.args.get('token')
            if not self.validateToken(token):
                abort(403)
            self.validateHost('private')
            if action == 'hello':
                resp = Response('Hello, World! ' + request.host)
            elif action == 'shutdown':
                request.environ.get('werkzeug.server.shutdown')()
                resp = Response('Goodbye')
            elif action == 'stats':
                resp = Response('me_irl')
            else:
                resp = Response('(O_o) Dude what? (invalid command)')
            endTime = math.floor(time.time())
            elapsed = endTime - startTime
            if elapsed < self._privateDelayTime:
                time.sleep(self._privateDelayTime - elapsed)

            return resp

        @app.route('/public/')
        def public_handler():
            # Public means it is publicly network accessible
            self.validateHost('public')
            action = request.args.get('action')
            requestingPeer = request.args.get('myID')
            data = request.args.get('data')
            if action == 'firstConnect':
                pass
            elif action == 'ping':
                resp = Response("pong!")
            elif action == 'getHMAC':
                resp = Response(self._crypto.generateSymmetric())
            elif action == 'getSymmetric':
                resp = Response(self._crypto.generateSymmetric())
            elif action == 'getDBHash':
                resp = Response(self._utils.getBlockDBHash())
            elif action == 'getBlockHashes':
                resp = Response(self._core.getBlockList())
            # setData should be something the communicator initiates, not this api
            elif action == 'getData':
                resp = self._core.getData(data)
                if resp == False:
                    abort(404)
                    resp = ""
                resp = Response(resp)
            elif action == 'pex':
                response = ','.join(self._core.listAdders())
                if len(response) == 0:
                    response = 'none'
                resp = Response(response)
            elif action == 'kex':
                response = ','.join(self._core.listPeers())
                if len(response) == 0:
                    response = 'none'
                resp = Response(response)
            else:
                resp = Response("")

            return resp

        @app.errorhandler(404)
        def notfound(err):
            self.requestFailed = True
            resp = Response("")

            return resp

        @app.errorhandler(403)
        def authFail(err):
            self.requestFailed = True
            resp = Response("403")

            return resp

        @app.errorhandler(401)
        def clientError(err):
            self.requestFailed = True
            resp = Response("Invalid request")

            return resp

        if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
            logger.info('Starting client on ' + self.host + ':' +
                        str(bindPort) + '...')

        try:
            app.run(host=self.host, port=bindPort, debug=True, threaded=True)
        except Exception as e:
            logger.error(str(e))
            logger.fatal('Failed to start client on ' + self.host + ':' +
                         str(bindPort) + ', exiting...')
            exit(1)
コード例 #6
0
    def __init__(self, debug, developmentMode):
        '''
            OnionrCommunicate

            This class handles communication with nodes in the Onionr network.
        '''

        self._core = core.Core()
        self._utils = onionrutils.OnionrUtils(self._core)
        self._crypto = onionrcrypto.OnionrCrypto(self._core)

        self.highFailureAmount = 7
        '''
        logger.info('Starting Bitcoin Node... with Tor socks port:' + str(sys.argv[2]))
        try:
            self.bitcoin = btc.OnionrBTC(torP=int(sys.argv[2]))
        except _gdbm.error:
            pass
        logger.info('Bitcoin Node started, on block: ' + self.bitcoin.node.getBlockHash(self.bitcoin.node.getLastBlockHeight()))
        '''
        #except:
        #logger.fatal('Failed to start Bitcoin Node, exiting...')
        #exit(1)

        blockProcessTimer = 0
        blockProcessAmount = 5
        highFailureTimer = 0
        highFailureRate = 10
        heartBeatTimer = 0
        heartBeatRate = 5
        pexTimer = 5  # How often we should check for new peers
        pexCount = 0
        logger.debug('Communicator debugging enabled.')
        torID = open('data/hs/hostname').read()

        self.peerData = {
        }  # Session data for peers (recent reachability, speed, etc)

        if os.path.exists(self._core.queueDB):
            self._core.clearDaemonQueue()

        # Loads in and starts the enabled plugins
        plugins.reload()

        while True:
            command = self._core.daemonQueue()
            # Process blocks based on a timer
            blockProcessTimer += 1
            heartBeatTimer += 1
            pexCount += 1
            if highFailureTimer == highFailureRate:
                highFailureTimer = 0
                for i in self.peerData:
                    if self.peerData[i]['failCount'] == self.highFailureAmount:
                        self.peerData[i]['failCount'] -= 1
            if pexTimer == pexCount:
                self.getNewPeers()
                pexCount = 0
            if heartBeatRate == heartBeatTimer:
                logger.debug('Communicator heartbeat')
                heartBeatTimer = 0
            if blockProcessTimer == blockProcessAmount:
                self.lookupBlocks()
                self.processBlocks()
                blockProcessTimer = 0
            if command != False:
                if command[0] == 'shutdown':
                    logger.info('Daemon recieved exit command.')
                    break
            time.sleep(1)

        return
コード例 #7
0
    def __init__(self, debug):
        '''
            Initialize the api server, preping variables for later use

            This initilization defines all of the API entry points and handlers for the endpoints and errors
            This also saves the used host (random localhost IP address) to the data folder in host.txt
        '''

        config.reload()

        if config.get('devmode', True):
            self._developmentMode = True
            logger.set_level(logger.LEVEL_DEBUG)
        else:
            self._developmentMode = False
            logger.set_level(logger.LEVEL_INFO)

        self.debug = debug
        self._privateDelayTime = 3
        self._core = Core()
        self._crypto = onionrcrypto.OnionrCrypto(self._core)
        self._utils = onionrutils.OnionrUtils(self._core)
        app = flask.Flask(__name__)
        bindPort = int(config.get('client')['port'])
        self.bindPort = bindPort
        self.clientToken = config.get('client')['client_hmac']
        self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()

        self.i2pEnabled = config.get('i2p')['host']

        self.mimeType = 'text/plain'

        with open('data/time-bypass.txt', 'w') as bypass:
            bypass.write(self.timeBypassToken)

        if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
            logger.debug('Your web password (KEEP SECRET): ' +
                         logger.colors.underline + self.clientToken)

        if not debug and not self._developmentMode:
            hostNums = [
                random.randint(1, 255),
                random.randint(1, 255),
                random.randint(1, 255)
            ]
            self.host = '127.' + str(hostNums[0]) + '.' + str(
                hostNums[1]) + '.' + str(hostNums[2])
        else:
            self.host = '127.0.0.1'
        hostFile = open('data/host.txt', 'w')
        hostFile.write(self.host)
        hostFile.close()

        @app.before_request
        def beforeReq():
            '''
                Simply define the request as not having yet failed, before every request.
            '''
            self.requestFailed = False

            return

        @app.after_request
        def afterReq(resp):
            if not self.requestFailed:
                resp.headers['Access-Control-Allow-Origin'] = '*'
            #else:
            #    resp.headers['server'] = 'Onionr'
            resp.headers['Content-Type'] = self.mimeType
            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'

            # reset to text/plain to help prevent browser attacks
            if self.mimeType != 'text/plain':
                self.mimeType = 'text/plain'

            return resp

        @app.route('/client/')
        def private_handler():
            if request.args.get('timingToken') is None:
                timingToken = ''
            else:
                timingToken = request.args.get('timingToken')
            data = request.args.get('data')
            try:
                data = data
            except:
                data = ''
            startTime = math.floor(time.time())
            # we should keep a hash DB of requests (with hmac) to prevent replays
            action = request.args.get('action')
            #if not self.debug:
            token = request.args.get('token')

            if not self.validateToken(token):
                abort(403)
            self.validateHost('private')
            if action == 'hello':
                resp = Response('Hello, World! ' + request.host)
            elif action == 'shutdown':
                # request.environ.get('werkzeug.server.shutdown')()
                self.http_server.stop()
                resp = Response('Goodbye')
            elif action == 'ping':
                resp = Response('pong')
            elif action == 'stats':
                resp = Response('me_irl')
                raise Exception
            elif action == 'site':
                block = data
                siteData = self._core.getData(data)
                response = 'not found'
                if siteData != '' and siteData != False:
                    self.mimeType = 'text/html'
                    response = siteData.split(b'-', 2)[-1]
                resp = Response(response)
            else:
                resp = Response('(O_o) Dude what? (invalid command)')
            endTime = math.floor(time.time())
            elapsed = endTime - startTime

            # if bypass token not used, delay response to prevent timing attacks
            if not hmac.compare_digest(timingToken, self.timeBypassToken):
                if elapsed < self._privateDelayTime:
                    time.sleep(self._privateDelayTime - elapsed)

            return resp

        @app.route('/')
        def banner():
            self.mimeType = 'text/html'
            self.validateHost('public')
            try:
                with open('static-data/index.html', 'r') as html:
                    resp = Response(html.read())
            except FileNotFoundError:
                resp = Response("")
            return resp

        @app.route('/public/')
        def public_handler():
            # Public means it is publicly network accessible
            self.validateHost('public')
            action = request.args.get('action')
            requestingPeer = request.args.get('myID')
            data = request.args.get('data')
            try:
                data = data
            except:
                data = ''
            if action == 'firstConnect':
                pass
            elif action == 'ping':
                resp = Response("pong!")
            elif action == 'getHMAC':
                resp = Response(self._crypto.generateSymmetric())
            elif action == 'getSymmetric':
                resp = Response(self._crypto.generateSymmetric())
            elif action == 'getDBHash':
                resp = Response(self._utils.getBlockDBHash())
            elif action == 'getBlockHashes':
                resp = Response('\n'.join(self._core.getBlockList()))
            elif action == 'directMessage':
                resp = Response(self._core.handle_direct_connection(data))
            elif action == 'announce':
                if data != '':
                    # TODO: require POW for this
                    if self._core.addAddress(data):
                        resp = Response('Success')
                    else:
                        resp = Response('')
                else:
                    resp = Response('')
            # setData should be something the communicator initiates, not this api
            elif action == 'getData':
                if self._utils.validateHash(data):
                    if not os.path.exists('data/blocks/' + data + '.db'):
                        try:
                            resp = base64.b64encode(self._core.getData(data))
                        except TypeError:
                            resp = ""
                if resp == False:
                    abort(404)
                    resp = ""
                resp = Response(resp)
            elif action == 'pex':
                response = ','.join(self._core.listAdders())
                if len(response) == 0:
                    response = 'none'
                resp = Response(response)
            elif action == 'kex':
                peers = self._core.listPeers(getPow=True)
                response = ','.join(peers)
                resp = Response(response)
            else:
                resp = Response("")

            return resp

        @app.errorhandler(404)
        def notfound(err):
            self.requestFailed = True
            resp = Response("")

            return resp

        @app.errorhandler(403)
        def authFail(err):
            self.requestFailed = True
            resp = Response("403")

            return resp

        @app.errorhandler(401)
        def clientError(err):
            self.requestFailed = True
            resp = Response("Invalid request")

            return resp

        if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
            logger.info('Starting client on ' + self.host + ':' +
                        str(bindPort) + '...',
                        timestamp=True)

        try:
            self.http_server = WSGIServer((self.host, bindPort), app)
            self.http_server.serve_forever()
        except KeyboardInterrupt:
            pass
            #app.run(host=self.host, port=bindPort, debug=False, threaded=True)
        except Exception as e:
            logger.error(str(e))
            logger.fatal('Failed to start client on ' + self.host + ':' +
                         str(bindPort) + ', exiting...')
            exit(1)