added clandestine
This commit is contained in:
		
							parent
							
								
									15e321feee
								
							
						
					
					
						commit
						fb32201df3
					
				
					 6 changed files with 91 additions and 172 deletions
				
			
		| 
						 | 
				
			
			@ -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/<address>', methods=['POST'])
 | 
			
		||||
    def get_bootstrap(address):
 | 
			
		||||
        if core_inst._utils.validateID(address + '.onion'):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
'''
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										26
									
								
								onionr/static-data/default-plugins/clandestine/controlapi.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								onionr/static-data/default-plugins/clandestine/controlapi.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
'''
 | 
			
		||||
from flask import Response, request, redirect, Blueprint, abort
 | 
			
		||||
 | 
			
		||||
flask_blueprint = Blueprint('clandenstine', __name__)
 | 
			
		||||
 | 
			
		||||
@flask_blueprint.route('/mail/ping')
 | 
			
		||||
def ping():
 | 
			
		||||
    return 'pong!'
 | 
			
		||||
							
								
								
									
										5
									
								
								onionr/static-data/default-plugins/clandestine/info.json
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								onionr/static-data/default-plugins/clandestine/info.json
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
{
 | 
			
		||||
    "name" : "clandestine",
 | 
			
		||||
    "version" : "1.0",
 | 
			
		||||
    "author" : "onionr"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								onionr/static-data/default-plugins/clandestine/main.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										46
									
								
								onionr/static-data/default-plugins/clandestine/main.py
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue