- Removed direct connections (will be a different project in the future)

- removed chat for now
- removed onionrcommunicatortimers
This commit is contained in:
Kevin Froman 2020-11-21 05:31:19 +00:00
parent 59330149e1
commit 30a4285b92
25 changed files with 21 additions and 823 deletions

View File

@ -7,7 +7,6 @@ from gevent import sleep
from httpapi import security, friendsapi, configapi, insertblock
from httpapi import miscclientapi, onionrsitesapi, apiutils
from httpapi import directconnections
from httpapi import themeapi
from httpapi import fileoffsetreader
from httpapi.sse.private import private_sse_blueprint
@ -42,8 +41,6 @@ def register_private_blueprints(private_api, app):
app.register_blueprint(onionrsitesapi.site_api)
app.register_blueprint(apiutils.shutdown.shutdown_bp)
app.register_blueprint(miscclientapi.staticfiles.static_files_bp)
app.register_blueprint(directconnections.DirectConnectionManagement(
private_api).direct_conn_management_bp)
app.register_blueprint(themeapi.theme_blueprint)
app.register_blueprint(private_sse_blueprint)
app.register_blueprint(fileoffsetreader.offset_reader_api)

View File

@ -12,8 +12,6 @@ import onionrpeers
import onionrplugins as plugins
from . import onlinepeers
from . import uploadqueue
from communicatorutils import servicecreator
from communicatorutils import onionrcommunicatortimers
from communicatorutils import downloadblocks
from communicatorutils import lookupblocks
from communicatorutils import lookupadders
@ -25,7 +23,6 @@ from communicatorutils import housekeeping
from communicatorutils import netcheck
from onionrthreads import add_onionr_thread
from onionrcommands.openwebinterface import get_url
import onionrservices
from netcontroller import NetController
from . import bootstrappeers
from . import daemoneventhooks
@ -44,8 +41,6 @@ from . import daemoneventhooks
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers
config.reload()
@ -66,9 +61,6 @@ class OnionrCommunicatorDaemon:
if config.get('general.offline_mode', False):
self.kv.put('isOnline', False)
# list of timer instances
self.timers = []
# initialize core with Tor socks port being 3rd argument
self.proxyPort = shared_state.get(NetController).socksPort
@ -118,24 +110,11 @@ class OnionrCommunicatorDaemon:
uploadblocks.upload_blocks_from_communicator,
[self.shared_state], 5, 1)
# Setup direct connections
if config.get('general.ephemeral_tunnels', False):
self.services = onionrservices.OnionrServices()
self.active_services = []
self.service_greenlets = []
OnionrCommunicatorTimers(
self, servicecreator.service_creator, 5,
max_threads=50, my_args=[self])
else:
self.services = None
# {peer_pubkey: ephemeral_address}, the address to reach them
self.direct_connection_clients = {}
# This timer creates deniable blocks,
# in an attempt to further obfuscate block insertion metadata
if config.get('general.insert_deniable_blocks', True):
add_onionr_thread(deniableinserts.insert_deniable_block, [], 180, 10)
add_onionr_thread(
deniableinserts.insert_deniable_block, [], 180, 10)
if config.get('transports.tor', True):
# Timer to check for connectivity,
@ -147,24 +126,14 @@ class OnionrCommunicatorDaemon:
if config.get('general.security_level', 1) == 0 \
and config.get('general.announce_node', True):
# Default to high security level incase config breaks
announceTimer = OnionrCommunicatorTimers(
self,
announcenode.announce_node,
3600, my_args=[self], requires_peer=True, max_threads=1)
announceTimer.count = (announceTimer.frequency - 60)
add_onionr_thread(
announcenode.announce_node, [self.shared_state], 600, 60)
else:
logger.debug('Will not announce node.')
# Timer to delete malfunctioning or long-dead peers
cleanupTimer = OnionrCommunicatorTimers(
self, self.peerCleanup, 300, requires_peer=True)
add_onionr_thread(onionrpeers.peer_cleanup, [], 300, 300)
# Timer to cleanup dead ephemeral forward secrecy keys
OnionrCommunicatorTimers(
self, housekeeping.clean_keys, 15, my_args=[self], max_threads=1)
# Adjust initial timer triggers
cleanupTimer.count = (cleanupTimer.frequency - 60)
add_onionr_thread(housekeeping.clean_keys, [], 15, 1)
if config.get('general.use_bootstrap_list', True):
bootstrappeers.add_bootstrap_list_to_peer_list(
@ -192,11 +161,6 @@ class OnionrCommunicatorDaemon:
try:
while not self.shared_state.get_by_string(
'DeadSimpleKV').get('shutdown'):
for i in self.timers:
if self.shared_state.get_by_string(
'DeadSimpleKV').get('shutdown'):
break
i.processTimer()
time.sleep(self.delay)
except KeyboardInterrupt:
self.shared_state.get_by_string(
@ -204,14 +168,7 @@ class OnionrCommunicatorDaemon:
logger.info(
'Goodbye. (Onionr is cleaning up, and will exit)', terminal=True)
try:
self.service_greenlets
except AttributeError:
pass
else:
# Stop onionr direct connection services
for server in self.service_greenlets:
server.stop()
try:
time.sleep(0.5)
except KeyboardInterrupt:

View File

@ -32,16 +32,16 @@ if TYPE_CHECKING:
"""
def announce_node(daemon):
def announce_node(shared_state):
"""Announce our node to our peers."""
ret_data = False
kv: "DeadSimpleKV" = daemon.shared_state.get_by_string("DeadSimpleKV")
kv: "DeadSimpleKV" = shared_state.get_by_string("DeadSimpleKV")
config = shared_state.get_by_string("OnionrCommunicatorDaemon").config
# Do not let announceCache get too large
if len(kv.get('announceCache')) >= 10000:
kv.get('announceCache').popitem()
if daemon.config.get('general.security_level', 0) == 0:
if config.get('general.security_level', 0) == 0:
# Announce to random online peers
for i in kv.get('onlinePeers'):
if i not in kv.get('announceCache'):
@ -67,12 +67,11 @@ def announce_node(daemon):
if basicrequests.do_post_request(
url,
data,
port=daemon.shared_state.get(NetController).socksPort)\
port=shared_state.get(NetController).socksPort)\
== 'Success':
logger.info('Successfully introduced node to ' + peer,
terminal=True)
ret_data = True
keydb.transportinfo.set_address_info(peer, 'introduced', 1)
daemon.decrementThreadCount('announce_node')
return ret_data

View File

@ -68,7 +68,7 @@ def clean_old_blocks(shared_state):
logger.info('Deleted block: %s' % (oldest,))
def clean_keys(comm_inst):
def clean_keys():
"""Delete expired forward secrecy keys"""
conn = sqlite3.connect(dbfiles.user_id_info_db,
timeout=DATABASE_LOCK_TIMEOUT)
@ -88,5 +88,3 @@ def clean_keys(comm_inst):
conn.close()
onionrusers.deleteExpiredKeys()
comm_inst.decrementThreadCount('clean_keys')

View File

@ -1,99 +0,0 @@
"""
Onionr - Private P2P Communication.
This file contains timer control for the communicator
"""
from __future__ import annotations # thank you python, very cool
import uuid
import threading
import onionrexceptions
import logger
from typing import TYPE_CHECKING
from typing import Callable, NewType, Iterable
if TYPE_CHECKING:
from deadsimplekv import DeadSimpleKV
from communicator import OnionrCommunicatorDaemon
"""
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/>.
"""
CallFreqSeconds = NewType('CallFreqSeconds', int)
class OnionrCommunicatorTimers:
def __init__(self, daemon_inst: OnionrCommunicatorDaemon,
timer_function: Callable, frequency: CallFreqSeconds,
make_thread: bool = True,
thread_amount: int = 1, max_threads: int = 5,
requires_peer: bool = False, my_args: Iterable = []):
self.timer_function = timer_function
self.frequency = frequency
self.thread_amount = thread_amount
self.make_thread = make_thread
self.requires_peer = requires_peer
self.daemon_inst = daemon_inst
self.max_threads = max_threads
self.args = my_args
self.kv: "DeadSimpleKV" = daemon_inst.shared_state.get_by_string(
"DeadSimpleKV")
self.daemon_inst.timers.append(self)
self.count = 0
def processTimer(self):
# mark # of instances of a thread we have (decremented at thread end)
try:
self.daemon_inst.threadCounts[self.timer_function.__name__]
except KeyError:
self.daemon_inst.threadCounts[self.timer_function.__name__] = 0
# execute timer's func, if we are not missing *required* online peer
if self.count == self.frequency and not self.kv.get('shutdown'):
try:
if self.requires_peer and \
len(self.kv.get('onlinePeers')) == 0:
raise onionrexceptions.OnlinePeerNeeded
except onionrexceptions.OnlinePeerNeeded:
return
else:
if self.make_thread:
for i in range(self.thread_amount):
"""
Log if a timer has max num of active threads
If this logs frequently it is indicative of a bug
or need for optimization
"""
if self.daemon_inst.threadCounts[
self.timer_function.__name__] >= \
self.max_threads:
logger.debug(
f'{self.timer_function.__name__} is currently using the maximum number of threads, not starting another.') # noqa
# if active number of threads for timer not reached yet
else:
self.daemon_inst.threadCounts[
self.timer_function.__name__] += 1
newThread = threading.Thread(
target=self.timer_function, args=self.args,
daemon=True,
name=self.timer_function.__name__ + ' - ' +
str(uuid.uuid4()))
newThread.start()
else:
self.timer_function()
self.count = -1 # negative 1 because its incremented at bottom
self.count += 1

View File

@ -1,47 +0,0 @@
"""
Onionr - Private P2P Communication.
Creates an onionr direct connection service by scanning all connection blocks
"""
import communicator
from onionrblocks import onionrblockapi
from onionrutils import stringvalidators, bytesconverter
from coredb import blockmetadb
from onionrservices import server_exists
"""
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/>.
"""
def service_creator(daemon):
assert isinstance(daemon, communicator.OnionrCommunicatorDaemon)
# Find socket connection blocks
# TODO cache blocks and only look at recently received ones
con_blocks = blockmetadb.get_blocks_by_type('con')
for b in con_blocks:
if b not in daemon.active_services:
bl = onionrblockapi.Block(b, decrypt=True)
bs = bytesconverter.bytes_to_str(bl.bcontent) + '.onion'
if server_exists(bl.signer):
continue
if stringvalidators.validate_pub_key(bl.signer) and \
stringvalidators.validate_transport(bs):
signer = bytesconverter.bytes_to_str(bl.signer)
daemon.active_services.append(b)
daemon.active_services.append(signer)
if not daemon.services.create_server(signer, bs, daemon):
daemon.active_services.remove(b)
daemon.active_services.remove(signer)
daemon.decrementThreadCount('service_creator')

View File

@ -1,78 +0,0 @@
"""Onionr - Private P2P Communication.
Misc client API endpoints too small to need their own file and that need access to the client api inst
"""
# For the client creation thread
import threading
# For direct connection management HTTP endpoints
from flask import Response
# To make the direct connection management blueprint in the webUI
from flask import Blueprint
# Mainly to access the shared toomanyobjs object
from flask import g
import deadsimplekv
import filepaths
import onionrservices
from onionrservices import pool
"""
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/>.
"""
def _get_communicator(g):
while True:
try:
return g.too_many.get_by_string("OnionrCommunicatorDaemon")
except KeyError:
pass
class DirectConnectionManagement:
def __init__(self, client_api):
direct_conn_management_bp = Blueprint(
'direct_conn_management', __name__)
self.direct_conn_management_bp = direct_conn_management_bp
cache = deadsimplekv.DeadSimpleKV(filepaths.cached_storage)
@direct_conn_management_bp.route('/dc-client/isconnected/<pubkey>')
def is_connected(pubkey):
communicator = _get_communicator(g)
resp = ""
if pubkey in communicator.direct_connection_clients:
resp = communicator.direct_connection_clients[pubkey]
return Response(resp)
@direct_conn_management_bp.route('/dc-client/connect/<pubkey>')
def make_new_connection(pubkey):
communicator = _get_communicator(g)
resp = "pending"
if pubkey in communicator.shared_state.get(
pool.ServicePool).bootstrap_pending:
return Response(resp)
if pubkey in communicator.direct_connection_clients:
resp = communicator.direct_connection_clients[pubkey]
else:
"""Spawn a thread that will create the client and eventually add it to the
communicator.active_services
"""
threading.Thread(
target=onionrservices.OnionrServices().create_client,
args=[pubkey, communicator], daemon=True).start()
return Response(resp)

View File

@ -60,9 +60,11 @@ def get_block_data(public_API, b_hash):
# Encode in case data is binary
block = block.encode('utf-8')
except AttributeError:
if len(block) == 0:
# 404 if no block data
if not block:
abort(404)
if not len(block):
abort(404)
#block = bytesconverter.str_to_bytes(block)
resp = block
if len(resp) == 0:
abort(404)

View File

@ -7,7 +7,7 @@ import hmac
from flask import Blueprint, request, abort, g
from onionrservices import httpheaders
from httpapi import httpheaders
from . import pluginwhitelist
import config
import logger

View File

@ -3,7 +3,7 @@
Process incoming requests to the public api server for certain attacks
"""
from flask import Blueprint, request, abort, g
from onionrservices import httpheaders
from httpapi import httpheaders
from onionrutils import epoch
from lan import getip
"""

View File

@ -3,7 +3,7 @@
Process incoming requests to the public api server for certain attacks
"""
from flask import Blueprint, request, abort, g
from onionrservices import httpheaders
from httpapi import httpheaders
from onionrutils import epoch
from utils import gettransports
"""

View File

@ -1,13 +0,0 @@
# onionrservices
onionservices is a submodule to handle direct connections to Onionr peers, using the Onionr network to broker them.
## Files
__init__.py: Contains the OnionrServices class which can create direct connection servers or clients.
bootstrapservice.py: Creates a bootstrap server for a peer and announces the connection by creating a block encrypted to the peer we want to connect to.
connectionserver.py: Creates a direct connection server for a peer
httpheaders.py: Modifies a Flask response object http response headers for security purposes.

View File

@ -1,69 +0,0 @@
"""Onionr - Private P2P Communication.
Onionr services provide the server component to direct connections
"""
import time
from . import connectionserver, bootstrapservice, serverexists
from onionrutils import stringvalidators, basicrequests
import config
"""
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/>.
"""
server_exists = serverexists.server_exists
class OnionrServices:
"""Create a client or server for connecting to peer interfaces."""
def __init__(self):
self.servers = {}
self.clients = {}
self.shutdown = False
def create_server(self, peer, address, comm_inst):
"""
Create a server for direct connections
When a client wants to connect, contact their bootstrap address and tell them our ephemeral address for our service by creating a new ConnectionServer instance
"""
if not stringvalidators.validate_transport(address):
raise ValueError('address must be valid')
# How many times to attempt contacting the bootstrap server
BOOTSTRAP_TRIES = 10
# Seconds to wait before trying bootstrap again
TRY_WAIT = 3
# HTTP is fine because .onion/i2p is encrypted/authenticated
base_url = 'http://%s/' % (address,)
socks = config.get('tor.socksport')
for x in range(BOOTSTRAP_TRIES):
if basicrequests.do_get_request(
base_url + 'ping', port=socks, ignoreAPI=True) == 'pong!':
# if bootstrap sever is online, tell them our service address
connectionserver.ConnectionServer(
peer, address, comm_inst=comm_inst)
else:
time.sleep(TRY_WAIT)
else:
return False
@staticmethod
def create_client(peer, comm_inst=None):
# Create ephemeral onion service to bootstrap connection to server
if comm_inst is not None:
try:
return comm_inst.direct_connection_clients[peer]
except KeyError:
pass
address = bootstrapservice.bootstrap_client_service(peer, comm_inst)
return address

View File

@ -1,116 +0,0 @@
'''
Onionr - Private P2P Communication
Bootstrap onion direct connections for the clients
'''
'''
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 time, threading, uuid, os
from gevent.pywsgi import WSGIServer, WSGIHandler
from stem.control import Controller
from flask import Flask, Response
from netcontroller import get_open_port
from . import httpheaders
from onionrutils import stringvalidators, epoch
import logger
import config, onionrblocks, filepaths
import onionrexceptions
import deadsimplekv as simplekv
from . import pool
def __bootstrap_timeout(server: WSGIServer, timeout: int, signal_object):
time.sleep(timeout)
signal_object.timed_out = True
server.stop()
def bootstrap_client_service(peer, comm_inst=None, bootstrap_timeout=300):
'''
Bootstrap client services
'''
if not stringvalidators.validate_pub_key(peer):
raise ValueError('Peer must be valid base32 ed25519 public key')
connection_pool = None
# here we use a lambda for the timeout thread to set to true
timed_out = lambda: None
timed_out.timed_out = False
bootstrap_port = get_open_port()
bootstrap_app = Flask(__name__)
bootstrap_app.config['MAX_CONTENT_LENGTH'] = 1 * 1024
http_server = WSGIServer(('127.0.0.1', bootstrap_port), bootstrap_app, log=None)
try:
if comm_inst is None: raise ValueError
except (AttributeError, ValueError) as e:
pass
else:
comm_inst.service_greenlets.append(http_server)
connection_pool = comm_inst.shared_state.get(pool.ServicePool)
bootstrap_address = ''
shutdown = False
bs_id = str(uuid.uuid4())
key_store = simplekv.DeadSimpleKV(filepaths.cached_storage)
@bootstrap_app.route('/ping')
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 stringvalidators.validate_transport(address + '.onion'):
# Set the bootstrap address then close the server
bootstrap_address = address + '.onion'
key_store.put(bs_id, bootstrap_address)
http_server.stop()
return Response("success")
else:
return Response("")
with Controller.from_port(port=config.get('tor.controlPort')) as controller:
if not connection_pool is None: connection_pool.bootstrap_pending.append(peer)
# Connect to the Tor process for Onionr
controller.authenticate(config.get('tor.controlpassword'))
# Create the v3 onion service
response = controller.create_ephemeral_hidden_service({80: bootstrap_port}, key_type = 'NEW', key_content = 'ED25519-V3', await_publication = True)
onionrblocks.insert(response.service_id, header='con', sign=True, encryptType='asym',
asymPeer=peer, disableForward=True, expire=(epoch.get_epoch() + bootstrap_timeout))
threading.Thread(target=__bootstrap_timeout, args=[http_server, bootstrap_timeout, timed_out], daemon=True).start()
# Run the bootstrap server
try:
http_server.serve_forever()
except TypeError:
pass
# This line reached when server is shutdown by being bootstrapped
# Add the address to the client pool
if not comm_inst is None:
connection_pool.bootstrap_pending.remove(peer)
if timed_out.timed_out:
logger.warn('Could not connect to %s due to timeout' % (peer,))
return None
comm_inst.direct_connection_clients[peer] = response.service_id
# Now that the bootstrap server has received a server, return the address
return key_store.get(bs_id)

View File

@ -1,89 +0,0 @@
'''
Onionr - Private P2P Communication
This module does the second part of the bootstrap block handshake and creates the API server
'''
'''
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 gevent.pywsgi import WSGIServer
from stem.control import Controller
from flask import Flask
import logger, httpapi
import onionrexceptions, config, filepaths
from netcontroller import get_open_port
from httpapi import apiutils
from onionrutils import stringvalidators, basicrequests, bytesconverter
from . import httpheaders
import deadsimplekv as simplekv
class ConnectionServer:
def __init__(self, peer, address, comm_inst=None):
if not stringvalidators.validate_pub_key(peer):
raise ValueError('Peer must be valid base32 ed25519 public key')
socks = config.get('tor.socksport') # Load config for Tor socks port for proxy
service_app = Flask(__name__) # Setup Flask app for server.
service_port = get_open_port()
service_ip = apiutils.setbindip.set_bind_IP()
http_server = WSGIServer(('127.0.0.1', service_port), service_app, log=None)
comm_inst.service_greenlets.append(http_server)
key_store = simplekv.DeadSimpleKV(filepaths.cached_storage)
# TODO define basic endpoints useful for direct connections like stats
httpapi.load_plugin_blueprints(service_app, blueprint='direct_blueprint')
@service_app.route('/ping')
def get_ping():
return "pong!"
@service_app.route('/close')
def shutdown_server():
comm_inst.service_greenlets.remove(http_server)
http_server.stop()
return Response('goodbye')
@service_app.after_request
def afterReq(resp):
# Security headers
resp = httpheaders.set_default_onionr_http_headers(resp)
return resp
with Controller.from_port(port=config.get('tor.controlPort')) as controller:
# Connect to the Tor process for Onionr
controller.authenticate(config.get('tor.controlpassword'))
# Create the v3 onion service for the peer to connect to
response = controller.create_ephemeral_hidden_service({80: service_port}, await_publication = True, key_type='NEW', key_content = 'ED25519-V3')
try:
for x in range(3):
attempt = basicrequests.do_post_request('http://' + address + '/bs/' + response.service_id, port=socks)
if attempt == 'success':
break
else:
raise ConnectionError
except ConnectionError:
# Re-raise
raise ConnectionError('Could not reach %s bootstrap address %s' % (peer, address))
else:
# If no connection error, create the service and save it to local global key store
peer = bytesconverter.bytes_to_str(peer)
key_store.put('dc-' + peer, response.service_id)
key_store.flush()
logger.info('hosting on %s with %s' % (response.service_id, peer))
http_server.serve_forever()
http_server.stop()
key_store.delete('dc-' + peer)

View File

@ -1,29 +0,0 @@
'''
Onionr - Private P2P Communication
Holds active onionrservices clients and servers
'''
'''
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 onionrutils import epoch
class ServicePool:
def __init__(self):
self.servers = []
self.clients = []
self.bootstrap_pending = []
def add_server(self, service):
self.servers.append((service, epoch.get_epoch()))

View File

@ -1,30 +0,0 @@
'''
Onionr - Private P2P Communication
Function to check if an onion server is created for a peer or not
'''
'''
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 deadsimplekv
import filepaths
from onionrutils import bytesconverter
def server_exists(peer: str) -> bool:
'''checks if an onion server is created for a peer or not'''
peer = bytesconverter.bytes_to_str(peer)
kv = deadsimplekv.DeadSimpleKV(filepaths.cached_storage)
kv.refresh()
return not kv.get('dc-' + peer) is None

View File

@ -26,7 +26,7 @@ if TYPE_CHECKING:
def setup_kv(shared_vars: 'DeadSimpleKV'):
"""Init initial pseudo-variables."""
"""Init initial pseudo-globals."""
shared_vars.put('plaintextDisabledPeers', {})
shared_vars.put('blockQueue', {})
shared_vars.put('shutdown', False)

View File

@ -1,75 +0,0 @@
"""Onionr - Private P2P Communication.
HTTP endpoints for controlling IMs
"""
import ujson as json
from flask import Response, request, redirect, Blueprint, send_from_directory
import deadsimplekv as simplekv
import filepaths
"""
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/>.
"""
flask_blueprint = Blueprint('chat_control', __name__)
key_store = simplekv.DeadSimpleKV(filepaths.cached_storage, refresh_seconds=5)
@flask_blueprint.route('/chatapi/ping')
def ping():
return 'pong!'
@flask_blueprint.route('/chatapi/send/<peer>', methods=['POST'])
def send_message(peer):
"""Send a message to the peer"""
data = request.get_json(force=True)
key_store.refresh()
existing = key_store.get('s' + peer)
if existing is None:
existing = []
existing.append(data)
key_store.put('s' + peer, existing)
key_store.flush()
return Response('success')
@flask_blueprint.route('/chatapi/gets/<peer>')
def get_sent(peer):
"""Get messages sent to peer"""
sent = key_store.get('s' + peer)
if sent is None:
sent = []
return Response(json.dumps(sent))
@flask_blueprint.route('/chatapi/addrec/<peer>', methods=['POST'])
def add_rec(peer):
"""Add a received message from the peer"""
data = request.get_json(force=True)
key_store.refresh()
existing = key_store.get('r' + peer)
if existing is None:
existing = []
existing.append(data)
key_store.put('r' + peer, existing)
key_store.flush()
return Response('success')
@flask_blueprint.route('/chatapi/getrec/<peer>')
def get_messages(peer):
"""Get received messages for the peer"""
key_store.refresh()
existing = key_store.get('r' + peer)
if existing is None:
existing = []
else:
existing = list(existing)
key_store.delete('r' + peer)
return Response(json.dumps(existing))

View File

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

View File

@ -1,39 +0,0 @@
'''
Onionr - Private P2P Communication
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, sys, os, threading, ujson as json
locale.setlocale(locale.LC_ALL, '')
import onionrservices, logger, config
from onionrservices import bootstrapservice
from onionrutils import stringvalidators, epoch, basicrequests
plugin_name = 'chat'
PLUGIN_VERSION = '0.0.0'
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
import controlapi, peerserver
flask_blueprint = controlapi.flask_blueprint
direct_blueprint = peerserver.direct_blueprint
security_whitelist = ['staticfiles.chat', 'staticfiles.chatIndex']
def exit_with_error(text=''):
if text != '':
logger.error(text)
sys.exit(1)

View File

@ -1,65 +0,0 @@
"""Onionr - Private P2P Communication.
HTTP endpoints for communicating with peers
"""
import sys
import os
from json import JSONDecodeError
import deadsimplekv as simplekv
import ujson as json
from flask import Response, request, redirect, Blueprint, abort, g
from utils import identifyhome
from onionrutils import localcommand
import filepaths
"""
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/>.
"""
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
direct_blueprint = Blueprint('chat', __name__)
key_store = simplekv.DeadSimpleKV(filepaths.cached_storage, refresh_seconds=5)
storage_dir = identifyhome.identify_home()
@direct_blueprint.before_request
def request_setup():
key_store.refresh()
host = request.host
host = host.strip('.b32.i2p')
host = host.strip('.onion')
g.host = host
g.peer = key_store.get('dc-' + g.host)
@direct_blueprint.route('/chat/ping')
def pingdirect():
return 'pong!'
@direct_blueprint.route('/chat/sendto', methods=['POST', 'GET'])
def sendto():
"""Endpoint peers send chat messages to"""
try:
msg = request.get_json(force=True)
except JSONDecodeError:
msg = ''
else:
msg = json.dumps(msg)
localcommand.local_command('/chat/addrec/%s' % (g.peer,), post=True, post_data=msg)
return Response('success')
@direct_blueprint.route('/chat/poll')
def poll_chat():
"""Endpoints peers get new messages from"""
return Response(localcommand.local_command('/chat/gets/%s' % (g.peer,)))

View File

@ -46,7 +46,6 @@
},
"plugins": {
"disabled": [
"chat"
],
"enabled": []
},