From 62cad7a6ea698fa1c9c757de65d7ddc75c74f41c Mon Sep 17 00:00:00 2001 From: Arinerron Date: Sat, 3 Feb 2018 19:44:29 -0800 Subject: [PATCH] Code consistency updates - Improved formatting - Added comments - URL encoded values in netcontroller.performGET - Kept SQL statement case consistency --- onionr/api.py | 28 ++++-- onionr/colors.py | 23 ----- onionr/communicator.py | 72 +++++++++++---- onionr/core.py | 190 +++++++++++++++++++++++++--------------- onionr/netcontroller.py | 32 ++++--- onionr/onionr.py | 1 - onionr/onionrcrypto.py | 5 +- onionr/onionrutils.py | 51 ++++++++--- onionr/tests.py | 9 ++ onionr/timedHmac.py | 11 +-- 10 files changed, 275 insertions(+), 147 deletions(-) delete mode 100644 onionr/colors.py diff --git a/onionr/api.py b/onionr/api.py index b361e959..a5e75e28 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -25,10 +25,12 @@ import configparser, sys, random, threading, hmac, hashlib, base64, time, math, from core import Core import onionrutils class API: - ''' Main http api (flask)''' + ''' + Main HTTP API (Flask) + ''' def validateToken(self, token): ''' - Validate if the client token (hmac) matches the given token + Validate that the client token (hmac) matches the given token ''' if self.clientToken != token: return False @@ -36,10 +38,11 @@ class API: return True def __init__(self, config, debug): - ''' Initialize the api server, preping variables for later use - This initilization defines all of the API entry points and handlers for the endpoints and errors + ''' + Initialize the api server, preping variables for later use - This also saves the used host (random localhost IP address) to the data folder in host.txt + This initilization defines all of the API entry points and handlers for the endpoints and errors + This also saves the used host (random localhost IP address) to the data folder in host.txt ''' if os.path.exists('dev-enabled'): self._developmentMode = True @@ -72,9 +75,10 @@ class API: @app.before_request def beforeReq(): ''' - Simply define the request as not having yet failed, before every request. + Simply define the request as not having yet failed, before every request. ''' self.requestFailed = False + return @app.after_request @@ -87,6 +91,7 @@ class API: resp.headers["Content-Security-Policy"] = "default-src 'none'" resp.headers['X-Frame-Options'] = 'deny' resp.headers['X-Content-Type-Options'] = "nosniff" + return resp @app.route('/client/') @@ -112,6 +117,7 @@ class API: elapsed = endTime - startTime if elapsed < self._privateDelayTime: time.sleep(self._privateDelayTime - elapsed) + return resp @app.route('/public/') @@ -149,17 +155,21 @@ class API: def notfound(err): self.requestFailed = True resp = Response("") - #resp.headers = getHeaders(resp) + return resp + @app.errorhandler(403) def authFail(err): self.requestFailed = True resp = Response("403") + return resp + @app.errorhandler(401) def clientError(err): self.requestFailed = True resp = Response("Invalid request") + return resp logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...') @@ -168,7 +178,9 @@ class API: app.run(host=self.host, port=bindPort, debug=True, threaded=True) def validateHost(self, hostType): - ''' Validate various features of the request including: + ''' + Validate various features of the request including: + If private (/client/), is the host header local? If public (/public/), is the host header onion or i2p? diff --git a/onionr/colors.py b/onionr/colors.py deleted file mode 100644 index bb3177f4..00000000 --- a/onionr/colors.py +++ /dev/null @@ -1,23 +0,0 @@ -''' -Simply define terminal control codes (mainly colors) -''' -class Colors: - def __init__(self): - ''' - PURPLE='\033[95m' - BLUE='\033[94m' - GREEN='\033[92m' - YELLOW='\033[93m' - RED='\033[91m' - BOLD='\033[1m' - UNDERLINE='\033[4m' - RESET="\x1B[m" - ''' - self.PURPLE='\033[95m' - self.BLUE='\033[94m' - self.GREEN='\033[92m' - self.YELLOW='\033[93m' - self.RED='\033[91m' - self.BOLD='\033[1m' - self.UNDERLINE='\033[4m' - self.RESET="\x1B[m" diff --git a/onionr/communicator.py b/onionr/communicator.py index 413cdfd3..9fd31550 100755 --- a/onionr/communicator.py +++ b/onionr/communicator.py @@ -19,13 +19,15 @@ and code to operate as a daemon, getting commands from the command queue databas You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import sqlite3, requests, hmac, hashlib, time, sys, os, logger +import sqlite3, requests, hmac, hashlib, time, sys, os, logger, urllib.parse import core, onionrutils + class OnionrCommunicate: def __init__(self, debug, developmentMode): - ''' OnionrCommunicate + ''' + OnionrCommunicate - This class handles communication with nodes in the Onionr network. + This class handles communication with nodes in the Onionr network. ''' self._core = core.Core() self._utils = onionrutils.OnionrUtils(self._core) @@ -63,29 +65,46 @@ class OnionrCommunicate: logger.warn('Daemon recieved exit command.') break time.sleep(1) - return - def getRemotePeerKey(self, peerID): - '''This function contacts a peer and gets their main PGP key. - This is safe because Tor or I2P is used, but it does not ensure that the person is who they say they are + return + + def getRemotePeerKey(self, peerID): + ''' + This function contacts a peer and gets their main PGP key. + + This is safe because Tor or I2P is used, but it does not ensure that the person is who they say they are ''' url = 'http://' + peerID + '/public/?action=getPGP' r = requests.get(url, headers=headers) response = r.text + return response + def shareHMAC(self, peerID, key): - '''This function shares an HMAC key to a peer ''' + This function shares an HMAC key to a peer + ''' + return + def getPeerProof(self, peerID): - '''This function gets the current peer proof requirement''' + ''' + This function gets the current peer proof requirement + ''' + return + def sendPeerProof(self, peerID, data): - '''This function sends the proof result to a peer previously fetched with getPeerProof''' + ''' + This function sends the proof result to a peer previously fetched with getPeerProof + ''' + return def lookupBlocks(self): - '''Lookup blocks and merge new ones''' + ''' + Lookup blocks and merge new ones + ''' peerList = self._core.listPeers() blocks = '' for i in peerList: @@ -120,20 +139,26 @@ class OnionrCommunicate: else: logger.debug('Adding ' + i + ' to hash database...') self._core.addToBlockDB(i) + return + def processBlocks(self): ''' - Work with the block database and download any missing blocks - This is meant to be called from the communicator daemon on its timer. + Work with the block database and download any missing blocks + + This is meant to be called from the communicator daemon on its timer. ''' for i in self._core.getBlockList(True).split("\n"): if i != "": logger.warn('UNSAVED BLOCK: ' + i) data = self.downloadBlock(i) + return - + def downloadBlock(self, hash): - '''download a block from random order of peers''' + ''' + Download a block from random order of peers + ''' peerList = self._core.listPeers() blocks = '' for i in peerList: @@ -155,22 +180,33 @@ class OnionrCommunicate: else: logger.warn("Failed to validate " + hash) + return + + def urlencode(self, data): + ''' + URL encodes the data + ''' + return urllib.parse.quote_plus(data) + def performGet(self, action, peer, data=None, type='tor'): - '''Performs a request to a peer through Tor or i2p (currently only tor)''' + ''' + Performs a request to a peer through Tor or i2p (currently only Tor) + ''' if not peer.endswith('.onion') and not peer.endswith('.onion/'): raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion') socksPort = sys.argv[2] '''We use socks5h to use tor as DNS''' proxies = {'http': 'socks5h://127.0.0.1:' + str(socksPort), 'https': 'socks5h://127.0.0.1:' + str(socksPort)} headers = {'user-agent': 'PyOnionr'} - url = 'http://' + peer + '/public/?action=' + action + url = 'http://' + peer + '/public/?action=' + urlencode(action) if data != None: - url = url + '&data=' + data + url = url + '&data=' + urlencode(data) try: r = requests.get(url, headers=headers, proxies=proxies, timeout=(15, 30)) except requests.exceptions.RequestException as e: logger.warn(action + " failed with peer " + peer + ": " + str(e)) return False + return r.text diff --git a/onionr/core.py b/onionr/core.py index 5cfa2015..d7ac589c 100644 --- a/onionr/core.py +++ b/onionr/core.py @@ -34,7 +34,7 @@ if sys.version_info < (3, 6): class Core: def __init__(self): ''' - Initialize Core Onionr library + Initialize Core Onionr library ''' self.queueDB = 'data/queue.db' self.peerDB = 'data/peers.db' @@ -54,87 +54,101 @@ class Core: return def generateMainPGP(self, myID): - ''' Generate the main PGP key for our client. Should not be done often. - Uses own PGP home folder in the data/ directory. ''' - # Generate main pgp key + ''' + Generate the main PGP key for our client. Should not be done often. + + Uses own PGP home folder in the data/ directory + ''' gpg = gnupg.GPG(homedir='./data/pgp/') input_data = gpg.gen_key_input(key_type="RSA", key_length=1024, name_real=myID, name_email='anon@onionr', testing=True) - #input_data = gpg.gen_key_input(key_type="RSA", key_length=1024) key = gpg.gen_key(input_data) logger.info("Generating PGP key, this will take some time..") while key.status != "key created": time.sleep(0.5) print(key.status) + logger.info("Finished generating PGP key") # Write the key myFingerpintFile = open('data/own-fingerprint.txt', 'w') myFingerpintFile.write(key.fingerprint) myFingerpintFile.close() + return def addPeer(self, peerID, name=''): - ''' Add a peer by their ID, with an optional name, to the peer database.''' - ''' DOES NO SAFETY CHECKS if the ID is valid, but prepares the insertion. ''' + ''' + Add a peer by their ID, with an optional name, to the peer database + + DOES NO SAFETY CHECKS if the ID is valid, but prepares the insertion + ''' # This function simply adds a peer to the DB if not self._utils.validateID(peerID): return False conn = sqlite3.connect(self.peerDB) c = conn.cursor() t = (peerID, name, 'unknown') - c.execute('insert into peers (id, name, dateSeen) values(?, ?, ?);', t) + c.execute('INSERT INTO peers (id, name, dateSeen) VALUES(?, ?, ?);', t) conn.commit() conn.close() return True def createPeerDB(self): ''' - Generate the peer sqlite3 database and populate it with the peers table. + Generate the peer sqlite3 database and populate it with the peers table. ''' # generate the peer database conn = sqlite3.connect(self.peerDB) c = conn.cursor() - c.execute(''' - create table peers( - ID text not null, - name text, - pgpKey text, - hmacKey text, - blockDBHash text, - forwardKey text, - dateSeen not null, - bytesStored int, - trust int); + c.execute('''CREATE TABLE peers( + ID text not null, + name text, + pgpKey text, + hmacKey text, + blockDBHash text, + forwardKey text, + dateSeen not null, + bytesStored int, + trust int); ''') conn.commit() conn.close() + + return + def createBlockDB(self): ''' - Create a database for blocks + Create a database for blocks - hash - the hash of a block - dateReceived - the date the block was recieved, not necessarily when it was created - decrypted - if we can successfully decrypt the block (does not describe its current state) - dataType - data type of the block - dataFound - if the data has been found for the block - dataSaved - if the data has been saved for the block + hash - the hash of a block + dateReceived - the date the block was recieved, not necessarily when it was created + decrypted - if we can successfully decrypt the block (does not describe its current state) + dataType - data type of the block + dataFound - if the data has been found for the block + dataSaved - if the data has been saved for the block ''' if os.path.exists(self.blockDB): raise Exception("Block database already exists") conn = sqlite3.connect(self.blockDB) c = conn.cursor() - c.execute('''create table hashes( + c.execute('''CREATE TABLE hashes( hash text not null, dateReceived int, decrypted int, dataType text, dataFound int, - dataSaved int - ); + dataSaved int); ''') conn.commit() conn.close() + + return + def addToBlockDB(self, newHash, selfInsert=False): - '''add a hash value to the block db (should be in hex format)''' + ''' + Add a hash value to the block db + + Should be in hex format! + ''' if not os.path.exists(self.blockDB): raise Exception('Block db does not exist') if self._utils.hasBlock(newHash): @@ -147,22 +161,29 @@ class Core: else: selfInsert = 0 data = (newHash, currentTime, 0, '', 0, selfInsert) - c.execute('INSERT into hashes values(?, ?, ?, ?, ?, ?);', data) + c.execute('INSERT INTO hashes VALUES(?, ?, ?, ?, ?, ?);', data) conn.commit() conn.close() + return + def getData(self,hash): - '''simply return the data associated to a hash''' + ''' + Simply return the data associated to a hash + ''' try: dataFile = open(self.blockDataLocation + hash + '.dat') data = dataFile.read() dataFile.close() except FileNotFoundError: data = False + return data def setData(self, data): - '''set the data assciated with a hash''' + ''' + Set the data assciated with a hash + ''' data = data.encode() hasher = hashlib.sha3_256() hasher.update(data) @@ -171,7 +192,7 @@ class Core: dataHash = dataHash.decode() blockFileName = self.blockDataLocation + dataHash + '.dat' if os.path.exists(blockFileName): - pass # to do, properly check if block is already saved elsewhere + pass # TODO: properly check if block is already saved elsewhere #raise Exception("Data is already set for " + dataHash) else: blockFile = open(blockFileName, 'w') @@ -180,7 +201,7 @@ class Core: conn = sqlite3.connect(self.blockDB) c = conn.cursor() - c.execute("UPDATE hashes set dataSaved=1 where hash = '" + dataHash + "';") + c.execute("UPDATE hashes SET dataSaved=1 WHERE hash = '" + dataHash + "';") conn.commit() conn.close() @@ -188,9 +209,8 @@ class Core: def dataDirEncrypt(self, password): ''' - Encrypt the data directory on Onionr shutdown + Encrypt the data directory on Onionr shutdown ''' - # Encrypt data directory (don't delete it in this function) if os.path.exists('data.tar'): os.remove('data.tar') tar = tarfile.open("data.tar", "w") @@ -201,12 +221,13 @@ class Core: encrypted = simplecrypt.encrypt(password, tarData) open('data-encrypted.dat', 'wb').write(encrypted) os.remove('data.tar') + return + def dataDirDecrypt(self, password): ''' - Decrypt the data directory on startup + Decrypt the data directory on startup ''' - # Decrypt data directory if not os.path.exists('data-encrypted.dat'): return (False, 'encrypted archive does not exist') data = open('data-encrypted.dat', 'rb').read() @@ -219,13 +240,15 @@ class Core: tar = tarfile.open('data.tar') tar.extractall() tar.close() + return (True, '') + def daemonQueue(self): ''' - Gives commands to the communication proccess/daemon by reading an sqlite3 database + Gives commands to the communication proccess/daemon by reading an sqlite3 database + + This function intended to be used by the client. Queue to exchange data between "client" and server. ''' - # This function intended to be used by the client - # Queue to exchange data between "client" and server. retData = False if not os.path.exists(self.queueDB): conn = sqlite3.connect(self.queueDB) @@ -241,7 +264,7 @@ class Core: retData = row break if retData != False: - c.execute('delete from commands where id = ?', (retData[3],)) + c.execute('DELETE FROM commands WHERE id=?;', (retData[3],)) conn.commit() conn.close() @@ -249,19 +272,23 @@ class Core: def daemonQueueAdd(self, command, data=''): ''' - Add a command to the daemon queue, used by the communication daemon (communicator.py) + Add a command to the daemon queue, used by the communication daemon (communicator.py) ''' # Intended to be used by the web server date = math.floor(time.time()) conn = sqlite3.connect(self.queueDB) c = conn.cursor() t = (command, data, date) - c.execute('INSERT into commands (command, data, date) values (?, ?, ?)', t) + c.execute('INSERT INTO commands (command, data, date) VALUES(?, ?, ?)', t) conn.commit() conn.close() + return + def clearDaemonQueue(self): - '''clear the daemon queue (somewhat dangerousous)''' + ''' + Clear the daemon queue (somewhat dangerous) + ''' conn = sqlite3.connect(self.queueDB) c = conn.cursor() try: @@ -271,45 +298,49 @@ class Core: pass conn.close() - def generateHMAC(self): + return + + def generateHMAC(self, length=32): ''' - generate and return an HMAC key + Generate and return an HMAC key ''' - key = base64.b64encode(os.urandom(32)) + key = base64.b64encode(os.urandom(length)) + return key def listPeers(self, randomOrder=True): - '''Return a list of peers + ''' + Return a list of peers - randomOrder determines if the list should be in a random order + randomOrder determines if the list should be in a random order ''' conn = sqlite3.connect(self.peerDB) c = conn.cursor() if randomOrder: - peers = c.execute('SELECT * FROM peers order by RANDOM();') + peers = c.execute('SELECT * FROM peers ORDER BY RANDOM();') else: peers = c.execute('SELECT * FROM peers;') peerList = [] for i in peers: peerList.append(i[0]) conn.close() + return peerList def getPeerInfo(self, peer, info): ''' - get info about a peer + Get info about a peer from their database entry - id text 0 - name text, 1 - pgpKey text, 2 - hmacKey text, 3 - blockDBHash text, 4 - forwardKey text, 5 - dateSeen not null, 7 - bytesStored int, 8 - trust int 9 + id text 0 + name text, 1 + pgpKey text, 2 + hmacKey text, 3 + blockDBHash text, 4 + forwardKey text, 5 + dateSeen not null, 7 + bytesStored int, 8 + trust int 9 ''' - # Lookup something about a peer from their database entry conn = sqlite3.connect(self.peerDB) c = conn.cursor() command = (peer,) @@ -325,21 +356,29 @@ class Core: else: iterCount += 1 conn.close() + return retVal + def setPeerInfo(self, peer, key, data): - '''update a peer for a key''' + ''' + Update a peer for a key + ''' conn = sqlite3.connect(self.peerDB) c = conn.cursor() command = (data, peer) # TODO: validate key on whitelist if key not in ('id', 'text', 'name', 'pgpKey', 'hmacKey', 'blockDBHash', 'forwardKey', 'dateSeen', 'bytesStored', 'trust'): raise Exception("Got invalid database key when setting peer info") - c.execute('UPDATE peers SET ' + key + ' = ? where id=?', command) + c.execute('UPDATE peers SET ' + key + ' = ? WHERE id=?', command) conn.commit() conn.close() + return + def getBlockList(self, unsaved=False): - '''get list of our blocks''' + ''' + Get list of our blocks + ''' conn = sqlite3.connect(self.blockDB) c = conn.cursor() retData = '' @@ -350,24 +389,33 @@ class Core: for row in c.execute(execute): for i in row: retData += i + "\n" + return retData def getBlocksByType(self, blockType): + ''' + Returns a list of blocks by the type + ''' conn = sqlite3.connect(self.blockDB) c = conn.cursor() retData = '' - execute = 'SELECT hash FROM hashes where dataType=?' + execute = 'SELECT hash FROM hashes WHERE dataType=?;' args = (blockType,) for row in c.execute(execute, args): for i in row: retData += i + "\n" + return retData.split('\n') def setBlockType(self, hash, blockType): + ''' + Sets the type of block + ''' + conn = sqlite3.connect(self.blockDB) c = conn.cursor() - #if blockType not in ("txt"): - # return c.execute("UPDATE hashes SET dataType='" + blockType + "' WHERE hash = '" + hash + "';") conn.commit() - conn.close() \ No newline at end of file + conn.close() + + return diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py index a53d93cc..dcb3c3a5 100644 --- a/onionr/netcontroller.py +++ b/onionr/netcontroller.py @@ -19,8 +19,8 @@ ''' import subprocess, os, random, sys, logger, time, signal class NetController: - '''NetController - This class handles hidden service setup on Tor and I2P + ''' + This class handles hidden service setup on Tor and I2P ''' def __init__(self, hsPort): self.torConfigLocation = 'data/torrc' @@ -30,15 +30,19 @@ class NetController: self._torInstnace = '' self.myID = '' ''' - if os.path.exists(self.torConfigLocation): - torrc = open(self.torConfigLocation, 'r') - if not str(self.hsPort) in torrc.read(): - os.remove(self.torConfigLocation) - torrc.close() + if os.path.exists(self.torConfigLocation): + torrc = open(self.torConfigLocation, 'r') + if not str(self.hsPort) in torrc.read(): + os.remove(self.torConfigLocation) + torrc.close() ''' + return + def generateTorrc(self): - '''generate a torrc file for our tor instance''' + ''' + Generate a torrc file for our tor instance + ''' if os.path.exists(self.torConfigLocation): os.remove(self.torConfigLocation) torrcData = '''SocksPort ''' + str(self.socksPort) + ''' @@ -48,10 +52,12 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' torrc = open(self.torConfigLocation, 'w') torrc.write(torrcData) torrc.close() + return def startTor(self): - '''Start Tor with onion service on port 80 & socks proxy on random port + ''' + Start Tor with onion service on port 80 & socks proxy on random port ''' self.generateTorrc() if os.path.exists('./tor'): @@ -80,9 +86,13 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' torPidFile = open('data/torPid.txt', 'w') torPidFile.write(str(tor.pid)) torPidFile.close() + return True + def killTor(self): - '''properly kill tor based on pid saved to file''' + ''' + Properly kill tor based on pid saved to file + ''' try: pid = open('data/torPid.txt', 'r') pidN = pid.read() @@ -95,3 +105,5 @@ HiddenServicePort 80 127.0.0.1:''' + str(self.hsPort) + ''' return os.kill(int(pidN), signal.SIGTERM) os.remove('data/torPid.txt') + + return diff --git a/onionr/onionr.py b/onionr/onionr.py index 120280cb..48ffc758 100755 --- a/onionr/onionr.py +++ b/onionr/onionr.py @@ -234,4 +234,3 @@ class Onionr: return Onionr() - diff --git a/onionr/onionrcrypto.py b/onionr/onionrcrypto.py index 9624fb11..fed23889 100644 --- a/onionr/onionrcrypto.py +++ b/onionr/onionrcrypto.py @@ -22,9 +22,12 @@ import nacl class OnionrCrypto: def __init__(self): return + def symmetricPeerEncrypt(self, data, key): return + def symmetricPeerDecrypt(self, data, key): return + def rsaEncrypt(self, peer, data): - return \ No newline at end of file + return diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index 1884bb5a..ca575073 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -32,15 +32,22 @@ class OnionrUtils: self._core = coreInstance return def localCommand(self, command): - '''Send a command to the local http API server, securely. Intended for local clients, DO NOT USE for remote peers.''' + ''' + Send a command to the local http API server, securely. Intended for local clients, DO NOT USE for remote peers. + ''' config = configparser.ConfigParser() if os.path.exists('data/config.ini'): config.read('data/config.ini') else: return requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config['CLIENT']['PORT']) + '/client/?action=' + command + '&token=' + config['CLIENT']['CLIENT HMAC']) + + return + def getPassword(self, message='Enter password: ', confirm = True): - '''Get a password without showing the users typing and confirm the input''' + ''' + Get a password without showing the users typing and confirm the input + ''' # Get a password safely with confirmation and return it while True: print(message) @@ -55,9 +62,13 @@ class OnionrUtils: break else: break + return pass1 - def checkPort(self, port, host = ''): - '''Checks if a port is available, returns bool''' + + def checkPort(self, port, host=''): + ''' + Checks if a port is available, returns bool + ''' # inspired by https://www.reddit.com/r/learnpython/comments/2i4qrj/how_to_write_a_python_script_that_checks_to_see/ckzarux/ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) retVal = False @@ -68,36 +79,49 @@ class OnionrUtils: retVal = True finally: sock.close() + return retVal + def checkIsIP(self, ip): - '''Check if a string is a valid ipv4 address''' + ''' + Check if a string is a valid IPv4 address + ''' try: socket.inet_aton(ip) except: return False else: return True + def exportMyPubkey(self): - '''Export our PGP key if it exists''' + ''' + Export our PGP key if it exists + ''' if not os.path.exists(self.fingerprintFile): raise Exception("No fingerprint found, cannot export our PGP key.") gpg = gnupg.GPG(homedir='./data/pgp/') with open(self.fingerprintFile,'r') as f: fingerprint = f.read() ascii_armored_public_keys = gpg.export_keys(fingerprint) + return ascii_armored_public_keys def getBlockDBHash(self): - '''Return a sha3_256 hash of the blocks DB''' + ''' + Return a sha3_256 hash of the blocks DB + ''' with open(self._core.blockDB, 'rb') as data: data = data.read() hasher = hashlib.sha3_256() hasher.update(data) dataHash = hasher.hexdigest() + return dataHash def hasBlock(self, hash): - '''detect if we have a block in the list or not''' + ''' + Check for new block in the list + ''' conn = sqlite3.connect(self._core.blockDB) c = conn.cursor() if not self.validateHash(hash): @@ -113,7 +137,9 @@ class OnionrUtils: return False def validateHash(self, data, length=64): - '''Validate if a string is a valid hex formatted hash''' + ''' + Validate if a string is a valid hex formatted hash + ''' retVal = True if data == False or data == True: return False @@ -125,9 +151,13 @@ class OnionrUtils: int(data, 16) except ValueError: retVal = False + return retVal + def validateID(self, id): - '''validate if a user ID is a valid tor or i2p hidden service''' + ''' + Validate if a user ID is a valid tor or i2p hidden service + ''' idLength = len(id) retVal = True idNoDomain = '' @@ -165,4 +195,5 @@ class OnionrUtils: retVal = False if not idNoDomain.isalnum(): retVal = False + return retVal diff --git a/onionr/tests.py b/onionr/tests.py index d296d948..8babbdfd 100755 --- a/onionr/tests.py +++ b/onionr/tests.py @@ -23,6 +23,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(False) else: self.assertTrue(True) + def testNone(self): logger.debug('--------------------------') logger.info('Running simple program run test...') @@ -32,6 +33,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(False) else: self.assertTrue(True) + def testPeer_a_DBCreation(self): logger.debug('--------------------------') logger.info('Running peer db creation test...') @@ -44,6 +46,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(True) else: self.assertTrue(False) + def testPeer_b_addPeerToDB(self): logger.debug('--------------------------') logger.info('Running peer db insertion test...') @@ -55,6 +58,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(True) else: self.assertTrue(False) + def testData_b_Encrypt(self): self.assertTrue(True) return @@ -67,6 +71,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(True) else: self.assertTrue(False) + def testData_a_Decrypt(self): self.assertTrue(True) return @@ -79,6 +84,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(True) else: self.assertTrue(False) + def testPGPGen(self): logger.debug('--------------------------') logger.info('Running PGP key generation test...') @@ -93,6 +99,7 @@ class OnionrTests(unittest.TestCase): myCore.generateMainPGP(torID) if os.path.exists('data/pgp/'): self.assertTrue(True) + def testHMACGen(self): logger.debug('--------------------------') logger.info('Running HMAC generation test...') @@ -104,6 +111,7 @@ class OnionrTests(unittest.TestCase): self.assertTrue(True) else: self.assertTrue(False) + def testQueue(self): logger.debug('--------------------------') logger.info('Running daemon queue test...') @@ -124,4 +132,5 @@ class OnionrTests(unittest.TestCase): if command[0] == 'testCommand': if myCore.daemonQueue() == False: logger.info('Succesfully added and read command') + unittest.main() diff --git a/onionr/timedHmac.py b/onionr/timedHmac.py index d703a905..2f23317f 100644 --- a/onionr/timedHmac.py +++ b/onionr/timedHmac.py @@ -16,12 +16,12 @@ import hmac, base64, time, math class TimedHMAC: def __init__(self, base64Key, data, hashAlgo): ''' - base64Key = base64 encoded key - data = data to hash - expire = time expiry in epoch - hashAlgo = string in hashlib.algorithms_available + base64Key = base64 encoded key + data = data to hash + expire = time expiry in epoch + hashAlgo = string in hashlib.algorithms_available - Maximum of 10 seconds grace period + Maximum of 10 seconds grace period ''' self.data = data self.expire = math.floor(time.time()) @@ -30,6 +30,7 @@ class TimedHMAC: generatedHMAC = hmac.HMAC(base64.b64decode(base64Key).decode(), digestmod=self.hashAlgo) generatedHMAC.update(data + expire) self.HMACResult = generatedHMAC.hexdigest() + return def check(self, data):