From eff834d9da2f0420596027a215287f1aeeb9e947 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Fri, 13 Jul 2018 00:48:19 -0500 Subject: [PATCH 01/14] updated readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 21542d07..926d3276 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,5 @@ ![Onionr logo](./docs/onionr-logo.png) -[![Build Status](https://travis-ci.org/beardog108/onionr.svg?branch=master)](https://travis-ci.org/beardog108/onionr) [![Open Source Love](https://badges.frapsoft.com/os/v3/open-source.png?v=103)](https://github.com/ellerbrock/open-source-badges/) @@ -10,10 +9,11 @@ Major work in progress. ***THIS SOFTWARE IS NOT USABLE OR SECURE YET.*** +**The main repo for this software is at https://gitlab.com/beardog/Onionr/** **Roadmap/features:** -Check the [GitHub Project](https://github.com/beardog108/onionr/projects/1) to see progress towards the alpha release. +Check the [Gitlab Project](https://gitlab.com/beardog/Onionr/milestones/1) to see progress towards the alpha release. * [X] Fully p2p/decentralized, no trackers or other single points of failure * [X] High level of anonymity From 40255538da9d34bae35c30a92097f2186aa94236 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Fri, 13 Jul 2018 16:02:41 -0500 Subject: [PATCH 02/14] reworking PM system before migration to plugin and updating blockapi to encryption format --- onionr/communicator2.py | 11 +++++++++-- onionr/core.py | 14 +++++++------- onionr/onionrblockapi.py | 7 ++++++- onionr/onionrcrypto.py | 11 ++++++++++- onionr/onionrutils.py | 19 ++++++++++++------- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/onionr/communicator2.py b/onionr/communicator2.py index 76359e42..450647ad 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -25,7 +25,6 @@ from defusedxml import minidom class OnionrCommunicatorDaemon: def __init__(self, debug, developmentMode): - logger.warn('New (unstable) communicator is being used.') # list of timer instances self.timers = [] @@ -57,6 +56,9 @@ class OnionrCommunicatorDaemon: # list of new blocks to download, added to when new block lists are fetched from peers self.blockQueue = [] + # list of blocks currently downloading, avoid s + self.currentDownloading = [] + # Clear the daemon queue for any dead messages if os.path.exists(self._core.queueDB): self._core.clearDaemonQueue() @@ -154,6 +156,10 @@ class OnionrCommunicatorDaemon: def getBlocks(self): '''download new blocks in queue''' for blockHash in self.blockQueue: + if blockHash in self.currentDownloading: + logger.debug('ALREADY DOWNLOADING ' + blockHash) + continue + self.currentDownloading.append(blockHash) logger.info("Attempting to download %s..." % blockHash) content = self.peerAction(self.pickOnlinePeer(), 'getData', data=blockHash) # block content from random peer (includes metadata) if content != False: @@ -171,7 +177,7 @@ class OnionrCommunicatorDaemon: content = content.decode() # decode here because sha3Hash needs bytes above metas = self._core._utils.getBlockMetadataFromData(content) # returns tuple(metadata, meta), meta is also in metadata metadata = metas[0] - meta = metas[1] + #meta = metas[1] if self._core._utils.validateMetadata(metadata): # check if metadata is valid if self._core._crypto.verifyPow(content): # check if POW is enough/correct logger.info('Block passed proof, saving.') @@ -191,6 +197,7 @@ class OnionrCommunicatorDaemon: pass logger.warn('Block hash validation failed for ' + blockHash + ' got ' + tempHash) self.blockQueue.remove(blockHash) # remove from block queue both if success or false + self.currentDownloading.remove(blockHash) self.decrementThreadCount('getBlocks') return diff --git a/onionr/core.py b/onionr/core.py index e1dce148..535c6b0a 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -727,15 +727,15 @@ class Core: if encryptType == 'sym': if len(symKey) < self.requirements.passwordLength: raise onionrexceptions.SecurityError('Weak encryption key') - jsonMeta = self._crypto.symmetricEncrypt(jsonMeta, key=symKey, returnEncoded=True) - data = self._crypto.symmetricEncrypt(data, key=symKey, returnEncoded=True) - signature = self._crypto.symmetricEncrypt(signature, key=symKey, returnEncoded=True) - signer = self._crypto.symmetricEncrypt(signer, key=symKey, returnEncoded=True) + jsonMeta = self._crypto.symmetricEncrypt(jsonMeta, key=symKey, returnEncoded=True).decode() + data = self._crypto.symmetricEncrypt(data, key=symKey, returnEncoded=True).decode() + signature = self._crypto.symmetricEncrypt(signature, key=symKey, returnEncoded=True).decode() + signer = self._crypto.symmetricEncrypt(signer, key=symKey, returnEncoded=True).decode() elif encryptType == 'asym': if self._utils.validatePubKey(asymPeer): - jsonMeta = self._crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True) - data = self._crypto.pubKeyEncrypt(data, asymPeer, encodedData=True) - signature = self._crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True) + jsonMeta = self._crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True).decode() + data = self._crypto.pubKeyEncrypt(data, asymPeer, encodedData=True).decode() + signature = self._crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True).decode() else: raise onionrexceptions.InvalidPubkey(asymPeer + ' is not a valid base32 encoded ed25519 key') diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index dbb358af..56be7617 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -51,6 +51,7 @@ class Block: self.parent = None self.bheader = {} self.bmetadata = {} + self.isEncrypted = False # handle arguments if self.getCore() is None: @@ -118,7 +119,11 @@ class Block: self.raw = str(blockdata) self.bheader = json.loads(self.getRaw()[:self.getRaw().index('\n')]) self.bcontent = self.getRaw()[self.getRaw().index('\n') + 1:] - self.bmetadata = json.loads(self.getHeader('meta', None)) + if self.bheader['encryptType'] in ('asym', 'sym'): + self.bmetadata = self.getHeader('meta', None) + self.isEncrypted = True + else: + self.bmetadata = json.loads(self.getHeader('meta', None)) self.parent = self.getMetadata('parent', None) self.btype = self.getMetadata('type', None) self.powHash = self.getMetadata('powHash', None) diff --git a/onionr/onionrcrypto.py b/onionr/onionrcrypto.py index 1500cea1..40dca90f 100644 --- a/onionr/onionrcrypto.py +++ b/onionr/onionrcrypto.py @@ -114,6 +114,11 @@ class OnionrCrypto: '''Encrypt to a public key (Curve25519, taken from base32 Ed25519 pubkey)''' retVal = '' + try: + pubkey = pubkey.encode() + except AttributeError: + pass + if encodedData: encoding = nacl.encoding.Base64Encoder else: @@ -127,7 +132,11 @@ class OnionrCrypto: elif anonymous: key = nacl.signing.VerifyKey(key=pubkey, encoder=nacl.encoding.Base32Encoder).to_curve25519_public_key() anonBox = nacl.public.SealedBox(key) - retVal = anonBox.encrypt(data.encode(), encoder=encoding) + try: + data = data.encode() + except AttributeError: + pass + retVal = anonBox.encrypt(data, encoder=encoding) return retVal def pubKeyDecrypt(self, data, pubkey='', anonymous=False, encodedData=False): diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 077fe302..dc1c1e49 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -59,7 +59,7 @@ class OnionrUtils: High level function to encrypt a message to a peer and insert it as a block ''' - self._core.insertBlock(message, header='pm', sign=True, encryptType='sym', symKey=pubkey) + self._core.insertBlock(message, header='pm', sign=True, encryptType='asym', asymPeer=pubkey) return @@ -117,7 +117,7 @@ class OnionrUtils: else: logger.warn("Failed to add key") else: - logger.warn('%s pow failed' % key[0]) + logger.debug('%s pow failed' % key[0]) return retVal except Exception as error: logger.error('Failed to merge keys.', error=error) @@ -204,18 +204,23 @@ class OnionrUtils: def getBlockMetadataFromData(self, blockData): ''' - accepts block contents as string and returns a tuple of metadata, meta (meta being internal metadata) + 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 = {} try: blockData = blockData.encode() except AttributeError: pass metadata = json.loads(blockData[:blockData.find(b'\n')].decode()) data = blockData[blockData.find(b'\n'):].decode() - try: - meta = json.loads(metadata['meta']) - except KeyError: - meta = {} + + if not metadata['encryptType'] in ('asym', 'sym'): + try: + meta = json.loads(metadata['meta']) + except KeyError: + pass + meta = metadata['meta'] return (metadata, meta, data) def checkPort(self, port, host=''): From f42d308b2bd5fd5b65a50a4927c14779e8741753 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Fri, 13 Jul 2018 21:43:03 -0500 Subject: [PATCH 03/14] - removed gui for now * work on new pm plugin --- onionr/onionr.py | 46 ------ onionr/onionrutils.py | 46 ------ onionr/onionrvalues.py | 2 +- .../static-data/default-plugins/gui/info.json | 5 - .../static-data/default-plugins/gui/main.py | 135 ------------------ 5 files changed, 1 insertion(+), 233 deletions(-) delete mode 100644 onionr/static-data/default-plugins/gui/info.json delete mode 100644 onionr/static-data/default-plugins/gui/main.py diff --git a/onionr/onionr.py b/onionr/onionr.py index 40c267ac..10aa54ce 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -50,7 +50,6 @@ class Onionr: Main Onionr class. This is for the CLI program, and does not handle much of the logic. In general, external programs and plugins should not use this class. ''' - try: os.chdir(sys.path[0]) except FileNotFoundError: @@ -181,15 +180,6 @@ class Onionr: 'listkeys': self.listKeys, 'list-keys': self.listKeys, - 'addmsg': self.addMessage, - 'addmessage': self.addMessage, - 'add-msg': self.addMessage, - 'add-message': self.addMessage, - 'pm': self.sendEncrypt, - - 'getpms': self.getPMs, - 'get-pms': self.getPMs, - 'addpeer': self.addPeer, 'add-peer': self.addPeer, 'add-address': self.addAddress, @@ -226,9 +216,6 @@ class Onionr: 'create-plugin': 'Creates directory structure for a plugin', 'add-peer': 'Adds a peer to database', 'list-peers': 'Displays a list of peers', - 'add-msg': 'Broadcasts a message to the Onionr network', - 'pm': 'Adds a private message to block', - 'get-pms': 'Shows private messages sent to you', 'add-file': 'Create an Onionr block from a file', 'import-blocks': 'import blocks from the disk (Onionr is transport-agnostic!)', 'listconn': 'list connected peers', @@ -341,32 +328,6 @@ class Onionr: logger.info('Sending kex to command queue...') self.onionrCore.daemonQueueAdd('kex') - def sendEncrypt(self): - ''' - Create a private message and send it - ''' - - invalidID = True - while invalidID: - try: - peer = logger.readline('Peer to send to: ') - except KeyboardInterrupt: - break - else: - if self.onionrUtils.validatePubKey(peer): - invalidID = False - else: - logger.error('Invalid peer ID') - else: - try: - message = logger.readline("Enter a message: ") - except KeyboardInterrupt: - pass - else: - logger.info("Sending message to: " + logger.colors.underline + peer) - self.onionrUtils.sendPM(peer, message) - - def listKeys(self): ''' Displays a list of keys (used to be called peers) (?) @@ -447,13 +408,6 @@ class Onionr: logger.error('Failed to insert block.', timestamp = False) return - def getPMs(self): - ''' - display PMs sent to us - ''' - - self.onionrUtils.loadPMs() - def enablePlugin(self): ''' Enables and starts the given plugin diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index dc1c1e49..6d2922a9 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -431,52 +431,6 @@ class OnionrUtils: except: return False - def loadPMs(self): - ''' - Find, decrypt, and return array of PMs (array of dictionary, {from, text}) - ''' - blocks = Block.getBlocks(type = 'pm', core = self._core) - message = '' - sender = '' - for i in blocks: - try: - blockContent = i.getContent() - - try: - message = self._core._crypto.pubKeyDecrypt(blockContent, encodedData=True, anonymous=True) - except nacl.exceptions.CryptoError as e: - pass - else: - try: - message = message.decode() - except AttributeError: - pass - - try: - message = json.loads(message) - except json.decoder.JSONDecodeError: - pass - else: - logger.debug('Decrypted %s:' % i.getHash()) - logger.info(message["msg"]) - - signer = message["id"] - sig = message["sig"] - - if self.validatePubKey(signer): - if self._core._crypto.edVerify(message["msg"], signer, sig, encodedData=True): - logger.info("Good signature by %s" % signer) - else: - logger.warn("Bad signature by %s" % signer) - else: - logger.warn('Bad sender id: %s' % signer) - - except FileNotFoundError: - pass - except Exception as error: - logger.error('Failed to open block %s.' % i, error=error) - return - def getPeerByHashId(self, hash): ''' Return the pubkey of the user if known from the hash diff --git a/onionr/onionrvalues.py b/onionr/onionrvalues.py index b8c36b05..3f806702 100644 --- a/onionr/onionrvalues.py +++ b/onionr/onionrvalues.py @@ -21,4 +21,4 @@ class OnionrValues: def __init__(self): self.passwordLength = 20 - self.blockMetadataLengths = {'meta': 1000, 'sig': 88, 'signer': 64, 'time': 10, 'powRandomToken': 1000, 'encryptType': 4} \ No newline at end of file + self.blockMetadataLengths = {'meta': 1000, 'sig': 200, 'signer': 200, 'time': 10, 'powRandomToken': 1000, 'encryptType': 4} #TODO properly refine values to minimum needed \ No newline at end of file diff --git a/onionr/static-data/default-plugins/gui/info.json b/onionr/static-data/default-plugins/gui/info.json deleted file mode 100644 index 83d4489a..00000000 --- a/onionr/static-data/default-plugins/gui/info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name" : "gui", - "version" : "1.0", - "author" : "onionr" -} diff --git a/onionr/static-data/default-plugins/gui/main.py b/onionr/static-data/default-plugins/gui/main.py deleted file mode 100644 index 07e5a76e..00000000 --- a/onionr/static-data/default-plugins/gui/main.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/python -''' - Onionr - P2P Microblogging Platform & Social network - 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 . -''' - -# Imports some useful libraries -import logger, config, core -import os, sqlite3, threading -from onionrblockapi import Block - -plugin_name = 'gui' - -def send(): - global message - block = Block() - block.setType('txt') - block.setContent(message) - logger.debug('Sent message in block %s.' % block.save(sign = True)) - - -def sendMessage(): - global sendEntry - - global message - message = sendEntry.get() - - t = threading.Thread(target = send) - t.start() - - sendEntry.delete(0, len(message)) - -def update(): - global listedBlocks, listbox, runningCheckDelayCount, runningCheckDelay, root, daemonStatus - - for i in Block.getBlocks(type = 'txt'): - if i.getContent().strip() == '' or i.getHash() in listedBlocks: - continue - listbox.insert(99999, str(i.getContent())) - listedBlocks.append(i.getHash()) - listbox.see(99999) - - runningCheckDelayCount += 1 - - if runningCheckDelayCount == runningCheckDelay: - resp = pluginapi.daemon.local_command('ping') - if resp == 'pong': - daemonStatus.config(text = "Onionr Daemon Status: Running") - else: - daemonStatus.config(text = "Onionr Daemon Status: Not Running") - runningCheckDelayCount = 0 - root.after(10000, update) - - -def reallyOpenGUI(): - import tkinter - global root, runningCheckDelay, runningCheckDelayCount, scrollbar, listedBlocks, nodeInfo, keyInfo, idText, idEntry, pubKeyEntry, listbox, daemonStatus, sendEntry - - root = tkinter.Tk() - - root.title("Onionr GUI") - - runningCheckDelay = 5 - runningCheckDelayCount = 4 - - scrollbar = tkinter.Scrollbar(root) - scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) - - listedBlocks = [] - - nodeInfo = tkinter.Frame(root) - keyInfo = tkinter.Frame(root) - - hostname = pluginapi.get_onionr().get_hostname() - logger.debug('Onionr Hostname: %s' % hostname) - idText = hostname - - idEntry = tkinter.Entry(nodeInfo) - tkinter.Label(nodeInfo, text = "Node Address: ").pack(side=tkinter.LEFT) - idEntry.pack() - idEntry.insert(0, idText.strip()) - idEntry.configure(state="readonly") - - nodeInfo.pack() - - pubKeyEntry = tkinter.Entry(keyInfo) - - tkinter.Label(keyInfo, text="Public key: ").pack(side=tkinter.LEFT) - - pubKeyEntry.pack() - pubKeyEntry.insert(0, pluginapi.get_core()._crypto.pubKey) - pubKeyEntry.configure(state="readonly") - - keyInfo.pack() - - sendEntry = tkinter.Entry(root) - sendBtn = tkinter.Button(root, text='Send Message', command=sendMessage) - sendEntry.pack(side=tkinter.TOP, pady=5) - sendBtn.pack(side=tkinter.TOP) - - listbox = tkinter.Listbox(root, yscrollcommand=tkinter.Scrollbar.set, height=15) - - listbox.pack(fill=tkinter.BOTH, pady=25) - - daemonStatus = tkinter.Label(root, text="Onionr Daemon Status: unknown") - daemonStatus.pack() - - scrollbar.config(command=tkinter.Listbox.yview) - root.after(2000, update) - root.mainloop() - -def openGUI(): - t = threading.Thread(target = reallyOpenGUI) - t.daemon = False - t.start() - -def on_init(api, data = None): - global pluginapi - pluginapi = api - - api.commands.register(['gui', 'launch-gui', 'open-gui'], openGUI) - api.commands.register_help('gui', 'Opens a graphical interface for Onionr') - - return From f432d9193e94d44f14c5c0e54e849f33e832b674 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Mon, 16 Jul 2018 02:40:58 -0500 Subject: [PATCH 04/14] + implemented some menus and message drafting in pm plugin * prevent block types from being too large in metadata processing --- onionr/onionrutils.py | 4 +- .../static-data/default-plugins/pms/info.json | 5 + .../static-data/default-plugins/pms/main.py | 130 ++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 onionr/static-data/default-plugins/pms/info.json create mode 100644 onionr/static-data/default-plugins/pms/main.py diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 6d2922a9..cb1054bf 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -256,7 +256,9 @@ class OnionrUtils: Read metadata from a block and cache it to the block database ''' myBlock = Block(blockHash, self._core) - self._core.updateBlockInfo(blockHash, 'dataType', myBlock.getType()) + blockType = myBlock.getType() + if len(blockType) <= 10: + self._core.updateBlockInfo(blockHash, 'dataType', blockType) def escapeAnsi(self, line): ''' diff --git a/onionr/static-data/default-plugins/pms/info.json b/onionr/static-data/default-plugins/pms/info.json new file mode 100644 index 00000000..454b9bd6 --- /dev/null +++ b/onionr/static-data/default-plugins/pms/info.json @@ -0,0 +1,5 @@ +{ + "name" : "pms", + "version" : "1.0", + "author" : "onionr" +} diff --git a/onionr/static-data/default-plugins/pms/main.py b/onionr/static-data/default-plugins/pms/main.py new file mode 100644 index 00000000..7a331271 --- /dev/null +++ b/onionr/static-data/default-plugins/pms/main.py @@ -0,0 +1,130 @@ +''' + Onionr - P2P Microblogging Platform & Social network + + This default plugin handles private messages in an email like fashion +''' +''' + 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 . +''' + +# Imports some useful libraries +import logger, config, threading, time, readline +from onionrblockapi import Block +import onionrexceptions + +plugin_name = 'pms' +PLUGIN_VERSION = '0.0.1' + +class MailStrings: + def __init__(self, mailInstance): + self.mailInstance = mailInstance + + self.programTag = 'OnionrMail v%s' % (PLUGIN_VERSION) + choices = ['view inbox', 'view sentbox', 'send message', 'help', 'quit'] + self.mainMenuChoices = choices + self.mainMenu = '''\n +----------------- +1. %s +2. %s +3. %s +4. %s +5. %s''' % (choices[0], choices[1], choices[2], choices[3], choices[4]) + +class OnionrMail: + def __init__(self, pluginapi): + self.myCore = pluginapi.get_core() + self.strings = MailStrings(self) + + return + + def inbox(self): + print('PM Blocks:') + for blockHash in self.myCore.getBlocksByType('pm'): + print(blockHash) + + return + + def draftMessage(self): + message = '' + newLine = '' + recip = '' + entering = True + + while entering: + try: + recip = logger.readline('Enter peer address, or q to stop:').strip() + if recip in ('-q', 'q'): + raise EOFError + if not self.myCore._utils.validatePubKey(recip): + raise onionrexceptions.InvalidPubkey('Must be a valid ed25519 base32 encoded public key') + except onionrexceptions.InvalidPubkey: + logger.warn('Invalid public key') + except (KeyboardInterrupt, EOFError): + entering = False + else: + break + else: + # if -q or ctrl-c/d, exit function here, otherwise we successfully got the public key + return + + print('Enter your message, stop by entering -q on a new line.') + while newLine != '-q': + try: + newLine = input() + except (KeyboardInterrupt, EOFError): + pass + if newLine == '-q': + continue + newLine += '\n' + message += newLine + + print('Inserting encrypted message as Onionr block....') + + self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip) + + def menu(self): + choice = '' + while True: + + print(self.strings.programTag + self.strings.mainMenu.title()) # print out main menu + + try: + choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower() + except (KeyboardInterrupt, EOFError): + choice = '5' + + if choice in (self.strings.mainMenuChoices[0], '1'): + self.inbox() + elif choice in (self.strings.mainMenuChoices[2], '3'): + self.draftMessage() + elif choice in (self.strings.mainMenuChoices[4], '5'): + logger.info('Goodbye.') + break + else: + logger.warn('Invalid choice.') + return + + +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 + mail = OnionrMail(pluginapi) + api.commands.register(['mail'], mail.menu) + api.commands.register_help('mail', 'Interact with OnionrMail') + return \ No newline at end of file From 7390945ebf114404a60c31ecfb4420fb3bc926fd Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Tue, 17 Jul 2018 02:18:17 -0500 Subject: [PATCH 05/14] work on mail plugin inbox --- onionr/core.py | 2 +- onionr/onionrblockapi.py | 12 ++++++++---- onionr/static-data/default-plugins/pms/main.py | 18 +++++++++++++----- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/onionr/core.py b/onionr/core.py index 535c6b0a..6798bb12 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -718,7 +718,7 @@ class Core: # sign before encrypt, as unauthenticated crypto should not be a problem here if sign: signature = self._crypto.edSign(jsonMeta.encode() + data, key=self._crypto.privKey, encodeResult=True) - signer = self._crypto.pubKeyHashID() + signer = self._crypto.pubKey if len(jsonMeta) > 1000: raise onionrexceptions.InvalidMetadata('meta in json encoded form must not exceed 1000 bytes') diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index 56be7617..8993cbac 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -42,8 +42,6 @@ class Block: # initialize variables self.valid = True self.raw = None - self.powHash = None - self.powToken = None self.signed = False self.signature = None self.signedData = None @@ -69,6 +67,14 @@ class Block: # logic + def decrypt(self, anonymous=True, encodedData=True): + '''Decrypt a block, loading decrypted data into their vars''' + + # decrypt data + self.getCore()._crypto.pubKeyDecrypt(self.bcontent, anonymous=anonymous, encodedData=encodedData) + + return + def update(self, data = None, file = None): ''' Loads data from a block in to the current object. @@ -126,8 +132,6 @@ class Block: self.bmetadata = json.loads(self.getHeader('meta', None)) self.parent = self.getMetadata('parent', None) self.btype = self.getMetadata('type', None) - self.powHash = self.getMetadata('powHash', None) - self.powToken = self.getMetadata('powToken', None) self.signed = ('sig' in self.getHeader() and self.getHeader('sig') != '') self.signature = self.getHeader('sig', None) self.signedData = (None if not self.isSigned() else self.getHeader('meta') + '\n' + self.getContent()) diff --git a/onionr/static-data/default-plugins/pms/main.py b/onionr/static-data/default-plugins/pms/main.py index 7a331271..5d960735 100644 --- a/onionr/static-data/default-plugins/pms/main.py +++ b/onionr/static-data/default-plugins/pms/main.py @@ -49,9 +49,15 @@ class OnionrMail: return def inbox(self): - print('PM Blocks:') + blockCount = 0 + pmBlockMap = {} + + print('Private Messages:') + for blockHash in self.myCore.getBlocksByType('pm'): - print(blockHash) + blockCount += 1 + pmBlockMap[blockCount] = blockHash + print('%s: %s' % (blockCount, blockHash)) return @@ -88,10 +94,10 @@ class OnionrMail: continue newLine += '\n' message += newLine - + print('Inserting encrypted message as Onionr block....') - self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip) + self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip, sign=True) def menu(self): choice = '' @@ -100,7 +106,7 @@ class OnionrMail: print(self.strings.programTag + self.strings.mainMenu.title()) # print out main menu try: - choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower() + choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower().strip() except (KeyboardInterrupt, EOFError): choice = '5' @@ -111,6 +117,8 @@ class OnionrMail: elif choice in (self.strings.mainMenuChoices[4], '5'): logger.info('Goodbye.') break + elif choice == '': + pass else: logger.warn('Invalid choice.') return From 40341b1dc39e7e174e23d255f0620229a7609c5b Mon Sep 17 00:00:00 2001 From: Arinerron Date: Tue, 17 Jul 2018 21:45:51 -0700 Subject: [PATCH 06/14] Misc updates --- onionr/logger.py | 30 +++++++++++-------- onionr/onionrblockapi.py | 15 ++++++---- .../static-data/default-plugins/flow/main.py | 17 +++++------ 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/onionr/logger.py b/onionr/logger.py index e2e09d03..1c299054 100644 --- a/onionr/logger.py +++ b/onionr/logger.py @@ -134,7 +134,7 @@ def raw(data, fd = sys.stdout): with open(_outputfile, "a+") as f: f.write(colors.filter(data) + '\n') -def log(prefix, data, color = '', timestamp=True, fd = sys.stdout): +def log(prefix, data, color = '', timestamp=True, fd = sys.stdout, prompt = True): ''' Logs the data prefix : The prefix to the output @@ -145,7 +145,7 @@ def log(prefix, data, color = '', timestamp=True, fd = sys.stdout): if timestamp: curTime = time.strftime("%m-%d %H:%M:%S") + ' ' - output = colors.reset + str(color) + '[' + colors.bold + str(prefix) + colors.reset + str(color) + '] ' + curTime + str(data) + colors.reset + output = colors.reset + str(color) + ('[' + colors.bold + str(prefix) + colors.reset + str(color) + '] ' if prompt is True else '') + curTime + str(data) + colors.reset if not get_settings() & USE_ANSI: output = colors.filter(output) @@ -201,31 +201,37 @@ def confirm(default = 'y', message = 'Are you sure %s? '): return default == 'y' # debug: when there is info that could be useful for debugging purposes only -def debug(data, timestamp=True): +def debug(data, error = None, timestamp = True, prompt = True): if get_level() <= LEVEL_DEBUG: - log('/', data, timestamp=timestamp) + log('/', data, timestamp=timestamp, prompt = prompt) + if not error is None: + debug('Error: ' + str(error) + parse_error()) # info: when there is something to notify the user of, such as the success of a process -def info(data, timestamp=False): +def info(data, timestamp = False, prompt = True): if get_level() <= LEVEL_INFO: - log('+', data, colors.fg.green, timestamp=timestamp) + log('+', data, colors.fg.green, timestamp = timestamp, prompt = prompt) # warn: when there is a potential for something bad to happen -def warn(data, timestamp=True): +def warn(data, error = None, timestamp = True, prompt = True): + if not error is None: + debug('Error: ' + str(error) + parse_error()) if get_level() <= LEVEL_WARN: - log('!', data, colors.fg.orange, timestamp=timestamp) + log('!', data, colors.fg.orange, timestamp = timestamp, prompt = prompt) # error: when only one function, module, or process of the program encountered a problem and must stop -def error(data, error=None, timestamp=True): +def error(data, error = None, timestamp = True, prompt = True): if get_level() <= LEVEL_ERROR: - log('-', data, colors.fg.red, timestamp=timestamp, fd = sys.stderr) + log('-', data, colors.fg.red, timestamp = timestamp, fd = sys.stderr, prompt = prompt) if not error is None: debug('Error: ' + str(error) + parse_error()) # fatal: when the something so bad has happened that the program must stop -def fatal(data, timestamp=True): +def fatal(data, error = None, timestamp=True, prompt = True): + if not error is None: + debug('Error: ' + str(error) + parse_error()) if get_level() <= LEVEL_FATAL: - log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp=timestamp, fd = sys.stderr) + log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp=timestamp, fd = sys.stderr, prompt = prompt) # returns a formatted error message def parse_error(): diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index dbb358af..177e0d36 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -55,16 +55,16 @@ class Block: # handle arguments if self.getCore() is None: self.core = onionrcore.Core() - - if not self.core._utils.validateHash(self.hash): - raise onionrexceptions.InvalidHexHash('specified block hash is not valid') # update the blocks' contents if it exists if not self.getHash() is None: - if not self.update(): + if not self.core._utils.validateHash(self.hash): + logger.debug('Block hash %s is invalid.' % self.getHash()) + raise onionrexceptions.InvalidHexHash('Block hash is invalid.') + elif not self.update(): logger.debug('Failed to open block %s.' % self.getHash()) else: - logger.debug('Did not update block') + logger.debug('Did not update block.') # logic @@ -471,6 +471,8 @@ class Block: if not signer is None: if isinstance(signer, (str,)): signer = [signer] + if isinstance(signer, (bytes,)): + signer = [signer.decode()] isSigner = False for key in signer: @@ -483,12 +485,13 @@ class Block: if relevant: relevant_blocks.append(block) + if bool(reverse): relevant_blocks.reverse() return relevant_blocks except Exception as e: - logger.debug(('Failed to get blocks: %s' % str(e)) + logger.parse_error()) + logger.debug('Failed to get blocks.', error = e) return list() diff --git a/onionr/static-data/default-plugins/flow/main.py b/onionr/static-data/default-plugins/flow/main.py index 2acce082..b2fb1dfa 100644 --- a/onionr/static-data/default-plugins/flow/main.py +++ b/onionr/static-data/default-plugins/flow/main.py @@ -47,25 +47,24 @@ class OnionrFlow: self.flowRunning = False if len(message) > 0: - self.myCore.insertBlock(message) + Block(content = message, type = 'txt', core = self.myCore).save() logger.info("Flow is exiting, goodbye") return def showOutput(self): while self.flowRunning: - for blockHash in self.myCore.getBlocksByType('txt'): - if blockHash in self.alreadyOutputed: + for block in Block.getBlocks(type = 'txt', core = self.myCore): + if block.getHash() in self.alreadyOutputed: continue if not self.flowRunning: break - logger.info('\n------------------------') - block = Block(blockHash, self.myCore) + logger.info('\n------------------------', prompt = False) content = block.getContent() # Escape new lines, remove trailing whitespace, and escape ansi sequences content = self.myCore._utils.escapeAnsi(content.replace('\n', '\\n').replace('\r', '\\r').strip()) - logger.info("\n" + block.getDate().strftime("%m/%d %H:%M") + ' - ' + '\033[0;0m' + content) - self.alreadyOutputed.append(blockHash) + logger.info(block.getDate().strftime("%m/%d %H:%M") + ' - ' + logger.colors.reset + content, prompt = False) + self.alreadyOutputed.append(block.getHash()) try: time.sleep(5) except KeyboardInterrupt: @@ -84,6 +83,6 @@ def on_init(api, data = None): global pluginapi pluginapi = api flow = OnionrFlow() - api.commands.register(['flow'], flow.start) + api.commands.register('flow', flow.start) api.commands.register_help('flow', 'Open the flow messaging interface') - return \ No newline at end of file + return From 2a4cef68f865cc25283960cc501936440f9f1656 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Wed, 18 Jul 2018 02:33:23 -0500 Subject: [PATCH 07/14] * onionrblockapi supports pubkey encryption now * can now read messages in mail plugin --- onionr/core.py | 14 +++-- onionr/onionrblockapi.py | 44 ++++++++++++++-- .../static-data/default-plugins/pms/main.py | 52 ++++++++++++++++--- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/onionr/core.py b/onionr/core.py index 6798bb12..dd9a48e0 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -627,13 +627,16 @@ class Core: return None - def getBlocksByType(self, blockType): + def getBlocksByType(self, blockType, orderDate=True): ''' Returns a list of blocks by the type ''' conn = sqlite3.connect(self.blockDB) c = conn.cursor() - execute = 'SELECT hash FROM hashes WHERE dataType=?;' + if orderDate: + execute = 'SELECT hash FROM hashes WHERE dataType=? ORDER BY dateReceived;' + else: + execute = 'SELECT hash FROM hashes WHERE dataType=?;' args = (blockType,) rows = list() for row in c.execute(execute, args): @@ -733,9 +736,10 @@ class Core: signer = self._crypto.symmetricEncrypt(signer, key=symKey, returnEncoded=True).decode() elif encryptType == 'asym': if self._utils.validatePubKey(asymPeer): - jsonMeta = self._crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True).decode() - data = self._crypto.pubKeyEncrypt(data, asymPeer, encodedData=True).decode() - signature = self._crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True).decode() + jsonMeta = self._crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True, anonymous=True).decode() + data = self._crypto.pubKeyEncrypt(data, asymPeer, encodedData=True, anonymous=True).decode() + signature = self._crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True, anonymous=True).decode() + signer = self._crypto.pubKeyEncrypt(signer, asymPeer, encodedData=True, anonymous=True).decode() else: raise onionrexceptions.InvalidPubkey(asymPeer + ' is not a valid base32 encoded ed25519 key') diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index 8993cbac..74326e9b 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -18,7 +18,7 @@ along with this program. If not, see . ''' -import core as onionrcore, logger, config, onionrexceptions +import core as onionrcore, logger, config, onionrexceptions, nacl.exceptions import json, os, sys, datetime, base64 class Block: @@ -50,6 +50,9 @@ class Block: self.bheader = {} self.bmetadata = {} self.isEncrypted = False + self.decrypted = False + self.signer = None + self.validSig = False # handle arguments if self.getCore() is None: @@ -69,11 +72,39 @@ class Block: def decrypt(self, anonymous=True, encodedData=True): '''Decrypt a block, loading decrypted data into their vars''' - + if self.decrypted: + return True + retData = False + core = self.getCore() # decrypt data - self.getCore()._crypto.pubKeyDecrypt(self.bcontent, anonymous=anonymous, encodedData=encodedData) + if self.getHeader('encryptType') == 'asym': + try: + self.bcontent = core._crypto.pubKeyDecrypt(self.bcontent, anonymous=anonymous, encodedData=encodedData) + self.bmetadata = json.loads(core._crypto.pubKeyDecrypt(self.bmetadata, anonymous=anonymous, encodedData=encodedData)) + self.signature = core._crypto.pubKeyDecrypt(self.signature, anonymous=anonymous, encodedData=encodedData) + self.signer = core._crypto.pubKeyDecrypt(self.signer, anonymous=anonymous, encodedData=encodedData) + self.signedData = json.dumps(self.bmetadata) + self.bcontent.decode() + except nacl.exceptions.CryptoError: + pass + #logger.debug('Could not decrypt block. Either invalid key or corrupted data') + else: + retData = True + self.decrypted = True + else: + logger.warn('symmetric decryption is not yet supported by this API') + return retData + + def verifySig(self): + '''Verify if a block's signature is signed by its claimed signer''' + core = self.getCore() + + if core._crypto.edVerify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True): + self.validSig = True + print('ded') + else: + self.validSig = False + return self.validSig - return def update(self, data = None, file = None): ''' @@ -133,8 +164,11 @@ class Block: self.parent = self.getMetadata('parent', None) self.btype = self.getMetadata('type', None) self.signed = ('sig' in self.getHeader() and self.getHeader('sig') != '') + # TODO: detect if signer is hash of pubkey or not + self.signer = self.getHeader('signer', None) self.signature = self.getHeader('sig', None) - self.signedData = (None if not self.isSigned() else self.getHeader('meta') + '\n' + self.getContent()) + # signed data is jsonMeta + block content (no linebreak) + self.signedData = (None if not self.isSigned() else self.getHeader('meta') + self.getContent()) self.date = self.getCore().getBlockDate(self.getHash()) if not self.getDate() is None: diff --git a/onionr/static-data/default-plugins/pms/main.py b/onionr/static-data/default-plugins/pms/main.py index 5d960735..f4a6ad5a 100644 --- a/onionr/static-data/default-plugins/pms/main.py +++ b/onionr/static-data/default-plugins/pms/main.py @@ -19,7 +19,7 @@ ''' # Imports some useful libraries -import logger, config, threading, time, readline +import logger, config, threading, time, readline, datetime from onionrblockapi import Block import onionrexceptions @@ -51,13 +51,53 @@ class OnionrMail: def inbox(self): blockCount = 0 pmBlockMap = {} + pmBlocks = {} + logger.info('Decrypting messages...') + choice = '' - print('Private Messages:') - + # this could use a lot of memory if someone has recieved a lot of messages for blockHash in self.myCore.getBlocksByType('pm'): - blockCount += 1 - pmBlockMap[blockCount] = blockHash - print('%s: %s' % (blockCount, blockHash)) + pmBlocks[blockHash] = Block(blockHash, core=self.myCore) + pmBlocks[blockHash].decrypt() + + while choice not in ('-q', 'q', 'quit'): + blockCount = 0 + for blockHash in pmBlocks: + if not pmBlocks[blockHash].decrypted: + continue + blockCount += 1 + pmBlockMap[blockCount] = blockHash + blockDate = pmBlocks[blockHash].getDate().strftime("%m/%d %H:%M") + print('%s. %s: %s' % (blockCount, blockDate, blockHash)) + + try: + choice = logger.readline('Enter a block number, -r to refresh, or -q to stop: ').strip().lower() + except (EOFError, KeyboardInterrupt): + choice = '-q' + + if choice in ('-q', 'q', 'quit'): + continue + + if choice in ('-r', 'r', 'refresh'): + # dirty hack + self.inbox() + return + + try: + choice = int(choice) + except ValueError: + pass + else: + try: + pmBlockMap[choice] + readBlock = pmBlocks[pmBlockMap[choice]] + except KeyError: + pass + else: + readBlock.verifySig() + print('Message recieved from', readBlock.signer) + print('Valid signature:', readBlock.validSig) + print(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode())) return From 3b04771eb72512b0aae8d15d2ab0591ccaa88317 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 02:08:51 -0500 Subject: [PATCH 08/14] finished inbox and signature validation for private messages --- onionr/onionrblockapi.py | 4 ++-- onionr/onionrutils.py | 10 +++++--- .../static-data/default-plugins/pms/main.py | 24 +++++++++++++++++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index e67e4cc7..e9b01b2d 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -66,7 +66,8 @@ class Block: elif not self.update(): logger.debug('Failed to open block %s.' % self.getHash()) else: - logger.debug('Did not update block.') + pass + #logger.debug('Did not update block.') # logic @@ -257,7 +258,6 @@ class Block: Outputs: - (str): the type of the block ''' - return self.btype def getRaw(self): diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index cb1054bf..5ecf14bc 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -256,9 +256,13 @@ class OnionrUtils: Read metadata from a block and cache it to the block database ''' myBlock = Block(blockHash, self._core) - blockType = myBlock.getType() - if len(blockType) <= 10: - self._core.updateBlockInfo(blockHash, 'dataType', blockType) + myBlock.decrypt() + blockType = myBlock.getMetadata('type') # we would use myBlock.getType() here, but it is bugged with encrypted blocks + try: + if len(blockType) <= 10: + self._core.updateBlockInfo(blockHash, 'dataType', blockType) + except TypeError: + pass def escapeAnsi(self, line): ''' diff --git a/onionr/static-data/default-plugins/pms/main.py b/onionr/static-data/default-plugins/pms/main.py index f4a6ad5a..3da4d268 100644 --- a/onionr/static-data/default-plugins/pms/main.py +++ b/onionr/static-data/default-plugins/pms/main.py @@ -26,6 +26,17 @@ import onionrexceptions plugin_name = 'pms' PLUGIN_VERSION = '0.0.1' +def draw_border(text): + #https://stackoverflow.com/a/20757491 + lines = text.splitlines() + width = max(len(s) for s in lines) + res = ['┌' + '─' * width + '┐'] + for s in lines: + res.append('│' + (s + ' ' * width)[:width] + '│') + res.append('└' + '─' * width + '┘') + return '\n'.join(res) + + class MailStrings: def __init__(self, mailInstance): self.mailInstance = mailInstance @@ -44,6 +55,7 @@ class MailStrings: class OnionrMail: def __init__(self, pluginapi): self.myCore = pluginapi.get_core() + #self.dataFolder = pluginapi.get_data_folder() self.strings = MailStrings(self) return @@ -97,7 +109,11 @@ class OnionrMail: readBlock.verifySig() print('Message recieved from', readBlock.signer) print('Valid signature:', readBlock.validSig) - print(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode())) + if not readBlock.validSig: + logger.warn('This message has an INVALID signature. Anyone could have sent this message.') + logger.readline('Press enter to continue to message.') + + print(draw_border(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode().strip()))) return @@ -143,7 +159,7 @@ class OnionrMail: choice = '' while True: - print(self.strings.programTag + self.strings.mainMenu.title()) # print out main menu + print(self.strings.programTag + '\n\nOur ID: ' + self.myCore._crypto.pubKey + self.strings.mainMenu.title()) # print out main menu try: choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower().strip() @@ -152,8 +168,12 @@ class OnionrMail: if choice in (self.strings.mainMenuChoices[0], '1'): self.inbox() + elif choice in (self.strings.mainMenuChoices[1], '2'): + logger.warn('not implemented yet') elif choice in (self.strings.mainMenuChoices[2], '3'): self.draftMessage() + elif choice in (self.strings.mainMenuChoices[3], '4'): + logger.warn('not implemented yet') elif choice in (self.strings.mainMenuChoices[4], '5'): logger.info('Goodbye.') break From 0f69bfd2959980d03ccb01e8953502215de6ff0c Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 14:46:13 -0500 Subject: [PATCH 09/14] fixed bytes issue with new pow and older python --- onionr/onionrproofs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/onionr/onionrproofs.py b/onionr/onionrproofs.py index b6a63d8a..04746508 100644 --- a/onionr/onionrproofs.py +++ b/onionr/onionrproofs.py @@ -159,6 +159,9 @@ class POW: self.metadata['powRandomToken'] = base64.b64encode(rand).decode() payload = json.dumps(self.metadata).encode() + b'\n' + self.data token = myCore._crypto.sha3Hash(payload) + if type(token) is bytes: + # crypto.sha3Hash returns bytes on some older python versions + self.puzzle = self.puzzle.encode() #print(token) if self.puzzle == token[0:self.difficulty]: self.hashing = False From 85fdcab53474028ff8b15e0e53ff3ccc2c97dbdf Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 15:12:48 -0500 Subject: [PATCH 10/14] fixed bytes on new pow in older python versions --- RUN-LINUX.sh | 2 ++ onionr/onionrproofs.py | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/RUN-LINUX.sh b/RUN-LINUX.sh index 8f9a4b37..9de398cd 100755 --- a/RUN-LINUX.sh +++ b/RUN-LINUX.sh @@ -1,3 +1,5 @@ #!/bin/sh cd onionr/ +cp -R static-data/default-plugins/pms/ data/plugins/ +cp -R static-data/default-plugins/flow/ data/plugins/ ./onionr.py "$@" diff --git a/onionr/onionrproofs.py b/onionr/onionrproofs.py index 04746508..194b37e9 100644 --- a/onionr/onionrproofs.py +++ b/onionr/onionrproofs.py @@ -159,10 +159,11 @@ class POW: self.metadata['powRandomToken'] = base64.b64encode(rand).decode() payload = json.dumps(self.metadata).encode() + b'\n' + self.data token = myCore._crypto.sha3Hash(payload) - if type(token) is bytes: - # crypto.sha3Hash returns bytes on some older python versions - self.puzzle = self.puzzle.encode() - #print(token) + try: + # on some versions, token is bytes + token = token.decode() + except AttributeError: + pass if self.puzzle == token[0:self.difficulty]: self.hashing = False iFound = True From 1c80849c38ea1836bfd079889ce3a718c01d3d60 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 16:31:48 -0500 Subject: [PATCH 11/14] do not attempt block decryption in metadata processing if it is not encrypted --- onionr/onionrutils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 5ecf14bc..64717a57 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -256,7 +256,8 @@ class OnionrUtils: Read metadata from a block and cache it to the block database ''' myBlock = Block(blockHash, self._core) - myBlock.decrypt() + if myBlock.isEncrypted: + myBlock.decrypt() blockType = myBlock.getMetadata('type') # we would use myBlock.getType() here, but it is bugged with encrypted blocks try: if len(blockType) <= 10: From d43daac99755dcc1eb4c67408a19f284259e7843 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 16:52:51 -0500 Subject: [PATCH 12/14] remove run-linux changes --- RUN-LINUX.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/RUN-LINUX.sh b/RUN-LINUX.sh index 9de398cd..8f9a4b37 100755 --- a/RUN-LINUX.sh +++ b/RUN-LINUX.sh @@ -1,5 +1,3 @@ #!/bin/sh cd onionr/ -cp -R static-data/default-plugins/pms/ data/plugins/ -cp -R static-data/default-plugins/flow/ data/plugins/ ./onionr.py "$@" From ee7e4289f11c834b2baf2b5df9ddfee061d37e70 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 17:32:21 -0500 Subject: [PATCH 13/14] Fixed thread exhaustion for address sync --- onionr/communicator2.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/onionr/communicator2.py b/onionr/communicator2.py index 450647ad..b4a32649 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -79,9 +79,9 @@ class OnionrCommunicatorDaemon: peerPoolTimer = OnionrCommunicatorTimers(self, self.getOnlinePeers, 60) OnionrCommunicatorTimers(self, self.lookupBlocks, 7, requiresPeer=True) OnionrCommunicatorTimers(self, self.getBlocks, 10, requiresPeer=True) - OnionrCommunicatorTimers(self, self.clearOfflinePeer, 120) - OnionrCommunicatorTimers(self, self.lookupKeys, 125, requiresPeer=True) - OnionrCommunicatorTimers(self, self.lookupAdders, 600, requiresPeer=True) + OnionrCommunicatorTimers(self, self.clearOfflinePeer, 58) + OnionrCommunicatorTimers(self, self.lookupKeys, 60, requiresPeer=True) + OnionrCommunicatorTimers(self, self.lookupAdders, 60, requiresPeer=True) # set loop to execute instantly to load up peer pool (replaced old pool init wait) peerPoolTimer.count = (peerPoolTimer.frequency - 1) @@ -124,8 +124,7 @@ class OnionrCommunicatorDaemon: peer = self.pickOnlinePeer() newAdders = self.peerAction(peer, action='pex') self._core._utils.mergeAdders(newAdders) - - self.decrementThreadCount('lookupKeys') + self.decrementThreadCount('lookupAdders') def lookupBlocks(self): '''Lookup new blocks & add them to download queue''' From 862b609687995efa556016e84045a746c9821886 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 19 Jul 2018 22:02:09 -0500 Subject: [PATCH 14/14] * reduce spam * another bytes fix for old python --- onionr/onionrblockapi.py | 9 +++++++-- onionr/onionrutils.py | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index e9b01b2d..695d41ab 100644 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -81,7 +81,13 @@ class Block: if self.getHeader('encryptType') == 'asym': try: self.bcontent = core._crypto.pubKeyDecrypt(self.bcontent, anonymous=anonymous, encodedData=encodedData) - self.bmetadata = json.loads(core._crypto.pubKeyDecrypt(self.bmetadata, anonymous=anonymous, encodedData=encodedData)) + bmeta = core._crypto.pubKeyDecrypt(self.bmetadata, anonymous=anonymous, encodedData=encodedData) + try: + bmeta = bmeta.decode() + except AttributeError: + # yet another bytes fix + pass + self.bmetadata = json.loads(bmeta) self.signature = core._crypto.pubKeyDecrypt(self.signature, anonymous=anonymous, encodedData=encodedData) self.signer = core._crypto.pubKeyDecrypt(self.signer, anonymous=anonymous, encodedData=encodedData) self.signedData = json.dumps(self.bmetadata) + self.bcontent.decode() @@ -101,7 +107,6 @@ class Block: if core._crypto.edVerify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True): self.validSig = True - print('ded') else: self.validSig = False return self.validSig diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 64717a57..33e3f51d 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -117,7 +117,8 @@ class OnionrUtils: else: logger.warn("Failed to add key") else: - logger.debug('%s pow failed' % key[0]) + pass + #logger.debug('%s pow failed' % key[0]) return retVal except Exception as error: logger.error('Failed to merge keys.', error=error) @@ -137,7 +138,8 @@ class OnionrUtils: logger.info('Added %s to db.' % adder, timestamp = True) retVal = True else: - logger.debug('%s is either our address or already in our DB' % adder) + pass + #logger.debug('%s is either our address or already in our DB' % adder) return retVal except Exception as error: logger.error('Failed to merge adders.', error = error)