See details

- Completes support for repositories
  - `./RUN-LINUX.sh create-repository [plugins...]`
  - `./RUN-LINUX.sh add-repository <block hash>`
  - `./RUN-LINUX.sh remove-repository <block hash>`
- Fixes several misc bugs
- Refactors code
  - Some messy code was rewritten
  - Variables renamed
  - Migrated old block api (insertBlock) to new Block API (onionrblockapi)
  - Kept to standards
  - Made code more reusable in `onionrproofs.py`
- Improves logging messages
  - Added error output for some features missing it
  - Capitalized sentences
  - Added punctuation where it is missing
  - Switched `logger.info` and `logger.debug` in a few places, where it is logical
  - Removed or added timestamps depending on the circumstance
- Added a few misc features
  - Added command aliases for `add-file` and `import-blocks`
  - Improved statistics menu
    - Displays `Known Block Count`
    - Calculates and displays `Percent Blocks Signed`
master
Arinerron 2018-05-31 21:25:28 -07:00
parent a232e663a7
commit 8846dcc2c6
No known key found for this signature in database
GPG Key ID: 99383627861C62F0
7 changed files with 184 additions and 86 deletions

View File

@ -70,7 +70,7 @@ class API:
self.clientToken = config.get('client')['client_hmac'] self.clientToken = config.get('client')['client_hmac']
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
self.i2pEnabled = config.get('i2p')['host'] self.i2pEnabled = config.get('i2p', {'host' : False})['host']
self.mimeType = 'text/plain' self.mimeType = 'text/plain'
@ -85,9 +85,9 @@ class API:
self.host = '127.' + str(hostNums[0]) + '.' + str(hostNums[1]) + '.' + str(hostNums[2]) self.host = '127.' + str(hostNums[0]) + '.' + str(hostNums[1]) + '.' + str(hostNums[2])
else: else:
self.host = '127.0.0.1' self.host = '127.0.0.1'
hostFile = open('data/host.txt', 'w')
hostFile.write(self.host) with open('data/host.txt', 'w') as file:
hostFile.close() file.write(self.host)
@app.before_request @app.before_request
def beforeReq(): def beforeReq():
@ -259,7 +259,7 @@ class API:
return resp return resp
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true": if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...', timestamp=True) logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...', timestamp=False)
try: try:
self.http_server = WSGIServer((self.host, bindPort), app) self.http_server = WSGIServer((self.host, bindPort), app)

View File

@ -123,16 +123,16 @@ class OnionrCommunicate:
announceAttempts = 3 announceAttempts = 3
announceAttemptCount = 0 announceAttemptCount = 0
announceVal = False announceVal = False
logger.info('Announcing node to ' + command[1], timestamp=True) logger.info('Announcing node to %s...' % command[1], timestamp=True)
while not announceVal: while not announceVal:
announceAttemptCount += 1 announceAttemptCount += 1
announceVal = self.performGet('announce', command[1], data=self._core.hsAdder.replace('\n', ''), skipHighFailureAddress=True) announceVal = self.performGet('announce', command[1], data=self._core.hsAdder.replace('\n', ''), skipHighFailureAddress=True)
logger.info(announceVal) # logger.info(announceVal)
if announceAttemptCount >= announceAttempts: if announceAttemptCount >= announceAttempts:
logger.warn('Unable to announce to ' + command[1]) logger.warn('Unable to announce to %s' % command[1])
break break
elif command[0] == 'runCheck': elif command[0] == 'runCheck':
logger.info('Status check; looks good.') logger.debug('Status check; looks good.')
open('data/.runcheck', 'w+').close() open('data/.runcheck', 'w+').close()
elif command[0] == 'kex': elif command[0] == 'kex':
self.pexCount = pexTimer - 1 self.pexCount = pexTimer - 1
@ -188,13 +188,17 @@ class OnionrCommunicate:
id_peer_cache = {} id_peer_cache = {}
def registerTimer(self, timerName, rate, timerFunc=None): def registerTimer(self, timerName, rate, timerFunc=None):
'''Register a communicator timer''' '''
Register a communicator timer
'''
self.communicatorTimers[timerName] = rate self.communicatorTimers[timerName] = rate
self.communicatorTimerCounts[timerName] = 0 self.communicatorTimerCounts[timerName] = 0
self.communicatorTimerFuncs[timerName] = timerFunc self.communicatorTimerFuncs[timerName] = timerFunc
def timerTick(self): def timerTick(self):
'''Increments timers "ticks" and calls funcs if applicable''' '''
Increments timers "ticks" and calls funcs if applicable
'''
tName = '' tName = ''
for i in self.communicatorTimers.items(): for i in self.communicatorTimers.items():
tName = i[0] tName = i[0]
@ -617,7 +621,9 @@ class OnionrCommunicate:
return return
def removeBlockFromProcessingList(self, block): def removeBlockFromProcessingList(self, block):
'''Remove a block from the processing list''' '''
Remove a block from the processing list
'''
try: try:
self.blocksProcessing.remove(block) self.blocksProcessing.remove(block)
except ValueError: except ValueError:
@ -724,7 +730,8 @@ class OnionrCommunicate:
r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30)) r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30))
retData = r.text retData = r.text
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
logger.debug("%s failed with peer %s" % (action, peer)) logger.debug('%s failed with peer %s' % (action, peer))
logger.debug('Error: %s' % str(e))
retData = False retData = False
if not retData: if not retData:

View File

@ -103,7 +103,7 @@ DataDirectory data/tordata/
logger.fatal("Got keyboard interrupt") logger.fatal("Got keyboard interrupt")
return False return False
logger.info('Finished starting Tor', timestamp=True) logger.debug('Finished starting Tor.', timestamp=True)
self.readyState = True self.readyState = True
myID = open('data/hs/hostname', 'r') myID = open('data/hs/hostname', 'r')

View File

@ -31,6 +31,7 @@ import api, core, config, logger, onionrplugins as plugins, onionrevents as even
import onionrutils import onionrutils
from onionrutils import OnionrUtils from onionrutils import OnionrUtils
from netcontroller import NetController from netcontroller import NetController
from onionrblockapi import Block
try: try:
from urllib3.contrib.socks import SOCKSProxyManager from urllib3.contrib.socks import SOCKSProxyManager
@ -192,8 +193,11 @@ class Onionr:
'add-addr': self.addAddress, 'add-addr': self.addAddress,
'addaddr': self.addAddress, 'addaddr': self.addAddress,
'addaddress': self.addAddress, 'addaddress': self.addAddress,
'add-file': self.addFile,
'addfile': self.addFile, 'addfile': self.addFile,
'import-blocks': self.onionrUtils.importNewBlocks,
'importblocks': self.onionrUtils.importNewBlocks, 'importblocks': self.onionrUtils.importNewBlocks,
'introduce': self.onionrCore.introduceNode, 'introduce': self.onionrCore.introduceNode,
@ -216,8 +220,8 @@ class Onionr:
'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', 'add-file': 'Create an Onionr block from a file',
'importblocks': 'import blocks from the disk (Onionr is transport-agnostic!)', 'import-blocks': 'import blocks from the disk (Onionr is transport-agnostic!)',
'introduce': 'Introduce your node to the public Onionr network', 'introduce': 'Introduce your node to the public Onionr network',
} }
@ -391,12 +395,11 @@ class Onionr:
except KeyboardInterrupt: except KeyboardInterrupt:
return return
#addedHash = self.onionrCore.setData(messageToAdd) addedHash = Block('txt', messageToAdd).save()
addedHash = self.onionrCore.insertBlock(messageToAdd, header='txt') if addedHash != None:
#self.onionrCore.addToBlockDB(addedHash, selfInsert=True)
#self.onionrCore.setBlockType(addedHash, 'txt')
if addedHash != '':
logger.info("Message inserted as as block %s" % addedHash) logger.info("Message inserted as as block %s" % addedHash)
else:
logger.error('Failed to insert block.', timestamp = False)
return return
def getPMs(self): def getPMs(self):
@ -520,12 +523,12 @@ class Onionr:
if not os.environ.get("WERKZEUG_RUN_MAIN") == "true": if not os.environ.get("WERKZEUG_RUN_MAIN") == "true":
if self._developmentMode: if self._developmentMode:
logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)') logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)', timestamp = False)
net = NetController(config.get('client')['port']) net = NetController(config.get('client')['port'])
logger.info('Tor is starting...') logger.info('Tor is starting...')
if not net.startTor(): if not net.startTor():
sys.exit(1) sys.exit(1)
logger.info('Started Tor .onion service: ' + logger.colors.underline + net.myID) logger.info('Started .onion service: ' + logger.colors.underline + net.myID)
logger.info('Our Public key: ' + self.onionrCore._crypto.pubKey) logger.info('Our Public key: ' + self.onionrCore._crypto.pubKey)
time.sleep(1) time.sleep(1)
subprocess.Popen(["./communicator.py", "run", str(net.socksPort)]) subprocess.Popen(["./communicator.py", "run", str(net.socksPort)])
@ -562,6 +565,9 @@ class Onionr:
try: try:
# define stats messages here # define stats messages here
totalBlocks = len(Block.getBlocks())
signedBlocks = len(Block.getBlocks(signed = True))
messages = { messages = {
# info about local client # info about local client
'Onionr Daemon Status' : ((logger.colors.fg.green + 'Online') if self.onionrUtils.isCommunicatorRunning(timeout = 2) else logger.colors.fg.red + 'Offline'), 'Onionr Daemon Status' : ((logger.colors.fg.green + 'Online') if self.onionrUtils.isCommunicatorRunning(timeout = 2) else logger.colors.fg.red + 'Offline'),
@ -577,7 +583,9 @@ class Onionr:
# count stats # count stats
'div2' : True, 'div2' : True,
'Known Peers Count' : str(len(self.onionrCore.listPeers()) - 1), 'Known Peers Count' : str(len(self.onionrCore.listPeers()) - 1),
'Enabled Plugins Count' : str(len(config.get('plugins')['enabled'])) + ' / ' + str(len(os.listdir('data/plugins/'))) 'Enabled Plugins Count' : str(len(config.get('plugins')['enabled'])) + ' / ' + str(len(os.listdir('data/plugins/'))),
'Known Blocks Count' : str(totalBlocks),
'Percent Blocks Signed' : str(round(100 * signedBlocks / totalBlocks, 2)) + '%'
} }
# color configuration # color configuration
@ -639,18 +647,30 @@ class Onionr:
return None return None
def addFile(self): def addFile(self):
'''command to add a file to the onionr network''' '''
if len(sys.argv) >= 2: Adds a file to the onionr network
newFile = sys.argv[2] '''
logger.info('Attempting to add file...')
try: if len(sys.argv) >= 3:
with open(newFile, 'rb') as new: filename = sys.argv[2]
new = new.read() contents = None
except FileNotFoundError:
if not os.path.exists(filename):
logger.warn('That file does not exist. Improper path?') logger.warn('That file does not exist. Improper path?')
try:
with open(filename, 'rb') as file:
contents = file.read().decode()
except:
pass
if not contents is None:
blockhash = Block('bin', contents).save()
logger.info('File %s saved in block %s.' % (filename, blockhash))
else: else:
logger.debug(new) logger.error('Failed to save file in block.', timestamp = False)
logger.info(self.onionrCore.insertBlock(new, header='bin')) else:
logger.error('%s add-file <filename>' % sys.argv[0], timestamp = False)
Onionr() Onionr()

View File

@ -77,7 +77,7 @@ def enable(name, onionr = None, start_event = True):
else: else:
return False return False
else: else:
logger.error('Failed to enable plugin \"' + name + '\", disabling plugin.') logger.error('Failed to enable plugin \"%s\", disabling plugin.' % name)
disable(name) disable(name)
return False return False
@ -121,9 +121,9 @@ def start(name, onionr = None):
return plugin return plugin
except: except:
logger.error('Failed to start module \"' + name + '\".') logger.error('Failed to start module \"%s\".' % name)
else: else:
logger.error('Failed to start nonexistant module \"' + name + '\".') logger.error('Failed to start nonexistant module \"%s\".' % name)
return None return None
@ -145,9 +145,9 @@ def stop(name, onionr = None):
return plugin return plugin
except: except:
logger.error('Failed to stop module \"' + name + '\".') logger.error('Failed to stop module \"%s\".' % name)
else: else:
logger.error('Failed to stop nonexistant module \"' + name + '\".') logger.error('Failed to stop nonexistant module \"%s\".' % name)
return None return None

View File

@ -22,7 +22,7 @@ import nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, lo
import core import core
class POW: class POW:
def pow(self, reporting = False): def pow(self, reporting = False, myCore = None):
startTime = math.floor(time.time()) startTime = math.floor(time.time())
self.hashing = True self.hashing = True
self.reporting = reporting self.reporting = reporting
@ -30,7 +30,7 @@ class POW:
answer = '' answer = ''
heartbeat = 200000 heartbeat = 200000
hbCount = 0 hbCount = 0
myCore = core.Core()
while self.hashing: while self.hashing:
rand = nacl.utils.random() rand = nacl.utils.random()
token = nacl.hash.blake2b(rand + self.data).decode() token = nacl.hash.blake2b(rand + self.data).decode()
@ -39,23 +39,22 @@ class POW:
self.hashing = False self.hashing = False
iFound = True iFound = True
break break
else:
logger.debug('POW thread exiting, another thread found result')
if iFound: if iFound:
endTime = math.floor(time.time()) endTime = math.floor(time.time())
if self.reporting: if self.reporting:
logger.info('Found token ' + token, timestamp=True) logger.debug('Found token after %s seconds: %s' % (endTime - startTime, token), timestamp=True)
logger.info('rand value: ' + base64.b64encode(rand).decode()) logger.debug('Random value was: %s' % base64.b64encode(rand).decode())
logger.info('took ' + str(endTime - startTime) + ' seconds', timestamp=True)
self.result = (token, rand) self.result = (token, rand)
def __init__(self, data): def __init__(self, data, threadCount = 5):
self.foundHash = False self.foundHash = False
self.difficulty = 0 self.difficulty = 0
self.data = data self.data = data
self.threadCount = threadCount
dataLen = sys.getsizeof(data) dataLen = sys.getsizeof(data)
self.difficulty = math.floor(dataLen/1000000) self.difficulty = math.floor(dataLen / 1000000)
if self.difficulty <= 2: if self.difficulty <= 2:
self.difficulty = 4 self.difficulty = 4
@ -63,19 +62,19 @@ class POW:
self.data = self.data.encode() self.data = self.data.encode()
except AttributeError: except AttributeError:
pass pass
self.data = nacl.hash.blake2b(self.data) self.data = nacl.hash.blake2b(self.data)
logger.debug('Computing difficulty of ' + str(self.difficulty)) logger.info('Computing POW (difficulty: %s)...' % self.difficulty)
self.mainHash = '0' * 70
self.puzzle = self.mainHash[0:min(self.difficulty, len(self.mainHash))]
myCore = core.Core()
for i in range(max(1, threadCount)):
t = threading.Thread(name = 'thread%s' % i, target = self.pow, args = (True,myCore))
t.start()
self.mainHash = '0000000000000000000000000000000000000000000000000000000000000000'#nacl.hash.blake2b(nacl.utils.random()).decode()
self.puzzle = self.mainHash[0:self.difficulty]
#logger.debug('trying to find ' + str(self.mainHash))
tOne = threading.Thread(name='one', target=self.pow, args=(True,))
tTwo = threading.Thread(name='two', target=self.pow, args=(True,))
tThree = threading.Thread(name='three', target=self.pow, args=(True,))
tOne.start()
tTwo.start()
tThree.start()
return return
def shutdown(self): def shutdown(self):
@ -89,9 +88,11 @@ class POW:
''' '''
Returns the result then sets to false, useful to automatically clear the result Returns the result then sets to false, useful to automatically clear the result
''' '''
try: try:
retVal = self.result retVal = self.result
except AttributeError: except AttributeError:
retVal = False retVal = False
self.result = False self.result = False
return retVal return retVal

View File

@ -34,9 +34,9 @@ def writeKeys():
Serializes and writes the keystore in memory to file Serializes and writes the keystore in memory to file
''' '''
file = open(keys_file, 'w') with open(keys_file, 'w') as file:
file.write(json.dumps(keys_data, indent=4, sort_keys=True)) file.write(json.dumps(keys_data, indent=4, sort_keys=True))
file.close() file.close()
def readKeys(): def readKeys():
''' '''
@ -44,7 +44,8 @@ def readKeys():
''' '''
global keys_data global keys_data
keys_data = json.loads(open(keys_file).read()) with open(keys_file) as file:
keys_data = json.loads(file.read())
return keys_data return keys_data
def getKey(plugin): def getKey(plugin):
@ -106,27 +107,37 @@ def getRepositories():
readKeys() readKeys()
return keys_data['repositories'] return keys_data['repositories']
def addRepository(repositories, data): def addRepository(blockhash, data):
''' '''
Saves the plugin name, to remember that it was installed by the pluginmanager Saves the plugin name, to remember that it was installed by the pluginmanager
''' '''
global keys_data global keys_data
readKeys() readKeys()
keys_data['repositories'][repositories] = data keys_data['repositories'][blockhash] = data
writeKeys() writeKeys()
def removeRepository(repositories): def removeRepository(blockhash):
''' '''
Removes the plugin name from the pluginmanager's records Removes the plugin name from the pluginmanager's records
''' '''
global keys_data global keys_data
readKeys() readKeys()
if plugin in keys_data['repositories']: if blockhash in keys_data['repositories']:
del keys_data['repositories'][repositories] del keys_data['repositories'][blockhash]
writeKeys() writeKeys()
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(): def check():
''' '''
Checks to make sure the keystore file still exists Checks to make sure the keystore file still exists
@ -144,7 +155,7 @@ def sanitize(name):
def blockToPlugin(block): def blockToPlugin(block):
try: try:
block = Block(block) block = Block(block, core = pluginapi.get_core())
blockContent = json.loads(block.getContent()) blockContent = json.loads(block.getContent())
name = sanitize(blockContent['name']) name = sanitize(blockContent['name'])
@ -194,14 +205,19 @@ def pluginToBlock(plugin, import_block = True):
shutil.rmtree(directory + '__pycache__') shutil.rmtree(directory + '__pycache__')
shutil.make_archive(zipfile[:-4], 'zip', directory) shutil.make_archive(zipfile[:-4], 'zip', directory)
data = base64.b64encode(open(zipfile, 'rb').read()) data = ''
with open(zipfile, 'rb') as file:
data = base64.b64encode(file.read())
author = getpass.getuser() author = getpass.getuser()
description = 'Default plugin description' description = 'Default plugin description'
info = {"name" : plugin} info = {"name" : plugin}
try: try:
if os.path.exists(directory + 'info.json'): if os.path.exists(directory + 'info.json'):
info = json.loads(open(directory + 'info.json').read()) info = ''
with open(directory + 'info.json').read() as file:
info = json.loads(file.read())
if 'author' in info: if 'author' in info:
author = info['author'] author = info['author']
if 'description' in info: if 'description' in info:
@ -211,7 +227,13 @@ 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} 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}
hash = pluginapi.get_core().insertBlock(json.dumps(metadata), header = 'plugin', sign = True) 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)
if import_block: if import_block:
pluginapi.get_utils().importNewBlocks() pluginapi.get_utils().importNewBlocks()
@ -226,7 +248,7 @@ def pluginToBlock(plugin, import_block = True):
def installBlock(block): def installBlock(block):
try: try:
block = Block(block) block = Block(block, core = pluginapi.get_core())
blockContent = json.loads(block.getContent()) blockContent = json.loads(block.getContent())
name = sanitize(blockContent['name']) name = sanitize(blockContent['name'])
@ -353,7 +375,8 @@ def commandInstallPlugin():
choice = logger.readline('Select the number of the key to use, from 1 to %s, or press Ctrl+C to cancel:' % (index - 1)) choice = logger.readline('Select the number of the key to use, from 1 to %s, or press Ctrl+C to cancel:' % (index - 1))
try: try:
if int(choice) < index and int(choice) >= 1: choice = int(choice)
if choice <= index and choice >= 1:
distributor = distributors[int(choice)] distributor = distributors[int(choice)]
valid = True valid = True
except KeyboardInterrupt: except KeyboardInterrupt:
@ -368,9 +391,11 @@ def commandInstallPlugin():
logger.warn('Failed to lookup plugin in repositories.', timestamp = False) logger.warn('Failed to lookup plugin in repositories.', timestamp = False)
logger.error('asdf', error = e, timestamp = False) logger.error('asdf', error = e, timestamp = False)
return True
if pkobh is None: if pkobh is None:
logger.error('No key for this plugin found in keystore or repositories, please specify.') logger.error('No key for this plugin found in keystore or repositories, please specify.', timestamp = False)
help()
return True return True
valid_hash = pluginapi.get_utils().validateHash(pkobh) valid_hash = pluginapi.get_utils().validateHash(pkobh)
@ -386,7 +411,7 @@ def commandInstallPlugin():
blockhash = None blockhash = None
if valid_hash and not real_block: if valid_hash and not real_block:
logger.error('Block hash not found. Perhaps it has not been synced yet?') logger.error('Block hash not found. Perhaps it has not been synced yet?', timestamp = False)
logger.debug('Is valid hash, but does not belong to a known block.') logger.debug('Is valid hash, but does not belong to a known block.')
return True return True
@ -396,7 +421,7 @@ def commandInstallPlugin():
installBlock(blockhash) installBlock(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.', timestamp = False)
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)
@ -432,10 +457,11 @@ def commandInstallPlugin():
except Exception as e: except Exception as e:
pass pass
logger.warn('Only continue the installation is you are absolutely certain that you trust the plugin distributor. Public key of plugin distributor: %s' % publickey, timestamp = False) logger.warn('Only continue the installation if you are absolutely certain that you trust the plugin distributor. Public key of plugin distributor: %s' % publickey, timestamp = False)
logger.debug('Most recent block matching parameters is %s' % mostRecentVersionBlock)
installBlock(mostRecentVersionBlock) installBlock(mostRecentVersionBlock)
else: else:
logger.error('Unknown data "%s"; must be public key or block hash.' % str(pkobh)) logger.error('Unknown data "%s"; must be public key or block hash.' % str(pkobh), timestamp = False)
return return
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin> [public key/block hash]') logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin> [public key/block hash]')
@ -463,11 +489,11 @@ def commandAddRepository():
if pluginapi.get_utils().validateHash(blockhash): if pluginapi.get_utils().validateHash(blockhash):
if Block.exists(blockhash): if Block.exists(blockhash):
try: try:
blockContent = json.loads(Block(blockhash).getContent()) blockContent = json.loads(Block(blockhash, core = pluginapi.get_core()).getContent())
pluginslist = dict() pluginslist = dict()
for pluginname, distributor in blockContent['plugins'].items(): for pluginname, distributor in blockContent['plugins']:
if pluginapi.get_utils().validatePubKey(distributor): if pluginapi.get_utils().validatePubKey(distributor):
pluginslist[pluginname] = distributor pluginslist[pluginname] = distributor
@ -477,14 +503,14 @@ def commandAddRepository():
addRepository(blockhash, pluginslist) addRepository(blockhash, pluginslist)
logger.info('Successfully added repository.') logger.info('Successfully added repository.')
else: else:
logger.error('Repository contains no records, not importing.') logger.error('Repository contains no records, not importing.', timestamp = False)
except Exception as e: except Exception as e:
logger.error('Failed to parse block.', error = e) logger.error('Failed to parse block.', error = e)
else: else:
logger.error('Block hash not found. Perhaps it has not been synced yet?') logger.error('Block hash not found. Perhaps it has not been synced yet?', timestamp = False)
logger.debug('Is valid hash, but does not belong to a known block.') logger.debug('Is valid hash, but does not belong to a known block.')
else: else:
logger.error('Unknown data "%s"; must be block hash.' % str(pkobh)) logger.error('Unknown data "%s"; must be block hash.' % str(pkobh), timestamp = False)
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' [block hash]') logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' [block hash]')
@ -500,10 +526,11 @@ def commandRemoveRepository():
if blockhash in getRepositories(): if blockhash in getRepositories():
try: try:
removeRepository(blockhash) removeRepository(blockhash)
logger.info('Successfully removed repository.')
except Exception as e: except Exception as e:
logger.error('Failed to parse block.', error = e) logger.error('Failed to parse block.', error = e)
else: else:
logger.error('Repository has not been imported, nothing to remove.') logger.error('Repository has not been imported, nothing to remove.', timestamp = False)
else: else:
logger.error('Unknown data "%s"; must be block hash.' % str(pkobh)) logger.error('Unknown data "%s"; must be block hash.' % str(pkobh))
else: else:
@ -526,6 +553,48 @@ def commandPublishPlugin():
else: else:
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>') 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 # event listeners
def on_init(api, data = None): def on_init(api, data = None):
@ -540,6 +609,7 @@ def on_init(api, data = None):
api.commands.register(['add-repo', 'add-repository', 'addrepo', 'addrepository', 'repository-add', 'repo-add', 'repoadd', 'addrepository', 'add-plugin-repository', 'add-plugin-repo', 'add-pluginrepo', 'add-pluginrepository', 'addpluginrepo', 'addpluginrepository'], commandAddRepository) api.commands.register(['add-repo', 'add-repository', 'addrepo', 'addrepository', 'repository-add', 'repo-add', 'repoadd', 'addrepository', 'add-plugin-repository', 'add-plugin-repo', 'add-pluginrepo', 'add-pluginrepository', 'addpluginrepo', 'addpluginrepository'], commandAddRepository)
api.commands.register(['remove-repo', 'remove-repository', 'removerepo', 'removerepository', 'repository-remove', 'repo-remove', 'reporemove', 'removerepository', 'remove-plugin-repository', 'remove-plugin-repo', 'remove-pluginrepo', 'remove-pluginrepository', 'removepluginrepo', 'removepluginrepository', 'rm-repo', 'rm-repository', 'rmrepo', 'rmrepository', 'repository-rm', 'repo-rm', 'reporm', 'rmrepository', 'rm-plugin-repository', 'rm-plugin-repo', 'rm-pluginrepo', 'rm-pluginrepository', 'rmpluginrepo', 'rmpluginrepository'], commandRemoveRepository) api.commands.register(['remove-repo', 'remove-repository', 'removerepo', 'removerepository', 'repository-remove', 'repo-remove', 'reporemove', 'removerepository', 'remove-plugin-repository', 'remove-plugin-repo', 'remove-pluginrepo', 'remove-pluginrepository', 'removepluginrepo', 'removepluginrepository', 'rm-repo', 'rm-repository', 'rmrepo', 'rmrepository', 'repository-rm', 'repo-rm', 'reporm', 'rmrepository', 'rm-plugin-repository', 'rm-plugin-repo', 'rm-pluginrepo', 'rm-pluginrepository', 'rmpluginrepo', 'rmpluginrepository'], commandRemoveRepository)
api.commands.register(['publish-plugin', 'plugin-publish', 'publishplugin', 'pluginpublish', 'publish'], commandPublishPlugin) api.commands.register(['publish-plugin', 'plugin-publish', 'publishplugin', 'pluginpublish', 'publish'], commandPublishPlugin)
api.commands.register(['create-repository', 'create-repo', 'createrepo', 'createrepository', 'repocreate'], commandCreateRepository)
# add help menus once the features are actually implemented # add help menus once the features are actually implemented