added clandestine
This commit is contained in:
parent
15e321feee
commit
fb32201df3
@ -23,6 +23,7 @@ from stem.control import Controller
|
|||||||
from flask import Flask, Response
|
from flask import Flask, Response
|
||||||
import core
|
import core
|
||||||
from netcontroller import getOpenPort
|
from netcontroller import getOpenPort
|
||||||
|
from . import httpheaders
|
||||||
|
|
||||||
def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300):
|
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():
|
def get_ping():
|
||||||
return "pong!"
|
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'])
|
@bootstrap_app.route('/bs/<address>', methods=['POST'])
|
||||||
def get_bootstrap(address):
|
def get_bootstrap(address):
|
||||||
if core_inst._utils.validateID(address + '.onion'):
|
if core_inst._utils.validateID(address + '.onion'):
|
||||||
|
@ -24,6 +24,7 @@ from flask import Flask
|
|||||||
import core, logger
|
import core, logger
|
||||||
from netcontroller import getOpenPort
|
from netcontroller import getOpenPort
|
||||||
import api
|
import api
|
||||||
|
from . import httpheaders
|
||||||
|
|
||||||
class ConnectionServer:
|
class ConnectionServer:
|
||||||
def __init__(self, peer, address, core_inst=None):
|
def __init__(self, peer, address, core_inst=None):
|
||||||
@ -48,6 +49,12 @@ class ConnectionServer:
|
|||||||
def get_ping():
|
def get_ping():
|
||||||
return "pong!"
|
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:
|
with Controller.from_port(port=core_inst.config.get('tor.controlPort')) as controller:
|
||||||
# Connect to the Tor process for Onionr
|
# Connect to the Tor process for Onionr
|
||||||
controller.authenticate(core_inst.config.get('tor.controlpassword'))
|
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…
Reference in New Issue
Block a user