added clandestine

master
Kevin Froman 2019-03-27 12:38:46 -05:00
parent 2e75e08879
commit d3c5fe3a5a
6 changed files with 91 additions and 172 deletions

View File

@ -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'):

View File

@ -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'))

View File

@ -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

View 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!'

View File

@ -0,0 +1,5 @@
{
"name" : "clandestine",
"version" : "1.0",
"author" : "onionr"
}

View 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