- Removed direct connections (will be a different project in the future)
- removed chat for now - removed onionrcommunicatortimers
This commit is contained in:
		
							parent
							
								
									59330149e1
								
							
						
					
					
						commit
						30a4285b92
					
				
					 25 changed files with 21 additions and 823 deletions
				
			
		|  | @ -7,7 +7,6 @@ from gevent import sleep | ||||||
| 
 | 
 | ||||||
| from httpapi import security, friendsapi, configapi, insertblock | from httpapi import security, friendsapi, configapi, insertblock | ||||||
| from httpapi import miscclientapi, onionrsitesapi, apiutils | from httpapi import miscclientapi, onionrsitesapi, apiutils | ||||||
| from httpapi import directconnections |  | ||||||
| from httpapi import themeapi | from httpapi import themeapi | ||||||
| from httpapi import fileoffsetreader | from httpapi import fileoffsetreader | ||||||
| from httpapi.sse.private import private_sse_blueprint | 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(onionrsitesapi.site_api) | ||||||
|     app.register_blueprint(apiutils.shutdown.shutdown_bp) |     app.register_blueprint(apiutils.shutdown.shutdown_bp) | ||||||
|     app.register_blueprint(miscclientapi.staticfiles.static_files_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(themeapi.theme_blueprint) | ||||||
|     app.register_blueprint(private_sse_blueprint) |     app.register_blueprint(private_sse_blueprint) | ||||||
|     app.register_blueprint(fileoffsetreader.offset_reader_api) |     app.register_blueprint(fileoffsetreader.offset_reader_api) | ||||||
|  |  | ||||||
|  | @ -12,8 +12,6 @@ import onionrpeers | ||||||
| import onionrplugins as plugins | import onionrplugins as plugins | ||||||
| from . import onlinepeers | from . import onlinepeers | ||||||
| from . import uploadqueue | from . import uploadqueue | ||||||
| from communicatorutils import servicecreator |  | ||||||
| from communicatorutils import onionrcommunicatortimers |  | ||||||
| from communicatorutils import downloadblocks | from communicatorutils import downloadblocks | ||||||
| from communicatorutils import lookupblocks | from communicatorutils import lookupblocks | ||||||
| from communicatorutils import lookupadders | from communicatorutils import lookupadders | ||||||
|  | @ -25,7 +23,6 @@ from communicatorutils import housekeeping | ||||||
| from communicatorutils import netcheck | from communicatorutils import netcheck | ||||||
| from onionrthreads import add_onionr_thread | from onionrthreads import add_onionr_thread | ||||||
| from onionrcommands.openwebinterface import get_url | from onionrcommands.openwebinterface import get_url | ||||||
| import onionrservices |  | ||||||
| from netcontroller import NetController | from netcontroller import NetController | ||||||
| from . import bootstrappeers | from . import bootstrappeers | ||||||
| from . import daemoneventhooks | from . import daemoneventhooks | ||||||
|  | @ -44,8 +41,6 @@ from . import daemoneventhooks | ||||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. |     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers |  | ||||||
| 
 |  | ||||||
| config.reload() | config.reload() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -66,9 +61,6 @@ class OnionrCommunicatorDaemon: | ||||||
|         if config.get('general.offline_mode', False): |         if config.get('general.offline_mode', False): | ||||||
|             self.kv.put('isOnline', False) |             self.kv.put('isOnline', False) | ||||||
| 
 | 
 | ||||||
|         # list of timer instances |  | ||||||
|         self.timers = [] |  | ||||||
| 
 |  | ||||||
|         # initialize core with Tor socks port being 3rd argument |         # initialize core with Tor socks port being 3rd argument | ||||||
|         self.proxyPort = shared_state.get(NetController).socksPort |         self.proxyPort = shared_state.get(NetController).socksPort | ||||||
| 
 | 
 | ||||||
|  | @ -118,24 +110,11 @@ class OnionrCommunicatorDaemon: | ||||||
|             uploadblocks.upload_blocks_from_communicator, |             uploadblocks.upload_blocks_from_communicator, | ||||||
|             [self.shared_state], 5, 1) |             [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, |         # This timer creates deniable blocks, | ||||||
|         # in an attempt to further obfuscate block insertion metadata |         # in an attempt to further obfuscate block insertion metadata | ||||||
|         if config.get('general.insert_deniable_blocks', True): |         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): |         if config.get('transports.tor', True): | ||||||
|             # Timer to check for connectivity, |             # Timer to check for connectivity, | ||||||
|  | @ -147,24 +126,14 @@ class OnionrCommunicatorDaemon: | ||||||
|         if config.get('general.security_level', 1) == 0 \ |         if config.get('general.security_level', 1) == 0 \ | ||||||
|                 and config.get('general.announce_node', True): |                 and config.get('general.announce_node', True): | ||||||
|             # Default to high security level incase config breaks |             # Default to high security level incase config breaks | ||||||
|             announceTimer = OnionrCommunicatorTimers( |             add_onionr_thread( | ||||||
|                 self, |                 announcenode.announce_node, [self.shared_state], 600, 60) | ||||||
|                 announcenode.announce_node, |  | ||||||
|                 3600, my_args=[self], requires_peer=True, max_threads=1) |  | ||||||
|             announceTimer.count = (announceTimer.frequency - 60) |  | ||||||
|         else: |         else: | ||||||
|             logger.debug('Will not announce node.') |             logger.debug('Will not announce node.') | ||||||
| 
 | 
 | ||||||
