From d3c5fe3a5a74b1a691a4c286441dd0a944c280ad Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Wed, 27 Mar 2019 12:38:46 -0500 Subject: [PATCH] added clandestine --- onionr/onionrservices/bootstrapservice.py | 7 + onionr/onionrservices/connectionserver.py | 7 + onionr/onionrsockets.py | 172 ------------------ .../default-plugins/clandestine/controlapi.py | 26 +++ .../default-plugins/clandestine/info.json | 5 + .../default-plugins/clandestine/main.py | 46 +++++ 6 files changed, 91 insertions(+), 172 deletions(-) delete mode 100755 onionr/onionrsockets.py create mode 100644 onionr/static-data/default-plugins/clandestine/controlapi.py create mode 100755 onionr/static-data/default-plugins/clandestine/info.json create mode 100755 onionr/static-data/default-plugins/clandestine/main.py diff --git a/onionr/onionrservices/bootstrapservice.py b/onionr/onionrservices/bootstrapservice.py index 292df4ed..a2952563 100644 --- a/onionr/onionrservices/bootstrapservice.py +++ b/onionr/onionrservices/bootstrapservice.py @@ -23,6 +23,7 @@ from stem.control import Controller from flask import Flask, Response import core from netcontroller import getOpenPort +from . import httpheaders def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): ''' @@ -52,6 +53,12 @@ def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): def get_ping(): return "pong!" + @bootstrap_app.after_request + def afterReq(resp): + # Security headers + resp = httpheaders.set_default_onionr_http_headers(resp) + return resp + @bootstrap_app.route('/bs/
', methods=['POST']) def get_bootstrap(address): if core_inst._utils.validateID(address + '.onion'): diff --git a/onionr/onionrservices/connectionserver.py b/onionr/onionrservices/connectionserver.py index 6b04645c..ee586e2b 100644 --- a/onionr/onionrservices/connectionserver.py +++ b/onionr/onionrservices/connectionserver.py @@ -24,6 +24,7 @@ from flask import Flask import core, logger from netcontroller import getOpenPort import api +from . import httpheaders class ConnectionServer: def __init__(self, peer, address, core_inst=None): @@ -48,6 +49,12 @@ class ConnectionServer: def get_ping(): return "pong!" + @service_app.after_request + def afterReq(resp): + # Security headers + resp = httpheaders.set_default_onionr_http_headers(resp) + return resp + with Controller.from_port(port=core_inst.config.get('tor.controlPort')) as controller: # Connect to the Tor process for Onionr controller.authenticate(core_inst.config.get('tor.controlpassword')) diff --git a/onionr/onionrsockets.py b/onionr/onionrsockets.py deleted file mode 100755 index aa02c3db..00000000 --- a/onionr/onionrsockets.py +++ /dev/null @@ -1,172 +0,0 @@ -''' - Onionr - P2P Anonymous Storage Network - - Onionr Socket interface -''' -''' - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -''' -import stem.control -import threading -import socks, config, uuid -import onionrexceptions, time, requests, onionrblockapi, logger -from dependencies import secrets -from gevent.pywsgi import WSGIServer -from flask import request, Response, abort -import flask -class OnionrSocketServer: - def __init__(self, coreInst): - self._core = coreInst - app = flask.Flask(__name__) - self._core.socketServerConnData = {} - self.bindPort = 0 - - self.sockets = {} - - while self.bindPort < 1024: - self.bindPort = secrets.randbelow(65535) - - self.responseData = {} - - threading.Thread(target=self.detectShutdown).start() - threading.Thread(target=self.socketStarter).start() - app = flask.Flask(__name__) - self.http_server = WSGIServer(('127.0.0.1', self.bindPort), app) - self.http_server.serve_forever() - - @app.route('/dc/', methods=['POST']) - def acceptConn(self): - data = request.form['data'] - data = self._core._utils.bytesTorStr(data) - data = {'date': self._core._utils.getEpoch(), 'data': data} - myPeer = '' - retData = '' - for peer in self.sockets: - if self.sockets[peer] == request.host: - myPeer = peer - break - else: - return "" - - if request.host in self.sockets: - self._core.socketServerConnData[myPeer].append(data) - else: - self._core.socketServerConnData[myPeer] = [data] - - try: - retData = self._core.socketServerResponseData[myPeer] - except KeyError: - pass - else: - self._core.socketServerResponseData[myPeer] = '' - - return retData - - def socketStarter(self): - while not self._core.killSockets: - try: - self.addSocket(self._core.startSocket['peer'], reason=self._core.startSocket['reason']) - except KeyError: - pass - else: - logger.info('%s socket started with %s' % (self._core.startSocket['reason'], self._core.startSocket['peer'])) - self._core.startSocket = {} - time.sleep(1) - - def detectShutdown(self): - while not self._core.killSockets: - time.sleep(5) - - logger.debug('Killing socket server...') - self.http_server.stop() - - def addSocket(self, peer, reason=''): - bindPort = 1337 - - assert len(reason) <= 12 - - with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller: - controller.authenticate(config.get('tor.controlpassword')) - - socket = controller.create_ephemeral_hidden_service({80: bindPort}, await_publication = True) - self.sockets[peer] = socket.service_id + '.onion' - - self.responseData[socket.service_id + '.onion'] = '' - - self._core.insertBlock(str(uuid.uuid4()), header='socket', sign=True, encryptType='asym', asymPeer=peer, meta={'reason': reason, 'address': socket.service_id + '.onion'}) - self._core.socketReasons[peer] = reason - return - -class OnionrSocketClient: - def __init__(self, coreInst): - self.sockets = {} # pubkey: tor address - self.connPool = {} - self.sendData = {} - self._core = coreInst - self.response = '' - self.request = '' - self.connected = False - self.killSocket = False - - def startSocket(self, peer, reason): - address = '' - logger.info('Trying to find socket server for %s' % (peer,)) - # Find the newest open socket for a given peer - for block in self._core.getBlocksByType('socket'): - block = onionrblockapi.Block(block, core=self._core) - if block.decrypt(): - theSigner = block.signer - try: - theSigner = theSigner.decode() - except AttributeError: - pass - if block.verifySig() and theSigner == peer: - address = block.getMetadata('address') - if self._core._utils.validateID(address): - # If we got their address, it is valid, and verified, we can break out - if block.getMetadata('reason') == reason: - break - else: - logger.error('The socket the peer opened is not for %s' % (reason,)) - else: - logger.error('Peer transport id is invalid for socket: %s' % (address,)) - address = '' - else: - logger.warn('Block has invalid sig or id, was for %s' % (theSigner,)) - if address != '': - logger.info('%s socket client started with %s' % (reason, peer)) - self.sockets[peer] = address - data = 'hey' - while not self.killSocket: - try: - data = self.sendData[peer] - logger.info('Sending %s to %s' % (data, peer)) - except KeyError: - pass - else: - self.sendData[peer] = '' - postData = {'data': data} - self.connPool[peer] = {'date': self._core._utils.getEpoch(), 'data': self._core._utils.doPostRequest('http://' + address + '/dc/', data=postData)} - time.sleep(2) - - def getResponse(self, peer): - retData = '' - try: - retData = self.connPool[peer] - except KeyError: - pass - return - - def sendData(self, peer, data): - self.sendData[peer] = data diff --git a/onionr/static-data/default-plugins/clandestine/controlapi.py b/onionr/static-data/default-plugins/clandestine/controlapi.py new file mode 100644 index 00000000..ce341f82 --- /dev/null +++ b/onionr/static-data/default-plugins/clandestine/controlapi.py @@ -0,0 +1,26 @@ +''' + Onionr - P2P Anonymous Storage Network + + HTTP endpoints for controlling IMs +''' +''' + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +''' +from flask import Response, request, redirect, Blueprint, abort + +flask_blueprint = Blueprint('clandenstine', __name__) + +@flask_blueprint.route('/mail/ping') +def ping(): + return 'pong!' diff --git a/onionr/static-data/default-plugins/clandestine/info.json b/onionr/static-data/default-plugins/clandestine/info.json new file mode 100755 index 00000000..7c5a143c --- /dev/null +++ b/onionr/static-data/default-plugins/clandestine/info.json @@ -0,0 +1,5 @@ +{ + "name" : "clandestine", + "version" : "1.0", + "author" : "onionr" +} diff --git a/onionr/static-data/default-plugins/clandestine/main.py b/onionr/static-data/default-plugins/clandestine/main.py new file mode 100755 index 00000000..bc7ca112 --- /dev/null +++ b/onionr/static-data/default-plugins/clandestine/main.py @@ -0,0 +1,46 @@ +''' + Onionr - P2P Anonymous Storage Network + + Instant message conversations with Onionr peers +''' +''' + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +''' + +# Imports some useful libraries +import locale + +locale.setlocale(locale.LC_ALL, '') + +plugin_name = 'clandenstine' +PLUGIN_VERSION = '0.0.0' + +sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) +from . import controlapi +flask_blueprint = controlapi.flask_blueprint + +class Clandenstine: + def __init__(self, pluginapi): + self.myCore = pluginapi.get_core() + +def on_init(api, data = None): + ''' + This event is called after Onionr is initialized, but before the command + inputted is executed. Could be called when daemon is starting or when + just the client is running. + ''' + + pluginapi = api + chat = Clandenstine(pluginapi) + return