Merge branch 'crypto' of github.com:beardog108/onionr into crypto

This commit is contained in:
Kevin Froman 2018-05-02 02:40:35 -05:00
commit 98dac40139
7 changed files with 116 additions and 53 deletions

View File

@ -136,7 +136,7 @@ class API:
if action == 'hello': if action == 'hello':
resp = Response('Hello, World! ' + request.host) resp = Response('Hello, World! ' + request.host)
elif action == 'shutdown': elif action == 'shutdown':
request.environ.get('werkzeug.server.shutdown')() # request.environ.get('werkzeug.server.shutdown')()
resp = Response('Goodbye') resp = Response('Goodbye')
elif action == 'ping': elif action == 'ping':
resp = Response('pong') resp = Response('pong')
@ -163,7 +163,7 @@ class API:
time.sleep(self._privateDelayTime - elapsed) time.sleep(self._privateDelayTime - elapsed)
return resp return resp
@app.route('/') @app.route('/')
def banner(): def banner():
self.mimeType = 'text/html' self.mimeType = 'text/html'

View File

@ -111,7 +111,12 @@ class OnionrCommunicate:
if announceAttemptCount >= announceAttempts: if announceAttemptCount >= announceAttempts:
logger.warn('Unable to announce to ' + command[1]) logger.warn('Unable to announce to ' + command[1])
break break
elif command[0] == 'runCheck':
logger.info('Status check; looks good.')
open('data/.runcheck', 'w+').close()
apiRunningCheckCount += 1 apiRunningCheckCount += 1
# check if local API is up # check if local API is up
if apiRunningCheckCount > apiRunningCheckRate: if apiRunningCheckCount > apiRunningCheckRate:
if self._core._utils.localCommand('ping') != 'pong': if self._core._utils.localCommand('ping') != 'pong':
@ -127,6 +132,7 @@ class OnionrCommunicate:
apiRunningCheckCount = 0 apiRunningCheckCount = 0
time.sleep(1) time.sleep(1)
self._netController.killTor() self._netController.killTor()
return return
@ -352,7 +358,7 @@ class OnionrCommunicate:
if not peer.endswith('.onion') and not peer.endswith('.onion/'): if not peer.endswith('.onion') and not peer.endswith('.onion/'):
raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion') raise PeerError('Currently only Tor .onion peers are supported. You must manually specify .onion')
if len(self._core.hsAdder.strip()) == 0: if len(self._core.hsAdder.strip()) == 0:
raise Exception("Could not perform self address check in performGet due to not knowing our address") raise Exception("Could not perform self address check in performGet due to not knowing our address")
if selfCheck: if selfCheck:

View File

@ -155,7 +155,7 @@ class Core:
return True return True
else: else:
return False return False
def removeBlock(self, block): def removeBlock(self, block):
''' '''
remove a block from this node remove a block from this node
@ -590,7 +590,7 @@ class Core:
conn.commit() conn.commit()
conn.close() conn.close()
return return
def updateBlockInfo(self, hash, key, data): def updateBlockInfo(self, hash, key, data):
''' '''
sets info associated with a block sets info associated with a block
@ -611,12 +611,15 @@ class Core:
''' '''
Inserts a block into the network Inserts a block into the network
''' '''
try: try:
data.decode() data.decode()
except AttributeError: except AttributeError:
data = data.encode() data = data.encode()
retData = '' retData = ''
metadata = {'type': header} metadata = {'type': header}
if sign: if sign:
signature = self._crypto.edSign(data, self._crypto.privKey, encodeResult=True) signature = self._crypto.edSign(data, self._crypto.privKey, encodeResult=True)
ourID = self._crypto.pubKeyHashID() ourID = self._crypto.pubKeyHashID()
@ -627,8 +630,10 @@ class Core:
pass pass
metadata['id'] = ourID metadata['id'] = ourID
metadata['sig'] = signature metadata['sig'] = signature
metadata = json.dumps(metadata) metadata = json.dumps(metadata)
metadata = metadata.encode() metadata = metadata.encode()
if len(data) == 0: if len(data) == 0:
logger.error('Will not insert empty block') logger.error('Will not insert empty block')
else: else:
@ -642,16 +647,28 @@ class Core:
''' '''
Introduces our node into the network by telling X many nodes our HS address Introduces our node into the network by telling X many nodes our HS address
''' '''
announceAmount = 2
nodeList = self.listAdders() if(self._utils.isCommunicatorRunning()):
if len(nodeList) == 0: announceAmount = 2
for i in self.bootstrapList: nodeList = self.listAdders()
if self._utils.validateID(i):
self.addAddress(i) if len(nodeList) == 0:
nodeList.append(i) for i in self.bootstrapList:
if announceAmount > len(nodeList): if self._utils.validateID(i):
announceAmount = len(nodeList) self.addAddress(i)
for i in range(announceAmount): nodeList.append(i)
self.daemonQueueAdd('announceNode', nodeList[i])
events.event('introduction', onionr = None) if announceAmount > len(nodeList):
announceAmount = len(nodeList)
for i in range(announceAmount):
self.daemonQueueAdd('announceNode', nodeList[i])
events.event('introduction', onionr = None)
return True
else:
logger.error('Onionr daemon is not running.')
return False
return return

View File

@ -99,17 +99,17 @@ def commandInstallPlugin():
return True return True
elif valid_hash and real_block: elif valid_hash and real_block:
blockhash = str(pkobh) blockhash = str(pkobh)
logger.debug('Using block ' + blockhash + '...') logger.debug('Using block %s...' % blockhash)
elif valid_key and not real_key: elif valid_key and not real_key:
logger.error('Public key not found. Try adding the node by address manually, if possible.') logger.error('Public key not found. Try adding the node by address manually, if possible.')
logger.debug('Is valid key, but the key is not a known one.') logger.debug('Is valid key, but the key is not a known one.')
elif valid_key and real_key: elif valid_key and real_key:
publickey = str(pkobh) publickey = str(pkobh)
logger.debug('Using public key ' + publickey + '...') logger.debug('Using public key %s...' % publickey)
saveKey(pluginname, pkobh) saveKey(pluginname, pkobh)
else: else:
logger.error('Unknown data \"' + str(pkobh) + '\"; must be public key or block hash.') logger.error('Unknown data "%s"; must be public key or block hash.' % str(pkobh))
return return
else: else:
help() help()

View File

@ -18,7 +18,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import re, sys, time import re, sys, time, traceback
class colors: class colors:
''' '''
@ -220,9 +220,19 @@ def error(data, error=None, timestamp=True):
if get_level() <= LEVEL_ERROR: if get_level() <= LEVEL_ERROR:
log('-', data, colors.fg.red, timestamp=timestamp) log('-', data, colors.fg.red, timestamp=timestamp)
if not error is None: if not error is None:
debug('Error details: ' + str(error)) debug('Error: ' + str(error) + parse_error())
# fatal: when the something so bad has happened that the prorgam must stop # fatal: when the something so bad has happened that the prorgam must stop
def fatal(data, timestamp=True): def fatal(data, timestamp=True):
if get_level() <= LEVEL_FATAL: if get_level() <= LEVEL_FATAL:
log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp=timestamp) log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp=timestamp)
# returns a formatted error message
def parse_error():
details = traceback.extract_tb(sys.exc_info()[2])
output = ''
for line in details:
output += '\n ... module %s in %s:%i' % (line[2], line[0], line[1])
return output

View File