|         # Timer to delete malfunctioning or long-dead peers |         add_onionr_thread(onionrpeers.peer_cleanup, [], 300, 300) | ||||||
|         cleanupTimer = OnionrCommunicatorTimers( |  | ||||||
|             self, self.peerCleanup, 300, requires_peer=True) |  | ||||||
| 
 | 
 | ||||||
|         # Timer to cleanup dead ephemeral forward secrecy keys |         add_onionr_thread(housekeeping.clean_keys, [], 15, 1) | ||||||
|         OnionrCommunicatorTimers( |  | ||||||
|             self, housekeeping.clean_keys, 15, my_args=[self], max_threads=1) |  | ||||||
| 
 |  | ||||||
|         # Adjust initial timer triggers |  | ||||||
|         cleanupTimer.count = (cleanupTimer.frequency - 60) |  | ||||||
| 
 | 
 | ||||||
|         if config.get('general.use_bootstrap_list', True): |         if config.get('general.use_bootstrap_list', True): | ||||||
|             bootstrappeers.add_bootstrap_list_to_peer_list( |             bootstrappeers.add_bootstrap_list_to_peer_list( | ||||||
|  | @ -192,11 +161,6 @@ class OnionrCommunicatorDaemon: | ||||||
|         try: |         try: | ||||||
|             while not self.shared_state.get_by_string( |             while not self.shared_state.get_by_string( | ||||||
|                     'DeadSimpleKV').get('shutdown'): |                     '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) |                 time.sleep(self.delay) | ||||||
|         except KeyboardInterrupt: |         except KeyboardInterrupt: | ||||||
|             self.shared_state.get_by_string( |             self.shared_state.get_by_string( | ||||||
|  | @ -204,14 +168,7 @@ class OnionrCommunicatorDaemon: | ||||||
| 
 | 
 | ||||||
|         logger.info( |         logger.info( | ||||||
|             'Goodbye. (Onionr is cleaning up, and will exit)', terminal=True) |             '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: |         try: | ||||||
|             time.sleep(0.5) |             time.sleep(0.5) | ||||||
|         except KeyboardInterrupt: |         except KeyboardInterrupt: | ||||||
|  |  | ||||||
|  | @ -32,16 +32,16 @@ if TYPE_CHECKING: | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def announce_node(daemon): | def announce_node(shared_state): | ||||||
|     """Announce our node to our peers.""" |     """Announce our node to our peers.""" | ||||||
|     ret_data = False |     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 |     # Do not let announceCache get too large | ||||||
|     if len(kv.get('announceCache')) >= 10000: |     if len(kv.get('announceCache')) >= 10000: | ||||||
|         kv.get('announceCache').popitem() |         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 |         # Announce to random online peers | ||||||
|         for i in kv.get('onlinePeers'): |         for i in kv.get('onlinePeers'): | ||||||
|             if i not in kv.get('announceCache'): |             if i not in kv.get('announceCache'): | ||||||
|  | @ -67,12 +67,11 @@ def announce_node(daemon): | ||||||
|             if basicrequests.do_post_request( |             if basicrequests.do_post_request( | ||||||
|                     url, |                     url, | ||||||
|                     data, |                     data, | ||||||
|                     port=daemon.shared_state.get(NetController).socksPort)\ |                     port=shared_state.get(NetController).socksPort)\ | ||||||
|                     == 'Success': |                     == 'Success': | ||||||
|                 logger.info('Successfully introduced node to ' + peer, |                 logger.info('Successfully introduced node to ' + peer, | ||||||
|                             terminal=True) |                             terminal=True) | ||||||
|                 ret_data = True |                 ret_data = True | ||||||
|                 keydb.transportinfo.set_address_info(peer, 'introduced', 1) |                 keydb.transportinfo.set_address_info(peer, 'introduced', 1) | ||||||
| 
 | 
 | ||||||
|     daemon.decrementThreadCount('announce_node') |  | ||||||
|     return ret_data |     return ret_data | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ def clean_old_blocks(shared_state): | ||||||
|             logger.info('Deleted block: %s' % (oldest,)) |             logger.info('Deleted block: %s' % (oldest,)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def clean_keys(comm_inst): | def clean_keys(): | ||||||
|     """Delete expired forward secrecy keys""" |     """Delete expired forward secrecy keys""" | ||||||
|     conn = sqlite3.connect(dbfiles.user_id_info_db, |     conn = sqlite3.connect(dbfiles.user_id_info_db, | ||||||
|                            timeout=DATABASE_LOCK_TIMEOUT) |                            timeout=DATABASE_LOCK_TIMEOUT) | ||||||
|  | @ -88,5 +88,3 @@ def clean_keys(comm_inst): | ||||||
|     conn.close() |     conn.close() | ||||||
| 
 | 
 | ||||||
|     onionrusers.deleteExpiredKeys() |     onionrusers.deleteExpiredKeys() | ||||||
| 
 |  | ||||||
|     comm_inst.decrementThreadCount('clean_keys') |  | ||||||
|  |  | ||||||
|  | @ -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 |  | ||||||
|  | @ -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') |  | ||||||
|  | @ -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) |  | ||||||
|              |  | ||||||
|  | @ -60,9 +60,11 @@ def get_block_data(public_API, b_hash): | ||||||
|                     # Encode in case data is binary |                     # Encode in case data is binary | ||||||
|                     block = block.encode('utf-8') |                     block = block.encode('utf-8') | ||||||
|                 except AttributeError: |                 except AttributeError: | ||||||
|                     if len(block) == 0: |                     # 404 if no block data | ||||||
|  |                     if not block: | ||||||
|  |                         abort(404) | ||||||
|  |                     if not len(block): | ||||||
|                         abort(404) |                         abort(404) | ||||||
|                 #block = bytesconverter.str_to_bytes(block) |  | ||||||
|                 resp = block |                 resp = block | ||||||
|     if len(resp) == 0: |     if len(resp) == 0: | ||||||
|         abort(404) |         abort(404) | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ import hmac | ||||||
| 
 | 
 | ||||||
| from flask import Blueprint, request, abort, g | from flask import Blueprint, request, abort, g | ||||||
| 
 | 
 | ||||||
| from onionrservices import httpheaders | from httpapi import httpheaders | ||||||
| from . import pluginwhitelist | from . import pluginwhitelist | ||||||
| import config | import config | ||||||
| import logger | import logger | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| Process incoming requests to the public api server for certain attacks | Process incoming requests to the public api server for certain attacks | ||||||
| """ | """ | ||||||
| from flask import Blueprint, request, abort, g | from flask import Blueprint, request, abort, g | ||||||
| from onionrservices import httpheaders | from httpapi import httpheaders | ||||||
| from onionrutils import epoch | from onionrutils import epoch | ||||||
| from lan import getip | from lan import getip | ||||||
| """ | """ | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| Process incoming requests to the public api server for certain attacks | Process incoming requests to the public api server for certain attacks | ||||||
| """ | """ | ||||||
| from flask import Blueprint, request, abort, g | from flask import Blueprint, request, abort, g | ||||||
| from onionrservices import httpheaders | from httpapi import httpheaders | ||||||
| from onionrutils import epoch | from onionrutils import epoch | ||||||
| from utils import gettransports | from utils import gettransports | ||||||
| """ | """ | ||||||
|  |  | ||||||
|  | @ -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. |  | ||||||
|  | @ -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 |  | ||||||
|  | @ -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) |  | ||||||
|  | @ -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) |  | ||||||
|  | @ -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())) |  | ||||||
|          |  | ||||||
|  | @ -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 |  | ||||||
|  | @ -26,7 +26,7 @@ if TYPE_CHECKING: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def setup_kv(shared_vars: 'DeadSimpleKV'): | def setup_kv(shared_vars: 'DeadSimpleKV'): | ||||||
|     """Init initial pseudo-variables.""" |     """Init initial pseudo-globals.""" | ||||||
|     shared_vars.put('plaintextDisabledPeers', {}) |     shared_vars.put('plaintextDisabledPeers', {}) | ||||||
|     shared_vars.put('blockQueue', {}) |     shared_vars.put('blockQueue', {}) | ||||||
|     shared_vars.put('shutdown', False) |     shared_vars.put('shutdown', False) | ||||||
|  |  | ||||||
|  | @ -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)) |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| { |  | ||||||
|     "name" : "chat", |  | ||||||
|     "version" : "1.0", |  | ||||||
|     "author" : "onionr" |  | ||||||
| } |  | ||||||
|  | @ -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) |  | ||||||
|  | @ -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,))) |  | ||||||
|      |  | ||||||
|  | @ -46,7 +46,6 @@ | ||||||
|     }, |     }, | ||||||
|     "plugins": { |     "plugins": { | ||||||
|         "disabled": [ |         "disabled": [ | ||||||
|             "chat" |  | ||||||
|         ], |         ], | ||||||
|         "enabled": [] |         "enabled": [] | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue