Onionr/onionr/onionrsockets.py

173 lines
6.3 KiB
Python
Raw Permalink Normal View History

'''
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/>.
'''
2018-09-15 16:13:03 +00:00
import stem.control
2018-09-23 01:21:39 +00:00
import threading
2018-09-21 04:47:40 +00:00
import socks, config, uuid
2018-09-23 04:53:09 +00:00
import onionrexceptions, time, requests, onionrblockapi, logger
2018-09-15 01:05:25 +00:00
from dependencies import secrets
2018-09-23 04:53:09 +00:00
from gevent.pywsgi import WSGIServer
2018-09-21 04:47:40 +00:00
from flask import request, Response, abort
2018-09-23 04:53:09 +00:00
import flask
2018-09-21 04:47:40 +00:00
class OnionrSocketServer:
def __init__(self, coreInst):
2018-09-24 01:47:27 +00:00
self._core = coreInst
2018-09-23 04:53:09 +00:00
app = flask.Flask(__name__)
2018-09-24 01:47:27 +00:00
self._core.socketServerConnData = {}
self.bindPort = 0
self.sockets = {}
while self.bindPort < 1024:
self.bindPort = secrets.randbelow(65535)
2018-09-22 05:01:17 +00:00
2018-09-21 04:47:40 +00:00
self.responseData = {}
2018-09-22 05:01:17 +00:00
2018-09-23 04:53:09 +00:00
threading.Thread(target=self.detectShutdown).start()
threading.Thread(target=self.socketStarter).start()
2018-09-21 04:47:40 +00:00
app = flask.Flask(__name__)
2018-09-23 04:53:09 +00:00
self.http_server = WSGIServer(('127.0.0.1', self.bindPort), app)
self.http_server.serve_forever()
2018-09-15 04:48:48 +00:00
2018-09-23 04:53:09 +00:00
@app.route('/dc/', methods=['POST'])
def acceptConn(self):
data = request.form['data']
data = self._core._utils.bytesTorStr(data)
2018-09-24 01:47:27 +00:00
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 ""
2018-09-15 04:48:48 +00:00
2018-09-24 01:47:27 +00:00
if request.host in self.sockets:
self._core.socketServerConnData[myPeer].append(data)
2018-09-23 04:53:09 +00:00
else:
2018-09-24 01:47:27 +00:00
self._core.socketServerConnData[myPeer] = [data]
2018-09-15 16:13:03 +00:00
2018-09-24 01:47:27 +00:00
try:
retData = self._core.socketServerResponseData[myPeer]
except KeyError:
pass
else:
self._core.socketServerResponseData[myPeer] = ''
2018-09-21 04:47:40 +00:00
2018-09-23 04:53:09 +00:00
return retData
2018-09-23 04:53:09 +00:00
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 = {}
2018-09-24 01:47:27 +00:00
time.sleep(1)
2018-09-23 04:53:09 +00:00
def detectShutdown(self):
while not self._core.killSockets:
time.sleep(5)
2018-11-17 07:23:10 +00:00
logger.debug('Killing socket server...')
2018-09-23 04:53:09 +00:00
self.http_server.stop()
2018-09-22 05:01:17 +00:00
def addSocket(self, peer, reason=''):
2018-09-21 04:47:40 +00:00
bindPort = 1337
2018-09-24 01:47:27 +00:00
assert len(reason) <= 12
2018-09-20 17:41:34 +00:00
with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller:
controller.authenticate(config.get('tor.controlpassword'))
2018-09-15 16:13:03 +00:00
2018-09-21 04:47:40 +00:00
socket = controller.create_ephemeral_hidden_service({80: bindPort}, await_publication = True)
self.sockets[peer] = socket.service_id + '.onion'
2018-09-17 05:02:16 +00:00
self.responseData[socket.service_id + '.onion'] = ''
2018-09-17 05:02:16 +00:00
self._core.insertBlock(str(uuid.uuid4()), header='socket', sign=True, encryptType='asym', asymPeer=peer, meta={'reason': reason, 'address': socket.service_id + '.onion'})
2018-09-24 01:47:27 +00:00
self._core.socketReasons[peer] = reason
2018-09-17 05:02:16 +00:00
return
2018-09-21 04:47:40 +00:00
class OnionrSocketClient:
def __init__(self, coreInst):
self.sockets = {} # pubkey: tor address
self.connPool = {}
2018-09-22 05:01:17 +00:00
self.sendData = {}
2018-09-21 04:47:40 +00:00
self._core = coreInst
self.response = ''
self.request = ''
self.connected = False
2018-09-22 05:01:17 +00:00
self.killSocket = False
2018-09-23 01:21:39 +00:00
def startSocket(self, peer, reason):
2018-09-22 05:01:17 +00:00
address = ''
2018-09-24 22:04:17 +00:00
logger.info('Trying to find socket server for %s' % (peer,))
2018-09-22 05:01:17 +00:00
# Find the newest open socket for a given peer
2018-09-24 21:21:59 +00:00
for block in self._core.getBlocksByType('socket'):
block = onionrblockapi.Block(block, core=self._core)
2018-09-22 05:01:17 +00:00
if block.decrypt():
theSigner = block.signer
try:
theSigner = theSigner.decode()
except AttributeError:
pass
if block.verifySig() and theSigner == peer:
2018-09-22 05:01:17 +00:00
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:
2018-09-24 22:04:17 +00:00
break
else:
logger.error('The socket the peer opened is not for %s' % (reason,))
2018-09-22 05:01:17 +00:00
else:
logger.error('Peer transport id is invalid for socket: %s' % (address,))
2018-09-22 05:01:17 +00:00
address = ''
else:
logger.warn('Block has invalid sig or id, was for %s' % (theSigner,))
2018-09-22 05:01:17 +00:00
if address != '':
2018-09-24 21:13:40 +00:00
logger.info('%s socket client started with %s' % (reason, peer))
2018-09-22 05:01:17 +00:00
self.sockets[peer] = address
2018-09-24 01:47:27 +00:00
data = 'hey'
2018-09-22 05:01:17 +00:00
while not self.killSocket:
try:
data = self.sendData[peer]
logger.info('Sending %s to %s' % (data, peer))
2018-09-22 05:01:17 +00:00
except KeyError:
pass
else:
self.sendData[peer] = ''
postData = {'data': data}
2018-09-24 01:47:27 +00:00
self.connPool[peer] = {'date': self._core._utils.getEpoch(), 'data': self._core._utils.doPostRequest('http://' + address + '/dc/', data=postData)}
time.sleep(2)
2018-09-21 04:47:40 +00:00
def getResponse(self, peer):
2018-09-22 05:01:17 +00:00
retData = ''
try:
retData = self.connPool[peer]
except KeyError:
pass
return
2018-09-22 05:01:17 +00:00
def sendData(self, peer, data):
self.sendData[peer] = data