From 993e5ae4c7ee00cf55a0b3f23a53d22878747641 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 13 Dec 2018 04:35:01 +0000 Subject: [PATCH 1/2] Cleanup and fixes --- onionr/core.py | 13 ++++---- onionr/onionr.py | 14 ++++----- onionr/onionrdaemontools.py | 10 +++++-- .../static-data/default-plugins/cliui/main.py | 30 ++++--------------- 4 files changed, 26 insertions(+), 41 deletions(-) diff --git a/onionr/core.py b/onionr/core.py index 0219a875..dcc95295 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -513,17 +513,18 @@ class Core: speed int, 3 success int, 4 DBHash text, 5 - failure int 6 - lastConnect 7 - trust 8 - introduced 9 + powValue 6 + failure int 7 + lastConnect 8 + trust 9 + introduced 10 ''' conn = sqlite3.connect(self.addressDB, timeout=10) c = conn.cursor() command = (address,) - infoNumbers = {'address': 0, 'type': 1, 'knownPeer': 2, 'speed': 3, 'success': 4, 'DBHash': 5, 'failure': 6, 'lastConnect': 7, 'trust': 8, 'introduced': 9} + infoNumbers = {'address': 0, 'type': 1, 'knownPeer': 2, 'speed': 3, 'success': 4, 'DBHash': 5, 'powValue': 6, 'failure': 7, 'lastConnect': 8, 'trust': 9, 'introduced': 10} info = infoNumbers[info] iterCount = 0 retVal = '' @@ -549,7 +550,7 @@ class Core: command = (data, address) - if key not in ('address', 'type', 'knownPeer', 'speed', 'success', 'DBHash', 'failure', 'lastConnect', 'lastConnectAttempt', 'trust', 'introduced'): + if key not in ('address', 'type', 'knownPeer', 'speed', 'success', 'DBHash', 'failure', 'powValue', 'lastConnect', 'lastConnectAttempt', 'trust', 'introduced'): raise Exception("Got invalid database key when setting address info") else: c.execute('UPDATE adders SET ' + key + ' = ? WHERE address=?', command) diff --git a/onionr/onionr.py b/onionr/onionr.py index e2f88225..cf515819 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -182,7 +182,6 @@ class Onionr: 'introduce': self.onionrCore.introduceNode, 'connect': self.addAddress, - 'kex': self.doKEX, 'pex': self.doPEX, 'ui' : self.openUI, @@ -227,7 +226,6 @@ class Onionr: 'get-file': 'Get a file from Onionr blocks', 'import-blocks': 'import blocks from the disk (Onionr is transport-agnostic!)', 'listconn': 'list connected peers', - 'kex': 'exchange keys with peers (done automatically)', 'pex': 'exchange addresses with peers (done automatically)', 'blacklist-block': 'deletes a block by hash and permanently removes it from your node', 'introduce': 'Introduce your node to the public Onionr network', @@ -495,11 +493,6 @@ class Onionr: return - def doKEX(self): - '''make communicator do kex''' - logger.info('Sending kex to command queue...') - self.onionrCore.daemonQueueAdd('kex') - def doPEX(self): '''make communicator do pex''' logger.info('Sending pex to command queue...') @@ -694,7 +687,10 @@ class Onionr: self.daemon() self.running = False if not self.debug and not self._developmentMode: - os.remove('.onionr-lock') + try: + os.remove('.onionr-lock') + except FileNotFoundError: + pass def daemon(self): ''' @@ -728,7 +724,7 @@ class Onionr: Onionr.setupConfig('data/', self = self) if self._developmentMode: - logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)', timestamp = False) + logger.warn('DEVELOPMENT MODE ENABLED (LESS SECURE)', timestamp = False) net = NetController(config.get('client.port', 59496), apiServerIP=apiHost) logger.debug('Tor is starting...') if not net.startTor(): diff --git a/onionr/onionrdaemontools.py b/onionr/onionrdaemontools.py index 890603dd..ebe181c6 100644 --- a/onionr/onionrdaemontools.py +++ b/onionr/onionrdaemontools.py @@ -49,9 +49,14 @@ class DaemonTools: data = {'node': ourID} combinedNodes = ourID + peer + existingRand = self.daemon._core.getAddressInfo(peer, 'powValue') + if type(existingRand) is type(None): + existingRand = '' if peer in self.announceCache: data['random'] = self.announceCache[peer] + elif len(existingRand) > 0: + data['random'] = existingRand else: proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=4) try: @@ -68,6 +73,7 @@ class DaemonTools: logger.info('Successfully introduced node to ' + peer) retData = True self.daemon._core.setAddressInfo(peer, 'introduced', 1) + self.daemon._core.setAddressInfo(peer, 'powValue', data['random']) self.daemon.decrementThreadCount('announceNode') return retData @@ -152,8 +158,8 @@ class DaemonTools: self.daemon.decrementThreadCount('cooldownPeer') def runCheck(self): - if os.path.isfile('data/.runcheck'): - os.remove('data/.runcheck') + if os.path.isfile(self.daemon._core.dataDir + '.runcheck'): + os.remove(self.daemon._core.dataDir + '.runcheck') return True return False diff --git a/onionr/static-data/default-plugins/cliui/main.py b/onionr/static-data/default-plugins/cliui/main.py index e40eb4b4..323b9419 100644 --- a/onionr/static-data/default-plugins/cliui/main.py +++ b/onionr/static-data/default-plugins/cliui/main.py @@ -34,7 +34,8 @@ class OnionrCLIUI: def subCommand(self, command): try: #subprocess.run(["./onionr.py", command]) - subprocess.Popen(['./onionr.py', command], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + #subprocess.Popen(['./onionr.py', command], stdin=subprocess.STD, stdout=subprocess.STDOUT, stderr=subprocess.STDOUT) + subprocess.call(['./onionr.py', command]) except KeyboardInterrupt: pass @@ -52,24 +53,17 @@ class OnionrCLIUI: firstRun = False while showMenu: - if firstRun: - logger.info('Please wait while Onionr starts...') - daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL) - time.sleep(30) - firstRun = False - if self.myCore._utils.localCommand('ping') == 'pong': isOnline = "Yes" else: isOnline = "No" - logger.info('''Daemon Running: ''' + isOnline + ''' + print('''Daemon Running: ''' + isOnline + ''' 1. Flow (Anonymous public chat, use at your own risk) 2. Mail (Secure email-like service) 3. File Sharing 4. User Settings -5. Start/Stop Daemon -6. Quit (Does not shutdown daemon) +5. Quit (Does not shutdown daemon) ''') try: choice = input(">").strip().lower() @@ -81,25 +75,13 @@ class OnionrCLIUI: elif choice in ("2", "mail"): self.subCommand("mail") elif choice in ("3", "file sharing", "file"): - logger.warn("Not supported yet") + print("Not supported yet") elif choice in ("4", "user settings", "settings"): try: self.setName() except (KeyboardInterrupt, EOFError) as e: pass - elif choice in ("5", "daemon"): - if isOnline == "Yes": - logger.info("Onionr daemon will shutdown...") - self.myCore.daemonQueueAdd('shutdown') - - try: - daemon.kill() - except UnboundLocalError: - pass - else: - logger.info("Starting Daemon...") - daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - elif choice in ("6", "quit"): + elif choice in ("5", "quit"): showMenu = False elif choice == "": pass From bf87ab17af4d02d30cd09c6f5e3628352f22a883 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 16 Dec 2018 05:36:47 +0000 Subject: [PATCH 2/2] Block time handling improvements --- .gitmodules | 0 onionr/communicator2.py | 1 - onionr/core.py | 1 - onionr/onionrcrypto.py | 9 +++----- onionr/onionrutils.py | 29 ++++++-------------------- onionr/static-data/default_config.json | 1 + 6 files changed, 10 insertions(+), 31 deletions(-) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/onionr/communicator2.py b/onionr/communicator2.py index 0bce1511..bddb21da 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -82,7 +82,6 @@ class OnionrCommunicatorDaemon: # daemon tools are misc daemon functions, e.g. announce to online peers # intended only for use by OnionrCommunicatorDaemon - #self.daemonTools = onionrdaemontools.DaemonTools(self) self.daemonTools = onionrdaemontools.DaemonTools(self) self._chat = onionrchat.OnionrChat(self) diff --git a/onionr/core.py b/onionr/core.py index dcc95295..59e802a5 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -679,7 +679,6 @@ class Core: ''' retData = False - # check nonce dataNonce = self._utils.bytesToStr(self._crypto.sha3Hash(data)) try: diff --git a/onionr/onionrcrypto.py b/onionr/onionrcrypto.py index 35a8050d..04c821cd 100644 --- a/onionr/onionrcrypto.py +++ b/onionr/onionrcrypto.py @@ -33,9 +33,7 @@ class OnionrCrypto: self._keyFile = self._core.dataDir + 'keys.txt' self.pubKey = None self.privKey = None - self.secrets = secrets - self.deterministicRequirement = 25 # Min deterministic password/phrase length self.HASH_ID_ROUNDS = 2000 self.keyManager = keymanager.KeyManager(self) @@ -99,7 +97,6 @@ class OnionrCrypto: def pubKeyEncrypt(self, data, pubkey, anonymous=True, encodedData=False): '''Encrypt to a public key (Curve25519, taken from base32 Ed25519 pubkey)''' retVal = '' - try: pubkey = pubkey.encode() except AttributeError: @@ -198,7 +195,7 @@ class OnionrCrypto: private_key = nacl.signing.SigningKey.generate() public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder()) return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode()) - + def generateDeterministic(self, passphrase, bypassCheck=False): '''Generate a Ed25519 public key pair from a password''' passStrength = self.deterministicRequirement @@ -212,7 +209,7 @@ class OnionrCrypto: salt = b"U81Q7llrQcdTP0Ux" # Does not need to be unique or secret, but must be 16 bytes ops = nacl.pwhash.argon2id.OPSLIMIT_SENSITIVE mem = nacl.pwhash.argon2id.MEMLIMIT_SENSITIVE - + key = kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt, opslimit=ops, memlimit=mem) key = nacl.public.PrivateKey(key, nacl.encoding.RawEncoder()) publicKey = key.public_key @@ -285,6 +282,6 @@ class OnionrCrypto: logger.debug("Invalid token, bad proof") return retData - + def safeCompare(self, one, two): return hmac.compare_digest(one, two) diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index dbcf01e6..948563e3 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -23,7 +23,6 @@ import nacl.signing, nacl.encoding from onionrblockapi import Block import onionrexceptions from onionr import API_VERSION -from defusedxml import minidom import onionrevents import pgpwords, onionrusers, storagecounter if sys.version_info < (3, 6): @@ -372,6 +371,7 @@ class OnionrUtils: pass # Validate metadata dict for invalid keys to sizes that are too large + maxAge = config.get("general.max_block_age", 2678400) if type(metadata) is dict: for i in metadata: try: @@ -392,6 +392,11 @@ class OnionrUtils: if not self.isIntegerString(metadata[i]): logger.warn('Block metadata time stamp is not integer string') break + if (metadata[i] - self.getEpoch()) > 30: + logger.warn('Block metadata time stamp is set for the future, which is not allowed.') + break + if (self.getEpoch() - metadata[i]) > maxAge: + logger.warn('Block is older than allowed: %s' % (maxAge,)) elif i == 'expire': try: assert int(metadata[i]) > self.getEpoch() @@ -653,28 +658,6 @@ class OnionrUtils: retData = False return retData - def getNistBeaconSalt(self, torPort=0, rounding=3600): - ''' - Get the token for the current hour from the NIST randomness beacon - ''' - if torPort == 0: - try: - sys.argv[2] - except IndexError: - raise onionrexceptions.MissingPort('Missing Tor socks port') - retData = '' - curTime = self.getRoundedEpoch(rounding) - self.nistSaltTimestamp = curTime - data = self.doGetRequest('https://beacon.nist.gov/rest/record/' + str(curTime), port = torPort) - dataXML = minidom.parseString(data, forbid_dtd = True, forbid_entities = True, forbid_external = True) - try: - retData = dataXML.getElementsByTagName('outputValue')[0].childNodes[0].data - except ValueError: - logger.warn('Failed to get the NIST beacon value.') - else: - self.powSalt = retData - return retData - def strToBytes(self, data): try: data = data.encode() diff --git a/onionr/static-data/default_config.json b/onionr/static-data/default_config.json index 5003d73b..5532797d 100644 --- a/onionr/static-data/default_config.json +++ b/onionr/static-data/default_config.json @@ -6,6 +6,7 @@ "minimum_send_pow": 5, "socket_servers": false, "security_level": 0, + "max_block_age": 2678400, "public_key": "" },