@ -203,13 +203,13 @@ class Onionr:
'disable-plugin': 'Disables and stops a plugin', 'disable-plugin': 'Disables and stops a plugin',
'reload-plugin': 'Reloads a plugin', 'reload-plugin': 'Reloads a plugin',
'create-plugin': 'Creates directory structure for a plugin', 'create-plugin': 'Creates directory structure for a plugin',
'add-peer': 'Adds a peer (?)', 'add-peer': 'Adds a peer to database',
'list-peers': 'Displays a list of peers', 'list-peers': 'Displays a list of peers',
'add-msg': 'Broadcasts a message to the Onionr network', 'add-msg': 'Broadcasts a message to the Onionr network',
'pm': 'Adds a private message to block', 'pm': 'Adds a private message to block',
'get-pms': 'Shows private messages sent to you', 'get-pms': 'Shows private messages sent to you',
'addfile': 'Create an Onionr block from a file', 'addfile': 'Create an Onionr block from a file',
'introduce': 'Introduce your node to the public Onionr network (DAEMON MUST BE RUNNING)', 'introduce': 'Introduce your node to the public Onionr network',
} }
# initialize plugins # initialize plugins
@ -293,11 +293,11 @@ class Onionr:
Displays the Onionr version Displays the Onionr version
''' '''
logger.info('Onionr ' + ONIONR_VERSION + ' (' + platform.machine() + ') - API v' + API_VERSION) logger.info('Onionr %s (%s) - API v%s' % (ONIONR_VERSION, platform.machine(), API_VERSION))
if verbosity >= 1: if verbosity >= 1:
logger.info(ONIONR_TAGLINE) logger.info(ONIONR_TAGLINE)
if verbosity >= 2: if verbosity >= 2:
logger.info('Running on ' + platform.platform() + ' ' + platform.release()) logger.info('Running on %s %s' % (platform.platform(), platform.release()))
return return
@ -323,7 +323,7 @@ class Onionr:
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
else: else:
logger.info("Sending message to " + peer) logger.info("Sending message to: " + logger.colors.underline + peer)
self.onionrUtils.sendPM(peer, message) self.onionrUtils.sendPM(peer, message)
@ -355,6 +355,7 @@ class Onionr:
''' '''
Adds a Onionr node address Adds a Onionr node address
''' '''
try: try:
newAddress = sys.argv[2] newAddress = sys.argv[2]
except: except:
@ -374,22 +375,25 @@ class Onionr:
''' '''
while True: while True:
try:
messageToAdd = logger.readline('Broadcast message to network: ') messageToAdd = logger.readline('Broadcast message to network: ')
if len(messageToAdd) >= 1: if len(messageToAdd) >= 1:
break break
except KeyboardInterrupt:
return
#addedHash = self.onionrCore.setData(messageToAdd) #addedHash = self.onionrCore.setData(messageToAdd)
addedHash = self.onionrCore.insertBlock(messageToAdd, header='txt') addedHash = self.onionrCore.insertBlock(messageToAdd, header='txt')
#self.onionrCore.addToBlockDB(addedHash, selfInsert=True) #self.onionrCore.addToBlockDB(addedHash, selfInsert=True)
#self.onionrCore.setBlockType(addedHash, 'txt') #self.onionrCore.setBlockType(addedHash, 'txt')
logger.info("inserted your message as block: " + addedHash) logger.info("Message inserted as as block %s" % addedHash)
return return
def getPMs(self): def getPMs(self):
''' '''
display PMs sent to us display PMs sent to us
''' '''
self.onionrUtils.loadPMs() self.onionrUtils.loadPMs()
def enablePlugin(self): def enablePlugin(self):
@ -399,10 +403,10 @@ class Onionr:
if len(sys.argv) >= 3: if len(sys.argv) >= 3:
plugin_name = sys.argv[2] plugin_name = sys.argv[2]
logger.info('Enabling plugin \"' + plugin_name + '\"...') logger.info('Enabling plugin "%s"...' % plugin_name)
plugins.enable(plugin_name, self) plugins.enable(plugin_name, self)
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>') logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
return return
@ -413,10 +417,10 @@ class Onionr:
if len(sys.argv) >= 3: if len(sys.argv) >= 3:
plugin_name = sys.argv[2] plugin_name = sys.argv[2]
logger.info('Disabling plugin \"' + plugin_name + '\"...') logger.info('Disabling plugin "%s"...' % plugin_name)
plugins.disable(plugin_name, self) plugins.disable(plugin_name, self)
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>') logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
return return
@ -427,7 +431,7 @@ class Onionr:
if len(sys.argv) >= 3: if len(sys.argv) >= 3:
plugin_name = sys.argv[2] plugin_name = sys.argv[2]
logger.info('Reloading plugin \"' + plugin_name + '\"...') logger.info('Reloading plugin "%s"...' % plugin_name)
plugins.stop(plugin_name, self) plugins.stop(plugin_name, self)
plugins.start(plugin_name, self) plugins.start(plugin_name, self)
else: else:
@ -446,21 +450,21 @@ class Onionr:
plugin_name = re.sub('[^0-9a-zA-Z]+', '', str(sys.argv[2]).lower()) plugin_name = re.sub('[^0-9a-zA-Z]+', '', str(sys.argv[2]).lower())
if not plugins.exists(plugin_name): if not plugins.exists(plugin_name):
logger.info('Creating plugin \"' + plugin_name + '\"...') logger.info('Creating plugin "%s"...' % plugin_name)
os.makedirs(plugins.get_plugins_folder(plugin_name)) os.makedirs(plugins.get_plugins_folder(plugin_name))
with open(plugins.get_plugins_folder(plugin_name) + '/main.py', 'a') as main: with open(plugins.get_plugins_folder(plugin_name) + '/main.py', 'a') as main:
main.write(open('static-data/default_plugin.txt').read().replace('$user', os.getlogin()).replace('$date', datetime.datetime.now().strftime('%Y-%m-%d'))) main.write(open('static-data/default_plugin.txt').read().replace('$user', os.getlogin()).replace('$date', datetime.datetime.now().strftime('%Y-%m-%d')))
logger.info('Enabling plugin \"' + plugin_name + '\"...') logger.info('Enabling plugin "%s"...' % plugin_name)
plugins.enable(plugin_name, self) plugins.enable(plugin_name, self)
else: else:
logger.warn('Cannot create plugin directory structure; plugin "' + plugin_name + '" exists.') logger.warn('Cannot create plugin directory structure; plugin "%s" exists.' % plugin_name)
except Exception as e: except Exception as e:
logger.error('Failed to create plugin directory structure.', e) logger.error('Failed to create plugin directory structure.', e)
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>') logger.info('%s %s <plugin>' % (sys.argv[0], sys.argv[1]))
return return
@ -523,15 +527,18 @@ class Onionr:
Shutdown the Onionr daemon Shutdown the Onionr daemon
''' '''
logger.warn('Killing the running daemon') logger.warn('Killing the running daemon...', timestamp = False)
events.event('daemon_stop', onionr = self)
net = NetController(config.get('client')['port'])
try: try:
self.onionrUtils.localCommand('shutdown') events.event('daemon_stop', onionr = self)
except requests.exceptions.ConnectionError: net = NetController(config.get('client')['port'])
pass try:
self.onionrCore.daemonQueueAdd('shutdown') self.onionrUtils.localCommand('shutdown')
net.killTor() except requests.exceptions.ConnectionError:
pass
self.onionrCore.daemonQueueAdd('shutdown')
net.killTor()
except Exception as e:
logger.error('Failed to shutdown daemon.', error = e, timestamp = False)
return return
@ -539,6 +546,7 @@ class Onionr:
''' '''
Displays statistics and exits Displays statistics and exits
''' '''
logger.info('Our pubkey: ' + self.onionrCore._crypto.pubKey) logger.info('Our pubkey: ' + self.onionrCore._crypto.pubKey)
logger.info('Our address: ' + self.get_hostname()) logger.info('Our address: ' + self.get_hostname())
return return

View File

@ -59,14 +59,14 @@ class OnionrUtils:
sign = self._core._crypto.edSign(message, self._core._crypto.privKey, encodeResult=True) sign = self._core._crypto.edSign(message, self._core._crypto.privKey, encodeResult=True)
#encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True).decode() #encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True).decode()
payload['sig'] = sign payload['sig'] = sign
payload['msg'] = message payload['msg'] = message
payload = json.dumps(payload) payload = json.dumps(payload)
message = payload message = payload
encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True).decode() encrypted = self._core._crypto.pubKeyEncrypt(message, pubkey, anonymous=True, encodedData=True).decode()
block = self._core.insertBlock(encrypted, header='pm', sign=False) block = self._core.insertBlock(encrypted, header='pm', sign=False)
if block == '': if block == '':
logger.error('Could not send PM') logger.error('Could not send PM')
@ -383,7 +383,7 @@ class OnionrUtils:
except Exception as error: except Exception as error:
logger.error('Failed to open block ' + str(i) + '.', error=error) logger.error('Failed to open block ' + str(i) + '.', error=error)
return return
def getPeerByHashId(self, hash): def getPeerByHashId(self, hash):
''' '''
Return the pubkey of the user if known from the hash Return the pubkey of the user if known from the hash
@ -398,4 +398,26 @@ class OnionrUtils:
for row in c.execute('SELECT ID FROM peers where hashID=?', command): for row in c.execute('SELECT ID FROM peers where hashID=?', command):
if row[0] != '': if row[0] != '':
retData = row[0] retData = row[0]
return retData return retData
def isCommunicatorRunning(self, timeout = 5, interval = 0.1):
try:
runcheck_file = 'data/.runcheck'
if os.path.isfile(runcheck_file):
os.remove(runcheck_file)
logger.debug('%s file appears to have existed before the run check.' % runcheck_file, timestamp = False)
self._core.daemonQueueAdd('runCheck')
starttime = time.time()
while True:
time.sleep(interval)
if os.path.isfile(runcheck_file):
os.remove(runcheck_file)
return True
elif time.time() - starttime >= timeout:
return False
except:
return False