Code consistency updates
- Improved formatting - Added comments - URL encoded values in netcontroller.performGET - Kept SQL statement case consistency
This commit is contained in:
parent
bdd1d9697b
commit
62cad7a6ea
@ -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?
|
||||
|
||||
|
@ -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"
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
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
|
||||
|
||||
|
||||
|
190
onionr/core.py
190
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()
|
||||
conn.close()
|
||||
|
||||
return
|
||||
|
@ -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
|
||||
|
@ -234,4 +234,3 @@ class Onionr:
|
||||
return
|
||||
|
||||
Onionr()
|
||||
|
||||
|
@ -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
|
||||
return
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user