Make Onionr more user friendly

This commit mostly just made messages more readable, worked on logger, and fixed a few bugs
master
Arinerron 2018-11-10 19:25:40 -08:00
parent 22115891f2
commit bb08162019
No known key found for this signature in database
GPG Key ID: 99383627861C62F0
16 changed files with 245 additions and 152 deletions

View File

@ -24,7 +24,7 @@ from gevent.pywsgi import WSGIServer
import sys, random, threading, hmac, hashlib, base64, time, math, os, json
import core
from onionrblockapi import Block
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config, onionr
class API:
'''
@ -75,14 +75,8 @@ class API:
This also saves the used host (random localhost IP address) to the data folder in host.txt
'''
config.reload()
if config.get('dev_mode', True):
self._developmentMode = True
logger.set_level(logger.LEVEL_DEBUG)
else:
self._developmentMode = False
logger.set_level(logger.LEVEL_INFO)
# configure logger and stuff
onionr.Onionr.setupConfig('data/', self = self)
self.debug = debug
self._privateDelayTime = 3
@ -131,14 +125,14 @@ class API:
resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'"
resp.headers['X-Frame-Options'] = 'deny'
resp.headers['X-Content-Type-Options'] = "nosniff"
resp.headers['api'] = API_VERSION
resp.headers['X-API'] = API_VERSION
# reset to text/plain to help prevent browser attacks
self.mimeType = 'text/plain'
self.overrideCSP = False
return resp
@app.route('/www/private/<path:path>')
def www_private(path):
startTime = math.floor(time.time())

View File

@ -21,12 +21,14 @@
'''
import sys, os, core, config, json, requests, time, logger, threading, base64, onionr, uuid
import onionrexceptions, onionrpeers, onionrevents as events, onionrplugins as plugins, onionrblockapi as block
import onionrdaemontools, onionrsockets, onionrchat
import onionrdaemontools, onionrsockets, onionrchat, onionr
from dependencies import secrets
from defusedxml import minidom
class OnionrCommunicatorDaemon:
def __init__(self, debug, developmentMode):
# configure logger and stuff
onionr.Onionr.setupConfig('data/', self = self)
self.isOnline = True # Assume we're connected to the internet
@ -303,9 +305,11 @@ class OnionrCommunicatorDaemon:
self.decrementThreadCount('clearOfflinePeer')
def getOnlinePeers(self):
'''Manages the self.onlinePeers attribute list, connects to more peers if we have none connected'''
'''
Manages the self.onlinePeers attribute list, connects to more peers if we have none connected
'''
logger.info('Refreshing peer pool.')
logger.debug('Refreshing peer pool...')
maxPeers = int(config.get('peers.max_connect', 10))
needed = maxPeers - len(self.onlinePeers)
@ -318,11 +322,13 @@ class OnionrCommunicatorDaemon:
break
else:
if len(self.onlinePeers) == 0:
logger.warn('Could not connect to any peer.')
logger.debug('Couldn\'t connect to any peers.')
self.decrementThreadCount('getOnlinePeers')
def addBootstrapListToPeerList(self, peerList):
'''Add the bootstrap list to the peer list (no duplicates)'''
'''
Add the bootstrap list to the peer list (no duplicates)
'''
for i in self._core.bootstrapList:
if i not in peerList and i not in self.offlinePeers and i != self._core.hsAddress and len(str(i).strip()) > 0:
peerList.append(i)
@ -440,11 +446,13 @@ class OnionrCommunicatorDaemon:
def heartbeat(self):
'''Show a heartbeat debug message'''
currentTime = self._core._utils.getEpoch() - self.startTime
logger.debug('heartbeat, running seconds: ' + str(currentTime))
logger.debug('Heartbeat. Node online for %s.' % self.daemonTools.humanReadableTime(currentTime))
self.decrementThreadCount('heartbeat')
def daemonCommands(self):
'''process daemon commands from daemonQueue'''
'''
Process daemon commands from daemonQueue
'''
cmd = self._core.daemonQueue()
if cmd is not False:

View File

@ -73,6 +73,7 @@ LEVEL_INFO = 2
LEVEL_WARN = 3
LEVEL_ERROR = 4
LEVEL_FATAL = 5
LEVEL_IMPORTANT = 6
_type = OUTPUT_TO_CONSOLE | USE_ANSI # the default settings for logging
_level = LEVEL_DEBUG # the lowest level to log
@ -201,36 +202,36 @@ def confirm(default = 'y', message = 'Are you sure %s? '):
return default == 'y'
# debug: when there is info that could be useful for debugging purposes only
def debug(data, error = None, timestamp = True, prompt = True, sensitive = False):
if get_level() <= LEVEL_DEBUG:
log('/', data, timestamp=timestamp, prompt = prompt, sensitive = sensitive)
def debug(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_DEBUG):
if get_level() <= level:
log('/', data, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
if not error is None:
debug('Error: ' + str(error) + parse_error())
# info: when there is something to notify the user of, such as the success of a process
def info(data, timestamp = False, prompt = True, sensitive = False):
if get_level() <= LEVEL_INFO:
def info(data, timestamp = False, prompt = True, sensitive = False, level = LEVEL_INFO):
if get_level() <= level:
log('+', data, colors.fg.green, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
# warn: when there is a potential for something bad to happen
def warn(data, error = None, timestamp = True, prompt = True, sensitive = False):
def warn(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_WARN):
if not error is None:
debug('Error: ' + str(error) + parse_error())
if get_level() <= LEVEL_WARN:
if get_level() <= level:
log('!', data, colors.fg.orange, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
# error: when only one function, module, or process of the program encountered a problem and must stop
def error(data, error = None, timestamp = True, prompt = True, sensitive = False):
if get_level() <= LEVEL_ERROR:
def error(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_ERROR):
if get_level() <= level:
log('-', data, colors.fg.red, timestamp = timestamp, fd = sys.stderr, prompt = prompt, sensitive = sensitive)
if not error is None:
debug('Error: ' + str(error) + parse_error())
# fatal: when the something so bad has happened that the program must stop
def fatal(data, error = None, timestamp=True, prompt = True, sensitive = False):
def fatal(data, error = None, timestamp=True, prompt = True, sensitive = False, level = LEVEL_FATAL):
if not error is None:
debug('Error: ' + str(error) + parse_error(), sensitive = sensitive)
if get_level() <= LEVEL_FATAL:
if get_level() <= level:
log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp = timestamp, fd = sys.stderr, prompt = prompt, sensitive = sensitive)
# returns a formatted error message

View File

@ -141,7 +141,7 @@ HashedControlPassword ''' + str(password) + '''
logger.fatal('Failed to start Tor. Maybe a stray instance of Tor used by Onionr is still running?')
return False
except KeyboardInterrupt:
logger.fatal("Got keyboard interrupt.")
logger.fatal('Got keyboard interrupt.', timestamp = false, level = logger.LEVEL_IMPORTANT)
return False
logger.debug('Finished starting Tor.', timestamp=True)

View File

@ -65,36 +65,7 @@ class Onionr:
# Load global configuration data
data_exists = os.path.exists(self.dataDir)
if not data_exists:
os.mkdir(self.dataDir)
if os.path.exists('static-data/default_config.json'):
config.set_config(json.loads(open('static-data/default_config.json').read())) # this is the default config, it will be overwritten if a config file already exists. Else, it saves it
else:
# the default config file doesn't exist, try hardcoded config
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': self.dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
if not data_exists:
config.save()
config.reload() # this will read the configuration file into memory
settings = 0b000
if config.get('log.console.color', True):
settings = settings | logger.USE_ANSI
if config.get('log.console.output', True):
settings = settings | logger.OUTPUT_TO_CONSOLE
if config.get('log.file.output', True):
settings = settings | logger.OUTPUT_TO_FILE
logger.set_file(config.get('log.file.path', '/tmp/onionr.log').replace('data/', self.dataDir))
logger.set_settings(settings)
if str(config.get('general.dev_mode', True)).lower() == 'true':
self._developmentMode = True
logger.set_level(logger.LEVEL_DEBUG)
else:
self._developmentMode = False
logger.set_level(logger.LEVEL_INFO)
data_exists = Onionr.setupConfig(self.dataDir, self = self)
self.onionrCore = core.Core()
self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore)
@ -222,14 +193,18 @@ class Onionr:
'help': 'Displays this Onionr help menu',
'version': 'Displays the Onionr version',
'config': 'Configures something and adds it to the file',
'start': 'Starts the Onionr daemon',
'stop': 'Stops the Onionr daemon',
'stats': 'Displays node statistics',
'get-password': 'Displays the web password',
'details': 'Displays the web password, public key, and human readable public key',
'enable-plugin': 'Enables and starts a plugin',
'disable-plugin': 'Disables and stops a plugin',
'reload-plugin': 'Reloads a plugin',
'create-plugin': 'Creates directory structure for a plugin',
'add-peer': 'Adds a peer to database',
'list-peers': 'Displays a list of peers',
'add-file': 'Create an Onionr block from a file',
@ -357,7 +332,7 @@ class Onionr:
return config.get('client.hmac')
def printWebPassword(self):
print(self.getWebPassword())
logger.info(self.getWebPassword(), sensitive = True)
def getHelp(self):
return self.cmdhelp
@ -410,16 +385,16 @@ class Onionr:
THIS SECTION DEFINES THE COMMANDS
'''
def version(self, verbosity=5):
def version(self, verbosity = 5, function = logger.info):
'''
Displays the Onionr version
'''
logger.info('Onionr %s (%s) - API v%s' % (ONIONR_VERSION, platform.machine(), API_VERSION))
function('Onionr v%s (%s) (API v%s)' % (ONIONR_VERSION, platform.machine(), API_VERSION))
if verbosity >= 1:
logger.info(ONIONR_TAGLINE)
function(ONIONR_TAGLINE)
if verbosity >= 2:
logger.info('Running on %s %s' % (platform.platform(), platform.release()))
function('Running on %s %s' % (platform.platform(), platform.release()))
return
@ -635,35 +610,47 @@ class Onionr:
logger.debug('Runcheck file found on daemon start, deleting in advance.')
os.remove('data/.runcheck')
apiThread = Thread(target=api.API, args=(self.debug,API_VERSION))
apiThread = Thread(target = api.API, args = (self.debug, API_VERSION))
apiThread.start()
try:
time.sleep(3)
except KeyboardInterrupt:
logger.info('Got keyboard interrupt')
logger.debug('Got keyboard interrupt, shutting down...')
time.sleep(1)
self.onionrUtils.localCommand('shutdown')
else:
if apiThread.isAlive():
# configure logger and stuff
Onionr.setupConfig('data/', self = self)
if self._developmentMode:
logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)', timestamp = False)
net = NetController(config.get('client.port', 59496))
logger.info('Tor is starting...')
logger.debug('Tor is starting...')
if not net.startTor():
sys.exit(1)
logger.info('Started .onion service: ' + logger.colors.underline + net.myID)
logger.info('Our Public key: ' + self.onionrCore._crypto.pubKey)
logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID))
logger.debug('Using public key: %s' % (logger.colors.underline + self.onionrCore._crypto.pubKey))
time.sleep(1)
#TODO make runable on windows
communicatorProc = subprocess.Popen([communicatorDaemon, "run", str(net.socksPort)])
# Print nice header thing :)
# TODO: make runable on windows
communicatorProc = subprocess.Popen([communicatorDaemon, 'run', str(net.socksPort)])
# print nice header thing :)
if config.get('general.display_header', True):
self.header()
logger.debug('Started communicator')
# print out debug info
self.version(verbosity = 5, function = logger.debug)
logger.debug('Python version %s' % platform.python_version())
logger.debug('Started communicator.')
events.event('daemon_start', onionr = self)
try:
while True:
time.sleep(5)
# Break if communicator process ends, so we don't have left over processes
if communicatorProc.poll() is not None:
break
@ -810,7 +797,7 @@ class Onionr:
except IndexError:
logger.error("Syntax %s %s" % (sys.argv[0], '/path/to/filename <blockhash>'))
else:
print(fileName)
logger.info(fileName)
contents = None
if os.path.exists(fileName):
logger.error("File already exists")
@ -842,17 +829,83 @@ class Onionr:
else:
logger.error('%s add-file <filename>' % sys.argv[0], timestamp = False)
def setupConfig(dataDir, self = None):
data_exists = os.path.exists(dataDir)
if not data_exists:
os.mkdir(dataDir)
if os.path.exists('static-data/default_config.json'):
config.set_config(json.loads(open('static-data/default_config.json').read())) # this is the default config, it will be overwritten if a config file already exists. Else, it saves it
else:
# the default config file doesn't exist, try hardcoded config
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
if not data_exists:
config.save()
config.reload() # this will read the configuration file into memory
settings = 0b000
if config.get('log.console.color', True):
settings = settings | logger.USE_ANSI
if config.get('log.console.output', True):
settings = settings | logger.OUTPUT_TO_CONSOLE
if config.get('log.file.output', True):
settings = settings | logger.OUTPUT_TO_FILE
logger.set_file(config.get('log.file.path', '/tmp/onionr.log').replace('data/', dataDir))
logger.set_settings(settings)
if not self is None:
if str(config.get('general.dev_mode', True)).lower() == 'true':
self._developmentMode = True
logger.set_level(logger.LEVEL_DEBUG)
else:
self._developmentMode = False
logger.set_level(logger.LEVEL_INFO)
verbosity = str(config.get('log.verbosity', 'default')).lower().strip()
if not verbosity in ['default', 'null', 'none', 'nil']:
map = {
str(logger.LEVEL_DEBUG) : logger.LEVEL_DEBUG,
'verbose' : logger.LEVEL_DEBUG,
'debug' : logger.LEVEL_DEBUG,
str(logger.LEVEL_INFO) : logger.LEVEL_INFO,
'info' : logger.LEVEL_INFO,
'information' : logger.LEVEL_INFO,
str(logger.LEVEL_WARN) : logger.LEVEL_WARN,
'warn' : logger.LEVEL_WARN,
'warning' : logger.LEVEL_WARN,
'warnings' : logger.LEVEL_WARN,
str(logger.LEVEL_ERROR) : logger.LEVEL_ERROR,
'err' : logger.LEVEL_ERROR,
'error' : logger.LEVEL_ERROR,
'errors' : logger.LEVEL_ERROR,
str(logger.LEVEL_FATAL) : logger.LEVEL_FATAL,
'fatal' : logger.LEVEL_FATAL,
str(logger.LEVEL_IMPORTANT) : logger.LEVEL_IMPORTANT,
'silent' : logger.LEVEL_IMPORTANT,
'quiet' : logger.LEVEL_IMPORTANT,
'important' : logger.LEVEL_IMPORTANT
}
if verbosity in map:
logger.set_level(map[verbosity])
else:
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
return data_exists
def openUI(self):
url = 'http://127.0.0.1:%s/ui/index.html?timingToken=%s' % (config.get('client.port', 59496), self.onionrUtils.getTimeBypassToken())
print('Opening %s ...' % url)
logger.info('Opening %s ...' % url)
webbrowser.open(url, new = 1, autoraise = True)
def header(self, message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'):
if os.path.exists('static-data/header.txt'):
if os.path.exists('static-data/header.txt') and logger.get_level() <= logger.LEVEL_INFO:
with open('static-data/header.txt', 'rb') as file:
# only to stdout, not file or log or anything
sys.stderr.write(file.read().decode().replace('P', logger.colors.fg.pink).replace('W', logger.colors.reset + logger.colors.bold).replace('G', logger.colors.fg.green).replace('\n', logger.colors.reset + '\n').replace('B', logger.colors.bold).replace('V', ONIONR_VERSION))
sys.stderr.write(file.read().decode().replace('P', logger.colors.fg.pink).replace('W', logger.colors.reset + logger.colors.bold).replace('G', logger.colors.fg.green).replace('\n', logger.colors.reset + '\n').replace('B', logger.colors.bold).replace('A', '%s' % API_VERSION).replace('V', ONIONR_VERSION))
logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
if __name__ == "__main__":

View File

@ -46,4 +46,4 @@ class OnionrChat:
self.communicator.socketClient.sendData(peer, "lol")
except:
pass
time.sleep(2)
time.sleep(2)

View File

@ -140,3 +140,23 @@ class DaemonTools:
return True
return False
def humanReadableTime(self, seconds):
build = ''
units = {
'year' : 31557600,
'month' : (31557600 / 12),
'day' : 86400,
'hour' : 3600,
'minute' : 60,
'second' : 1
}
for unit in units:
amnt_unit = int(seconds / units[unit])
if amnt_unit >= 1:
seconds -= amnt_unit * units[unit]
build += '%s %s' % (amnt_unit, unit) + ('s' if amnt_unit != 1 else '') + ' '
return build.strip()

View File

@ -77,7 +77,7 @@ def enable(name, onionr = None, start_event = True):
else:
enabled_plugins.append(name)
config.set('plugins.enabled', enabled_plugins, True)
if start_event is True:
start(name)
return True
@ -234,7 +234,7 @@ def check():
config.reload()
if not config.is_set('plugins'):
logger.debug('Generating plugin config data...')
logger.debug('Generating plugin configuration data...')
config.set('plugins', {'enabled': []}, True)
if not os.path.exists(os.path.dirname(get_plugins_folder())):

View File

@ -72,7 +72,7 @@ class OnionrSocketServer:
self._core.socketServerResponseData[myPeer] = ''
return retData
def socketStarter(self):
while not self._core.killSockets:
try:
@ -87,14 +87,14 @@ class OnionrSocketServer:
def detectShutdown(self):
while not self._core.killSockets:
time.sleep(5)
logger.info('Killing socket server')
logger.debug('Killing socket server...')
self.http_server.stop()
def addSocket(self, peer, reason=''):
bindPort = 1337
assert len(reason) <= 12
with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller:
controller.authenticate(config.get('tor.controlpassword'))
@ -106,7 +106,7 @@ class OnionrSocketServer:
self._core.insertBlock(str(uuid.uuid4()), header='socket', sign=True, encryptType='asym', asymPeer=peer, meta={'reason': reason, 'address': socket.service_id + '.onion'})
self._core.socketReasons[peer] = reason
return
class OnionrSocketClient:
def __init__(self, coreInst):
self.sockets = {} # pubkey: tor address
@ -158,7 +158,7 @@ class OnionrSocketClient:
postData = {'data': data}
self.connPool[peer] = {'date': self._core._utils.getEpoch(), 'data': self._core._utils.doPostRequest('http://' + address + '/dc/', data=postData)}
time.sleep(2)
def getResponse(self, peer):
retData = ''
try:
@ -166,6 +166,6 @@ class OnionrSocketClient:
except KeyError:
pass
return
def sendData(self, peer, data):
self.sendData[peer] = data
self.sendData[peer] = data

View File

@ -527,7 +527,7 @@ class OnionrUtils:
while True:
time.sleep(interval)
if not os.path.isfile(runcheck_file):
return True
elif time.time() - starttime >= timeout:
@ -622,12 +622,14 @@ class OnionrUtils:
else:
return
headers = {'user-agent': 'PyOnionr'}
response_headers = dict()
try:
proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)}
r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30))
# Check server is using same API version as us
try:
if r.headers['api'] != str(API_VERSION):
response_headers = r.headers
if r.headers['X-API'] != str(API_VERSION):
raise onionrexceptions.InvalidAPIVersion
except KeyError:
raise onionrexceptions.InvalidAPIVersion
@ -635,9 +637,12 @@ class OnionrUtils:
except KeyboardInterrupt:
raise KeyboardInterrupt
except ValueError as e:
logger.debug('Failed to make request', error = e)
logger.debug('Failed to make GET request to %s' % url, error = e, sensitive = True)
except onionrexceptions.InvalidAPIVersion:
logger.debug("Node is using different API version :(")
if 'X-API' in response_headers:
logger.debug('Using API version %s. Cannot communicate with node\'s API version of %s.' % (API_VERSION, response_headers['X-API']))
else:
logger.debug('Using API version %s. API version was not sent with the request.' % API_VERSION)
except requests.exceptions.RequestException as e:
if not 'ConnectTimeoutError' in str(e) and not 'Request rejected or failed' in str(e):
logger.debug('Error: %s' % str(e))
@ -656,12 +661,12 @@ class OnionrUtils:
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)
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('Could not get NIST beacon value')
logger.warn('Failed to get the NIST beacon value.')
else:
self.powSalt = retData
return retData

View File

@ -38,13 +38,12 @@ class OnionrCLIUI:
pass
def refresh(self):
for i in range(100):
print('')
print('\n' * 80 + logger.colors.reset)
def start(self):
'''Main CLI UI interface menu'''
showMenu = True
isOnline = "No"
isOnline = 'No'
firstRun = True
choice = ''
@ -53,7 +52,7 @@ class OnionrCLIUI:
while showMenu:
if firstRun:
logger.info("please wait while Onionr starts...")
logger.info('Please wait while Onionr starts...'')
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
time.sleep(30)
firstRun = False
@ -63,9 +62,8 @@ class OnionrCLIUI:
else:
isOnline = "No"
print('''
Daemon Running: ''' + isOnline + '''
logger.info('''Daemon Running: ''' + isOnline + '''
1. Flow (Anonymous public chat, use at your own risk)
2. Mail (Secure email-like service)
3. File Sharing
@ -83,7 +81,7 @@ Daemon Running: ''' + isOnline + '''
elif choice in ("2", "mail"):
self.subCommand("mail")
elif choice in ("3", "file sharing", "file"):
print("Not supported yet")
logger.warn("Not supported yet")
elif choice in ("4", "user settings", "settings"):
try:
self.setName()
@ -91,21 +89,21 @@ Daemon Running: ''' + isOnline + '''
pass
elif choice in ("5", "daemon"):
if isOnline == "Yes":
print("Onionr daemon will shutdown...")
logger.info("Onionr daemon will shutdown...")
self.myCore.daemonQueueAdd('shutdown')
try:
daemon.kill()
except UnboundLocalError:
pass
else:
print("Starting Daemon...")
logger.info("Starting Daemon...")
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
elif choice in ("6", "quit"):
showMenu = False
elif choice == "":
pass
else:
print("Invalid choice")
logger.error("Invalid choice")
return
def setName(self):

View File

@ -71,7 +71,7 @@ class PlainEncryption:
plaintext = data
encrypted = self.api.get_core()._crypto.pubKeyEncrypt(plaintext, pubkey, anonymous=True, encodedData=True)
encrypted = self.api.get_core()._utils.bytesToStr(encrypted)
print('ONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,))
logger.info('Encrypted Message: \n\nONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,))
def decrypt(self):
plaintext = ""
data = ""
@ -89,10 +89,10 @@ class PlainEncryption:
myPub = self.api.get_core()._crypto.pubKey
decrypted = self.api.get_core()._crypto.pubKeyDecrypt(encrypted, privkey=self.api.get_core()._crypto.privKey, anonymous=True, encodedData=True)
if decrypted == False:
print("Decryption failed")
logger.error("Decryption failed")
else:
data = json.loads(decrypted)
print(data['data'])
logger.info('Decrypted Message: \n\n%s' % data['data'])
try:
logger.info("Signing public key: %s" % (data['signer'],))
assert self.api.get_core()._crypto.edVerify(data['data'], data['signer'], data['sig']) != False
@ -101,7 +101,7 @@ class PlainEncryption:
else:
logger.info("Message has good signature.")
return
def on_init(api, data = None):
'''
@ -114,4 +114,4 @@ def on_init(api, data = None):
encrypt = PlainEncryption(pluginapi)
api.commands.register(['encrypt'], encrypt.encrypt)
api.commands.register(['decrypt'], encrypt.decrypt)
return
return

View File

@ -132,10 +132,10 @@ def createRepository(plugins):
contents = {'plugins' : plugins, 'author' : getpass.getuser(), 'compiled-by' : plugin_name}
block = Block(core = pluginapi.get_core())
block.setType('repository')
block.setContent(json.dumps(contents))
return block.save(True)
def check():
@ -217,7 +217,7 @@ def pluginToBlock(plugin, import_block = True):
info = ''
with open(directory + 'info.json').read() as file:
info = json.loads(file.read())
if 'author' in info:
author = info['author']
if 'description' in info:
@ -228,10 +228,10 @@ def pluginToBlock(plugin, import_block = True):
metadata = {'author' : author, 'date' : str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')), 'name' : plugin, 'info' : info, 'compiled-by' : plugin_name, 'content' : data.decode('utf-8'), 'description' : description}
block = Block(core = pluginapi.get_core())
block.setType('plugin')
block.setContent(json.dumps(metadata))
hash = block.save(True)
# hash = pluginapi.get_core().insertBlock(, header = 'plugin', sign = True)
@ -390,12 +390,12 @@ def commandInstallPlugin():
except Exception as e:
logger.warn('Failed to lookup plugin in repositories.', timestamp = False)
logger.error('asdf', error = e, timestamp = False)
return True
if pkobh is None:
logger.error('No key for this plugin found in keystore or repositories, please specify.', timestamp = False)
return True
valid_hash = pluginapi.get_utils().validateHash(pkobh)
@ -552,49 +552,48 @@ def commandPublishPlugin():
logger.error('Plugin %s does not exist.' % pluginname, timestamp = False)
else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>')
def commandCreateRepository():
if len(sys.argv) >= 3:
check()
plugins = list()
script = sys.argv[0]
del sys.argv[:2]
success = True
for pluginname in sys.argv:
distributor = None
if ':' in pluginname:
split = pluginname.split(':')
pluginname = split[0]
distributor = split[1]
pluginname = sanitize(pluginname)
if distributor is None:
distributor = getKey(pluginname)
if distributor is None:
logger.error('No distributor key was found for the plugin %s.' % pluginname, timestamp = False)
success = False
plugins.append([pluginname, distributor])
if not success:
logger.error('Please correct the above errors, then recreate the repository.')
return True
blockhash = createRepository(plugins)
print(blockhash)
if not blockhash is None:
logger.info('Successfully created repository. Execute the following command to add the repository:\n ' + logger.colors.underline + '%s --add-repository %s' % (script, blockhash))
else:
logger.error('Failed to create repository, an unknown error occurred.')
else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' [plugins...]')
return True
# event listeners
def on_init(api, data = None):

View File

@ -66,7 +66,7 @@ class OnionrMail:
self.sentboxList = []
self.sentMessages = {}
return
def inbox(self):
blockCount = 0
pmBlockMap = {}
@ -87,7 +87,7 @@ class OnionrMail:
continue
blockCount += 1
pmBlockMap[blockCount] = blockHash
block = pmBlocks[blockHash]
senderKey = block.signer
try:
@ -102,7 +102,7 @@ class OnionrMail:
displayList.append('%s. %s - %s: %s' % (blockCount, blockDate, senderDisplay[:12], blockHash))
#displayList.reverse()
for i in displayList:
print(i)
logger.info(i)
try:
choice = logger.readline('Enter a block number, -r to refresh, or -q to stop: ').strip().lower()
except (EOFError, KeyboardInterrupt):
@ -129,16 +129,16 @@ class OnionrMail:
else:
cancel = ''
readBlock.verifySig()
print('Message recieved from %s' % (self.myCore._utils.bytesToStr(readBlock.signer,)))
print('Valid signature:', readBlock.validSig)
logger.info('Message recieved from %s' % (self.myCore._utils.bytesToStr(readBlock.signer,)))
logger.info('Valid signature: %s' % readBlock.validSig)
if not readBlock.validSig:
logger.warn('This message has an INVALID signature. ANYONE could have sent this message.')
cancel = logger.readline('Press enter to continue to message, or -q to not open the message (recommended).')
if cancel != '-q':
print(draw_border(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode().strip())))
input("Press enter to continue")
logger.readline("Press enter to continue")
return
def sentbox(self):
'''
Display sent mail messages
@ -146,7 +146,7 @@ class OnionrMail:
entering = True
while entering:
self.getSentList()
print('Enter block number or -q to return')
logger.info('Enter block number or -q to return')
try:
choice = input('>')
except (EOFError, KeyboardInterrupt) as e:
@ -158,21 +158,21 @@ class OnionrMail:
try:
self.sentboxList[int(choice) - 1]
except IndexError:
print('Invalid block')
logger.warn('Invalid block.')
else:
logger.info('Sent to: ' + self.sentMessages[self.sentboxList[int(choice) - 1]][1])
# Print ansi escaped sent message
print(self.myCore._utils.escapeAnsi(self.sentMessages[self.sentboxList[int(choice) - 1]][0]))
logger.info(self.myCore._utils.escapeAnsi(self.sentMessages[self.sentboxList[int(choice) - 1]][0]))
input('Press enter to continue...')
return
def getSentList(self):
count = 1
for i in self.sentboxTools.listSent():
self.sentboxList.append(i['hash'])
self.sentMessages[i['hash']] = (i['message'], i['peer'])
print('%s. %s - %s - %s' % (count, i['hash'], i['peer'][:12], i['date']))
logger.info('%s. %s - %s - %s' % (count, i['hash'], i['peer'][:12], i['date']))
count += 1
def draftMessage(self):
@ -198,7 +198,7 @@ class OnionrMail:
# if -q or ctrl-c/d, exit function here, otherwise we successfully got the public key
return
print('Enter your message, stop by entering -q on a new line.')
logger.info('Enter your message, stop by entering -q on a new line.')
while newLine != '-q':
try:
newLine = input()
@ -209,7 +209,7 @@ class OnionrMail:
newLine += '\n'
message += newLine
print('Inserting encrypted message as Onionr block....')
logger.info('Inserting encrypted message as Onionr block....')
blockID = self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip, sign=True)
self.sentboxTools.addToSent(blockID, recip, message)
@ -217,7 +217,7 @@ class OnionrMail:
choice = ''
while True:
print(self.strings.programTag + '\n\nOur ID: ' + self.myCore._crypto.pubKey + self.strings.mainMenu.title()) # print out main menu
logger.info(self.strings.programTag + '\n\nOur ID: ' + self.myCore._crypto.pubKey + self.strings.mainMenu.title()) # print out main menu
try:
choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower().strip()
@ -251,4 +251,4 @@ def on_init(api, data = None):
mail = OnionrMail(pluginapi)
api.commands.register(['mail'], mail.menu)
api.commands.register_help('mail', 'Interact with OnionrMail')
return
return

View File

@ -2,6 +2,7 @@
"general" : {
"dev_mode" : true,
"display_header" : true,
"minimum_block_pow": 5,
"minimum_send_pow": 5,
@ -34,7 +35,20 @@
"client" : {
},
"log": {
"plugins" : {
"enabled" : {
},
"disabled" : {
}
},
"log" : {
"verbosity" : "default",
"file": {
"output": false,
"path": "data/output.log"

View File

@ -3,9 +3,9 @@ P G'
P G''
P G'' '
P G''''''
P :G;'''''P:
P ::G;'''P::
P :::G;;P:::
P :G''''''P:
P ::G''''P::
P :::G''P:::
P ::::::::
P ::::::::::::
P :::::::::::::::
@ -20,6 +20,7 @@ P :::: ::::: ::::: ::: W :::: :: :: :: ::::: :: :: :: ::
P :::: :::::: :::::: ::::
P :::: :::::::::::: :::: GvPBV
P ::::: :::::::: ::::
P ::::: ::::::
P ::::: :::::
P ::::::::::::::::
P :::::::