diff --git a/onionr/etc/onionrvalues.py b/onionr/etc/onionrvalues.py index ece721f2..c70ff0c6 100755 --- a/onionr/etc/onionrvalues.py +++ b/onionr/etc/onionrvalues.py @@ -27,6 +27,8 @@ API_VERSION = '0' # increments of 1; only change when something fundamental abou MIN_PY_VERSION = 6 DEVELOPMENT_MODE = True +MAX_BLOCK_TYPE_LENGTH = 15 + platform = platform.system() if platform == 'Windows': SCRIPT_NAME = 'run-windows.bat' diff --git a/onionr/httpapi/security/client.py b/onionr/httpapi/security/client.py index 7838d974..aa12a8f1 100644 --- a/onionr/httpapi/security/client.py +++ b/onionr/httpapi/security/client.py @@ -54,7 +54,7 @@ class ClientAPISecurity: def after_req(resp): # Security headers resp = httpheaders.set_default_onionr_http_headers(resp) - if request.endpoint == 'site': + if request.endpoint == 'siteapi.site': resp.headers['Content-Security-Policy'] = "default-src 'none'; style-src data: 'unsafe-inline'; img-src data:" else: resp.headers['Content-Security-Policy'] = "default-src 'none'; script-src 'self'; object-src 'none'; style-src 'self'; img-src 'self'; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'self'" diff --git a/onionr/onionrcommands/filecommands.py b/onionr/onionrcommands/filecommands.py index 11387b9c..953abb2e 100755 --- a/onionr/onionrcommands/filecommands.py +++ b/onionr/onionrcommands/filecommands.py @@ -42,11 +42,11 @@ def add_file(singleBlock=False, blockType='bin'): logger.info('Adding file... this might take a long time.', terminal=True) try: with open(filename, 'rb') as singleFile: - blockhash = insert.insert_block(base64.b64encode(singleFile.read()), header=blockType) + blockhash = insert(base64.b64encode(singleFile.read()), header=blockType) if len(blockhash) > 0: logger.info('File %s saved in block %s' % (filename, blockhash), terminal=True) - except: - logger.error('Failed to save file in block.', timestamp = False, terminal=True) + except Exception as e: + logger.error('Failed to save file in block ' + str(e), timestamp = False, terminal=True) else: logger.error('%s add-file ' % sys.argv[0], timestamp = False, terminal=True) diff --git a/onionr/onionrutils/blockmetadata/__init__.py b/onionr/onionrutils/blockmetadata/__init__.py new file mode 100644 index 00000000..29d3dc01 --- /dev/null +++ b/onionr/onionrutils/blockmetadata/__init__.py @@ -0,0 +1,24 @@ +''' + Onionr - Private P2P Communication + + Module to work with block metadata +''' +''' + 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 . +''' + +from . import hasblock, fromdata, process +has_block = hasblock.has_block +process_block_metadata = process.process_block_metadata +get_block_metadata_from_data = fromdata.get_block_metadata_from_data diff --git a/onionr/onionrutils/blockmetadata/fromdata.py b/onionr/onionrutils/blockmetadata/fromdata.py new file mode 100644 index 00000000..5ffcf26a --- /dev/null +++ b/onionr/onionrutils/blockmetadata/fromdata.py @@ -0,0 +1,49 @@ +''' + Onionr - Private P2P Communication + + Return a useful tuple of (metadata (header), meta, and data) by accepting raw block data +''' +''' + 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 . +''' + +import json +def get_block_metadata_from_data(block_data): + ''' + accepts block contents as string, returns a tuple of + metadata, meta (meta being internal metadata, which will be + returned as an encrypted base64 string if it is encrypted, dict if not). + ''' + meta = {} + metadata = {} + data = block_data + try: + block_data = block_data.encode() + except AttributeError: + pass + + try: + metadata = json.loads(block_data[:block_data.find(b'\n')].decode()) + except json.decoder.JSONDecodeError: + pass + else: + data = block_data[block_data.find(b'\n'):].decode() + + if not metadata['encryptType'] in ('asym', 'sym'): + try: + meta = json.loads(metadata['meta']) + except KeyError: + pass + meta = metadata['meta'] + return (metadata, meta, data) diff --git a/onionr/onionrutils/blockmetadata/hasblock.py b/onionr/onionrutils/blockmetadata/hasblock.py new file mode 100644 index 00000000..0e98dcd9 --- /dev/null +++ b/onionr/onionrutils/blockmetadata/hasblock.py @@ -0,0 +1,42 @@ +''' + Onionr - Private P2P Communication + + Returns a bool if a block is in the block metadata db 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 . +''' +import sqlite3 +from coredb import dbfiles +import onionrexceptions +from .. import stringvalidators + +def has_block(hash: str) -> bool: + ''' + Check for new block in the block meta db + ''' + conn = sqlite3.connect(dbfiles.block_meta_db) + c = conn.cursor() + if not stringvalidators.validate_hash(hash): + raise onionrexceptions.InvalidHexHash("Invalid hash") + for result in c.execute("SELECT COUNT() FROM hashes WHERE hash = ?", (hash,)): + if result[0] >= 1: + conn.commit() + conn.close() + return True + else: + conn.commit() + conn.close() + return False + return False diff --git a/onionr/onionrutils/blockmetadata.py b/onionr/onionrutils/blockmetadata/process.py similarity index 52% rename from onionr/onionrutils/blockmetadata.py rename to onionr/onionrutils/blockmetadata/process.py index 2e11eb42..ee68d690 100644 --- a/onionr/onionrutils/blockmetadata.py +++ b/onionr/onionrutils/blockmetadata/process.py @@ -1,7 +1,7 @@ ''' Onionr - Private P2P Communication - Module to fetch block metadata from raw block data and process it + Process block metadata with relevant actions ''' ''' This program is free software: you can redistribute it and/or modify @@ -17,45 +17,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import json, sqlite3 -import logger, onionrevents -from onionrusers import onionrusers + from etc import onionrvalues import onionrblockapi -from . import epoch, stringvalidators, bytesconverter -from coredb import dbfiles, blockmetadb -def get_block_metadata_from_data(blockData): - ''' - accepts block contents as string, returns a tuple of - metadata, meta (meta being internal metadata, which will be - returned as an encrypted base64 string if it is encrypted, dict if not). - ''' - meta = {} - metadata = {} - data = blockData - try: - blockData = blockData.encode() - except AttributeError: - pass +from .. import epoch, bytesconverter +from coredb import blockmetadb +import logger +import onionrevents - try: - metadata = json.loads(blockData[:blockData.find(b'\n')].decode()) - except json.decoder.JSONDecodeError: - pass - else: - data = blockData[blockData.find(b'\n'):].decode() - - if not metadata['encryptType'] in ('asym', 'sym'): - try: - meta = json.loads(metadata['meta']) - except KeyError: - pass - meta = metadata['meta'] - return (metadata, meta, data) - -def process_block_metadata(blockHash): +def process_block_metadata(blockHash: str): ''' Read metadata from a block and cache it to the block database + + blockHash -> sha3_256 hex formatted hash of Onionr block ''' curTime = epoch.get_rounded_epoch(roundS=60) myBlock = onionrblockapi.Block(blockHash) @@ -67,10 +41,13 @@ def process_block_metadata(blockHash): signer = bytesconverter.bytes_to_str(myBlock.signer) valid = myBlock.verifySig() if myBlock.getMetadata('newFSKey') is not None: - onionrusers.OnionrUser(signer).addForwardKey(myBlock.getMetadata('newFSKey')) + try: + onionrusers.OnionrUser(signer).addForwardKey(myBlock.getMetadata('newFSKey')) + except onionrexceptions.InvalidPubkey: + logger.warn('%s has invalid forward secrecy key to add: %s' % (signer, myBlock.getMetadata('newFSKey'))) try: - if len(blockType) <= 10: + if len(blockType) <= onionrvalues.MAX_BLOCK_TYPE_LENGTH: blockmetadb.update_block_info(blockHash, 'dataType', blockType) except TypeError: logger.warn("Missing block information") @@ -83,27 +60,4 @@ def process_block_metadata(blockHash): expireTime = onionrvalues.OnionrValues().default_expire + curTime finally: blockmetadb.update_block_info(blockHash, 'expire', expireTime) - if not blockType is None: - blockmetadb.update_block_info(blockHash, 'dataType', blockType) onionrevents.event('processblocks', data = {'block': myBlock, 'type': blockType, 'signer': signer, 'validSig': valid}) - else: - pass - -def has_block(hash): - ''' - Check for new block in the list - ''' - conn = sqlite3.connect(dbfiles.block_meta_db) - c = conn.cursor() - if not stringvalidators.validate_hash(hash): - raise Exception("Invalid hash") - for result in c.execute("SELECT COUNT() FROM hashes WHERE hash = ?", (hash,)): - if result[0] >= 1: - conn.commit() - conn.close() - return True - else: - conn.commit() - conn.close() - return False - return False \ No newline at end of file diff --git a/onionr/static-data/default-plugins/chat/controlapi.py b/onionr/static-data/default-plugins/chat/controlapi.py index f5a0abcf..c6b8c490 100755 --- a/onionr/static-data/default-plugins/chat/controlapi.py +++ b/onionr/static-data/default-plugins/chat/controlapi.py @@ -67,4 +67,7 @@ def get_messages(peer): else: existing = list(existing) key_store.delete('r' + peer) - return Response(json.dumps(existing)) \ No newline at end of file + return Response(json.dumps(existing)) + +#@flask_blueprint.route('/chatapi/connect/') +#def create_connection(peer) \ No newline at end of file diff --git a/onionr/static-data/default-plugins/chat/main.py b/onionr/static-data/default-plugins/chat/main.py index 963890b1..484e79e0 100755 --- a/onionr/static-data/default-plugins/chat/main.py +++ b/onionr/static-data/default-plugins/chat/main.py @@ -36,58 +36,3 @@ def exit_with_error(text=''): if text != '': logger.error(text) sys.exit(1) - -class Chat: - def __init__(self, pluginapi): - self.peer = None - self.transport = None - self.shutdown = False - self.pluginapi = pluginapi - - def _sender_loop(self): - print('Enter a message to send, with ctrl-d or -s on a new line.') - print('-c on a new line or ctrl-c stops') - message = '' - while not self.shutdown: - try: - message += input() - if message == '-s': - raise EOFError - elif message == '-c': - raise KeyboardInterrupt - else: - message += '\n' - except EOFError: - message = json.dumps({'m': message, 't': epoch.get_epoch()}) - print(basicrequests.do_post_request(self.pluginapi.onionr, 'http://%s/chat/sendto' % (self.transport,), port=self.socks, data=message)) - message = '' - except KeyboardInterrupt: - self.shutdown = True - - def create(self): - try: - peer = sys.argv[2] - if not stringvalidators.validate_pub_key(peer): - exit_with_error('Invalid public key specified') - except IndexError: - exit_with_error('You must specify a peer public key') - self.peer = peer - # Ask peer for transport address by creating block for them - peer_transport_address = bootstrapservice.bootstrap_client_service(peer) - self.transport = peer_transport_address - self.socks = config.get('tor.socksport') - - print('connected with', peer, 'on', peer_transport_address) - if basicrequests.do_get_request('http://%s/ping' % (peer_transport_address,), ignoreAPI=True, port=self.socks) == 'pong!': - print('connected', peer_transport_address) - threading.Thread(target=self._sender_loop).start() - -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 = Chat(pluginapi) - return diff --git a/onionr/static-data/default-plugins/pms/mailapi.py b/onionr/static-data/default-plugins/pms/mailapi.py index 34692a75..efa827f4 100755 --- a/onionr/static-data/default-plugins/pms/mailapi.py +++ b/onionr/static-data/default-plugins/pms/mailapi.py @@ -60,9 +60,9 @@ def list_sentbox(): deleted = kv.get('deleted_mail') if deleted is None: deleted = [] - for x in list_copy: - if x['hash'] in deleted: - sentbox_list.remove(x) + for sent in list_copy: + if sent['hash'] in deleted: + sentbox_list.remove(sent) continue - x['name'] = contactmanager.ContactManager(x['peer'], saveUser=False).get_info('name') + sent['name'] = contactmanager.ContactManager(sent['peer'], saveUser=False).get_info('name') return json.dumps(sentbox_list) diff --git a/onionr/static-data/default-plugins/searchengine/info.json b/onionr/static-data/default-plugins/searchengine/info.json new file mode 100755 index 00000000..edae5a0e --- /dev/null +++ b/onionr/static-data/default-plugins/searchengine/info.json @@ -0,0 +1,5 @@ +{ + "name" : "searchengine", + "version" : "0.0.0", + "author" : "0gitnick" +} diff --git a/onionr/static-data/default-plugins/searchengine/main.py b/onionr/static-data/default-plugins/searchengine/main.py new file mode 100755 index 00000000..7970660b --- /dev/null +++ b/onionr/static-data/default-plugins/searchengine/main.py @@ -0,0 +1,24 @@ +''' + Onionr - Private P2P Communication + + Search engine plugin for Onionr, to search for +''' +''' + 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 . +''' + + +plugin_name = 'searchengine' + + diff --git a/onionr/static-data/www/chat/index.html b/onionr/static-data/www/chat/index.html index b7d18141..f10a0456 100755 --- a/onionr/static-data/www/chat/index.html +++ b/onionr/static-data/www/chat/index.html @@ -14,6 +14,7 @@ + diff --git a/onionr/static-data/www/chat/js/message-feed.js b/onionr/static-data/www/chat/js/message-feed.js index 69ef94b7..8bdeef5a 100644 --- a/onionr/static-data/www/chat/js/message-feed.js +++ b/onionr/static-data/www/chat/js/message-feed.js @@ -17,5 +17,8 @@ along with this program. If not, see */ let MessageCache = class { - + constructor(user) { + this.user = user + this.cache = [] // array of Messages + } } \ No newline at end of file diff --git a/onionr/static-data/www/chat/js/messages.js b/onionr/static-data/www/chat/js/messages.js new file mode 100644 index 00000000..1d1d5451 --- /dev/null +++ b/onionr/static-data/www/chat/js/messages.js @@ -0,0 +1,26 @@ +/* + Onionr - Private P2P Communication + + Onionr chat message objects + + 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 +*/ + +let Message = class { + constructor(text, to, time){ + this.text = text // string + this.to = to // bool. False = not outgoing + this.time = time // epoch int + } +} \ No newline at end of file