work on pm and gui improvements & some bug fixes
parent
3a2efce637
commit
a3aa8e3ae6
|
@ -32,7 +32,8 @@ class API:
|
|||
'''
|
||||
Validate that the client token (hmac) matches the given token
|
||||
'''
|
||||
if self.clientToken != token:
|
||||
|
||||
if not hmac.compare_digest(self.clientToken.strip(), token.strip()):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
@ -63,6 +64,11 @@ class API:
|
|||
bindPort = int(config.get('client')['port'])
|
||||
self.bindPort = bindPort
|
||||
self.clientToken = config.get('client')['client_hmac']
|
||||
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
|
||||
|
||||
with open('data/time-bypass.txt', 'w') as bypass:
|
||||
bypass.write(self.timeBypassToken)
|
||||
|
||||
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
|
||||
logger.debug('Your HMAC token: ' + logger.colors.underline + self.clientToken)
|
||||
|
||||
|
@ -99,11 +105,16 @@ class API:
|
|||
|
||||
@app.route('/client/')
|
||||
def private_handler():
|
||||
if request.args.get('timingToken') is None:
|
||||
timingToken = ''
|
||||
else:
|
||||
timingToken = request.args.get('timingToken')
|
||||
startTime = math.floor(time.time())
|
||||
# we should keep a hash DB of requests (with hmac) to prevent replays
|
||||
action = request.args.get('action')
|
||||
#if not self.debug:
|
||||
token = request.args.get('token')
|
||||
|
||||
if not self.validateToken(token):
|
||||
abort(403)
|
||||
self.validateHost('private')
|
||||
|
@ -112,14 +123,19 @@ class API:
|
|||
elif action == 'shutdown':
|
||||
request.environ.get('werkzeug.server.shutdown')()
|
||||
resp = Response('Goodbye')
|
||||
elif action == 'ping':
|
||||
resp = Response('pong')
|
||||
elif action == 'stats':
|
||||
resp = Response('me_irl')
|
||||
else:
|
||||
resp = Response('(O_o) Dude what? (invalid command)')
|
||||
endTime = math.floor(time.time())
|
||||
elapsed = endTime - startTime
|
||||
if elapsed < self._privateDelayTime:
|
||||
time.sleep(self._privateDelayTime - elapsed)
|
||||
|
||||
# if bypass token not used, delay response to prevent timing attacks
|
||||
if not hmac.compare_digest(timingToken, self.timeBypassToken):
|
||||
if elapsed < self._privateDelayTime:
|
||||
time.sleep(self._privateDelayTime - elapsed)
|
||||
|
||||
return resp
|
||||
|
||||
|
@ -208,9 +224,11 @@ class API:
|
|||
host = self.host
|
||||
if hostType == 'private':
|
||||
if not request.host.startswith('127') and not self._utils.checkIsIP(request.host):
|
||||
print("WHAT")
|
||||
abort(403)
|
||||
elif hostType == 'public':
|
||||
if not request.host.endswith('onion') and not request.host.endswith('i2p'):
|
||||
print("WHAT2")
|
||||
abort(403)
|
||||
# Validate x-requested-with, to protect against CSRF/metadata leaks
|
||||
if not self._developmentMode:
|
||||
|
|
|
@ -513,3 +513,17 @@ class Core:
|
|||
conn.close()
|
||||
|
||||
return
|
||||
|
||||
def insertBlock(self, data, header='txt'):
|
||||
'''
|
||||
Inserts a block into the network
|
||||
'''
|
||||
retData = ''
|
||||
if len(data) == 0:
|
||||
logger.error('Will not insert empty block')
|
||||
else:
|
||||
addedHash = self.setData('-' + header + '-' + data)
|
||||
self.addToBlockDB(addedHash, selfInsert=True)
|
||||
self.setBlockType(addedHash, header)
|
||||
retData = addedHash
|
||||
return retData
|
|
@ -19,30 +19,55 @@ import os, sqlite3, core
|
|||
class OnionrGUI:
|
||||
def __init__(self, myCore):
|
||||
self.root = Tk()
|
||||
|
||||
self.myCore = myCore # onionr core
|
||||
self.root.title("PyOnionr")
|
||||
|
||||
w = Label(self.root, text="Onionr", width=10)
|
||||
w.config(font=("Sans-Serif", 22))
|
||||
w.pack()
|
||||
self.runningCheckDelay = 5
|
||||
self.runningCheckDelayCount = 0
|
||||
|
||||
scrollbar = Scrollbar(self.root)
|
||||
scrollbar.pack(side=RIGHT, fill=Y)
|
||||
|
||||
self.listedBlocks = []
|
||||
|
||||
self.nodeInfo = Frame(self.root)
|
||||
self.keyInfo = Frame(self.root)
|
||||
|
||||
idText = open('./data/hs/hostname', 'r').read()
|
||||
idLabel = Label(self.root, text="ID: " + idText)
|
||||
idLabel.pack(pady=5)
|
||||
#idLabel = Label(self.info, text="Node Address: " + idText)
|
||||
#idLabel.pack(pady=5)
|
||||
|
||||
idEntry = Entry(self.nodeInfo)
|
||||
Label(self.nodeInfo, text="Node Address: ").pack(side=LEFT)
|
||||
idEntry.pack()
|
||||
idEntry.insert(0, idText.strip())
|
||||
idEntry.configure(state="readonly")
|
||||
|
||||
self.nodeInfo.pack()
|
||||
|
||||
pubKeyEntry = Entry(self.keyInfo)
|
||||
|
||||
Label(self.keyInfo, text="Public key: ").pack(side=LEFT)
|
||||
|
||||
pubKeyEntry.pack()
|
||||
pubKeyEntry.insert(0, self.myCore._crypto.pubKey)
|
||||
pubKeyEntry.configure(state="readonly")
|
||||
|
||||
self.keyInfo.pack()
|
||||
|
||||
self.sendEntry = Entry(self.root)
|
||||
sendBtn = Button(self.root, text='Send Message', command=self.sendMessage)
|
||||
self.sendEntry.pack()
|
||||
sendBtn.pack()
|
||||
self.sendEntry.pack(side=TOP, pady=5)
|
||||
sendBtn.pack(side=TOP)
|
||||
|
||||
self.listbox = Listbox(self.root, yscrollcommand=scrollbar.set, height=15)
|
||||
|
||||
#listbox.insert(END, str(i))
|
||||
self.listbox.pack(fill=BOTH)
|
||||
self.listbox.pack(fill=BOTH, pady=25)
|
||||
|
||||
self.daemonStatus = Label(self.root, text="Onionr Daemon Status: unknown")
|
||||
self.daemonStatus.pack()
|
||||
|
||||
scrollbar.config(command=self.listbox.yview)
|
||||
self.root.after(2000, self.update)
|
||||
|
@ -66,5 +91,12 @@ class OnionrGUI:
|
|||
self.listbox.see(END)
|
||||
blocksList = os.listdir('./data/blocks/') # dir is your directory path
|
||||
number_blocks = len(blocksList)
|
||||
self.runningCheckDelayCount += 1
|
||||
|
||||
if self.runningCheckDelayCount == self.runningCheckDelay:
|
||||
if self.myCore._utils.localCommand('ping') == 'pong':
|
||||
self.daemonStatus.config(text="Onionr Daemon Status: Running")
|
||||
else:
|
||||
self.daemonStatus.config(text="Onionr Daemon Status: Not Running")
|
||||
self.runningCheckDelayCount = 0
|
||||
self.root.after(10000, self.update)
|
||||
|
|
|
@ -111,7 +111,7 @@ class Onionr:
|
|||
randomPort = random.randint(1024, 65535)
|
||||
if self.onionrUtils.checkPort(randomPort):
|
||||
break
|
||||
config.set('client', {'participate': 'true', 'client_hmac': base64.b64encode(os.urandom(32)).decode('utf-8'), 'port': randomPort, 'api_version': API_VERSION}, True)
|
||||
config.set('client', {'participate': 'true', 'client_hmac': base64.b16encode(os.urandom(32)).decode('utf-8'), 'port': randomPort, 'api_version': API_VERSION}, True)
|
||||
|
||||
self.cmds = {
|
||||
'': self.showHelpSuggestion,
|
||||
|
@ -316,14 +316,15 @@ class Onionr:
|
|||
|
||||
return
|
||||
|
||||
def addMessage(self):
|
||||
def addMessage(self, header="txt"):
|
||||
'''
|
||||
Broadcasts a message to the Onionr network
|
||||
'''
|
||||
|
||||
while True:
|
||||
|
||||
messageToAdd = '-txt-' + logger.readline('Broadcast message to network: ')
|
||||
if len(messageToAdd) >= 1:
|
||||
if len(messageToAdd) - 5 >= 1:
|
||||
break
|
||||
|
||||
addedHash = self.onionrCore.setData(messageToAdd)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
# Misc functions that do not fit in the main api, but are useful
|
||||
import getpass, sys, requests, os, socket, hashlib, logger, sqlite3, config, binascii
|
||||
import getpass, sys, requests, os, socket, hashlib, logger, sqlite3, config, binascii, time
|
||||
import nacl.signing, nacl.encoding
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
|
@ -35,7 +35,15 @@ class OnionrUtils:
|
|||
def __init__(self, coreInstance):
|
||||
self.fingerprintFile = 'data/own-fingerprint.txt'
|
||||
self._core = coreInstance
|
||||
|
||||
self.timingToken = ''
|
||||
|
||||
return
|
||||
|
||||
def getTimeBypassToken(self):
|
||||
if os.path.exists('data/time-bypass.txt'):
|
||||
with open('data/time-bypass.txt', 'r') as bypass:
|
||||
self.timingToken = bypass.read()
|
||||
|
||||
def sendPM(self, pubkey, message):
|
||||
'''High level function to encrypt a message to a peer and insert it as a block'''
|
||||
|
@ -44,9 +52,13 @@ class OnionrUtils:
|
|||
|
||||
#if self._core.getPeerInfo(pubkey, 'pubkeyExchanged') == 1:
|
||||
# pass
|
||||
encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True)
|
||||
logger.info(encrypted)
|
||||
return
|
||||
encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True).decode()
|
||||
block = self._core.insertBlock(encrypted, header='pm')
|
||||
|
||||
if block == '':
|
||||
logger.error('Could not send PM')
|
||||
else:
|
||||
logger.info('Sent PM, hash: ' + block)
|
||||
|
||||
return
|
||||
|
||||
|
@ -99,11 +111,14 @@ class OnionrUtils:
|
|||
'''
|
||||
|
||||
config.reload()
|
||||
|
||||
self.getTimeBypassToken()
|
||||
# TODO: URL encode parameters, just as an extra measure. May not be needed, but should be added regardless.
|
||||
requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config.get('client')['port']) + '/client/?action=' + command + '&token=' + str(config.get('client')['client_hmac']))
|
||||
try:
|
||||
retData = requests.get('http://' + open('data/host.txt', 'r').read() + ':' + str(config.get('client')['port']) + '/client/?action=' + command + '&token=' + str(config.get('client')['client_hmac']) + '&timingToken=' + self.timingToken).text
|
||||
except requests.ConnectionError:
|
||||
retData = False
|
||||
|
||||
return
|
||||
return retData
|
||||
|
||||
def getPassword(self, message='Enter password: ', confirm = True):
|
||||
'''
|
||||
|
|
Loading…
Reference in New Issue