Various improvements
- Adds a lot more to the pluginmanager - Refactors code - Relocates functionsmaster
parent
adf007bf30
commit
fe4261c4a2
|
@ -565,31 +565,26 @@ class OnionrCommunicate:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not self.verifyPow(blockContent, blockMeta2):
|
if not self._crypto.verifyPow(blockContent, blockMeta2):
|
||||||
logger.warn("%s has invalid or insufficient proof of work token, deleting..." % str(i))
|
logger.warn("%s has invalid or insufficient proof of work token, deleting..." % str(i))
|
||||||
self._core.removeBlock(i)
|
self._core.removeBlock(i)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
|
||||||
blockMetadata['sig']
|
|
||||||
blockMeta2['id']
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
#blockData = json.dumps(blockMetadata['meta']) + blockMetadata[blockMetadata.rfind(b'}') + 1:]
|
if (('sig' in blockMetadata) and ('id' in blockMeta2)):
|
||||||
|
#blockData = json.dumps(blockMetadata['meta']) + blockMetadata[blockMetadata.rfind(b'}') + 1:]
|
||||||
|
|
||||||
creator = self._utils.getPeerByHashId(blockMeta2['id'])
|
creator = self._utils.getPeerByHashId(blockMeta2['id'])
|
||||||
try:
|
try:
|
||||||
creator = creator.decode()
|
creator = creator.decode()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if self._core._crypto.edVerify(blockMetaData['meta'] + blockContent, creator, blockMetadata['sig'], encodedData=True):
|
if self._core._crypto.edVerify(blockMetaData['meta'] + blockContent, creator, blockMetadata['sig'], encodedData=True):
|
||||||
logger.info('%s was signed' % str(i))
|
logger.info('%s was signed' % str(i))
|
||||||
self._core.updateBlockInfo(i, 'sig', 'true')
|
self._core.updateBlockInfo(i, 'sig', 'true')
|
||||||
else:
|
else:
|
||||||
logger.warn('%s has an invalid signature' % str(i))
|
logger.warn('%s has an invalid signature' % str(i))
|
||||||
self._core.updateBlockInfo(i, 'sig', 'false')
|
self._core.updateBlockInfo(i, 'sig', 'false')
|
||||||
try:
|
try:
|
||||||
logger.info('Block type is %s' % str(blockMeta2['type']))
|
logger.info('Block type is %s' % str(blockMeta2['type']))
|
||||||
self._core.updateBlockInfo(i, 'dataType', blockMeta2['type'])
|
self._core.updateBlockInfo(i, 'dataType', blockMeta2['type'])
|
||||||
|
@ -605,12 +600,7 @@ class OnionrCommunicate:
|
||||||
return
|
return
|
||||||
|
|
||||||
def removeBlockFromProcessingList(self, block):
|
def removeBlockFromProcessingList(self, block):
|
||||||
try:
|
return block in blocksProcessing
|
||||||
self.blocksProcessing.remove(block)
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def downloadBlock(self, hash, peerTries=3):
|
def downloadBlock(self, hash, peerTries=3):
|
||||||
'''
|
'''
|
||||||
|
@ -666,41 +656,6 @@ class OnionrCommunicate:
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def verifyPow(self, blockContent, metadata):
|
|
||||||
'''
|
|
||||||
Verifies the proof of work associated with a block
|
|
||||||
'''
|
|
||||||
retData = False
|
|
||||||
try:
|
|
||||||
metadata['powToken']
|
|
||||||
metadata['powHash']
|
|
||||||
token = metadata['powToken']
|
|
||||||
except KeyError:
|
|
||||||
return False
|
|
||||||
dataLen = len(blockContent)
|
|
||||||
|
|
||||||
expectedHash = self._crypto.blake2bHash(base64.b64decode(metadata['powToken']) + self._crypto.blake2bHash(blockContent.encode()))
|
|
||||||
difficulty = 0
|
|
||||||
try:
|
|
||||||
expectedHash = expectedHash.decode()
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
if metadata['powHash'] == expectedHash:
|
|
||||||
difficulty = math.floor(dataLen/1000000)
|
|
||||||
|
|
||||||
mainHash = '0000000000000000000000000000000000000000000000000000000000000000'#nacl.hash.blake2b(nacl.utils.random()).decode()
|
|
||||||
puzzle = mainHash[0:difficulty]
|
|
||||||
|
|
||||||
if metadata['powHash'][0:difficulty] == puzzle:
|
|
||||||
logger.info('Validated block pow')
|
|
||||||
retData = True
|
|
||||||
else:
|
|
||||||
logger.warn("Invalid token (#1)")
|
|
||||||
else:
|
|
||||||
logger.warn('Invalid token (#2): Expected hash %s, got hash %s...' % (metadata['powHash'], expectedHash))
|
|
||||||
|
|
||||||
return retData
|
|
||||||
|
|
||||||
def urlencode(self, data):
|
def urlencode(self, data):
|
||||||
'''
|
'''
|
||||||
URL encodes the data
|
URL encodes the data
|
||||||
|
|
|
@ -277,11 +277,12 @@ class Core:
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def getData(self,hash):
|
def getData(self, hash):
|
||||||
'''
|
'''
|
||||||
Simply return the data associated to a hash
|
Simply return the data associated to a hash
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
|
# logger.debug('Opening %s' % (str(self.blockDataLocation) + str(hash) + '.dat'))
|
||||||
dataFile = open(self.blockDataLocation + hash + '.dat', 'rb')
|
dataFile = open(self.blockDataLocation + hash + '.dat', 'rb')
|
||||||
data = dataFile.read()
|
data = dataFile.read()
|
||||||
dataFile.close()
|
dataFile.close()
|
||||||
|
@ -576,22 +577,22 @@ class Core:
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def getBlockList(self, unsaved = False):
|
def getBlockList(self, unsaved = False): # TODO: Use unsaved
|
||||||
'''
|
'''
|
||||||
Get list of our blocks
|
Get list of our blocks
|
||||||
'''
|
'''
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
retData = ''
|
|
||||||
if unsaved:
|
if unsaved:
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataSaved != 1 ORDER BY RANDOM();'
|
execute = 'SELECT hash FROM hashes WHERE dataSaved != 1 ORDER BY RANDOM();'
|
||||||
else:
|
else:
|
||||||
execute = 'SELECT hash FROM hashes ORDER BY RANDOM();'
|
execute = 'SELECT hash FROM hashes ORDER BY RANDOM();'
|
||||||
|
rows = list()
|
||||||
for row in c.execute(execute):
|
for row in c.execute(execute):
|
||||||
for i in row:
|
for i in row:
|
||||||
retData += i + "\n"
|
rows.append(i)
|
||||||
|
|
||||||
return retData
|
return rows
|
||||||
|
|
||||||
def getBlocksByType(self, blockType):
|
def getBlocksByType(self, blockType):
|
||||||
'''
|
'''
|
||||||
|
@ -599,14 +600,14 @@ class Core:
|
||||||
'''
|
'''
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
retData = ''
|
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataType=?;'
|
execute = 'SELECT hash FROM hashes WHERE dataType=?;'
|
||||||
args = (blockType,)
|
args = (blockType,)
|
||||||
|
rows = list()
|
||||||
for row in c.execute(execute, args):
|
for row in c.execute(execute, args):
|
||||||
for i in row:
|
for i in row:
|
||||||
retData += i + "\n"
|
rows.append(i)
|
||||||
|
|
||||||
return retData.split('\n')
|
return rows
|
||||||
|
|
||||||
def setBlockType(self, hash, blockType):
|
def setBlockType(self, hash, blockType):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -108,7 +108,7 @@ class Onionr:
|
||||||
if not os.path.exists('data/blocks/'):
|
if not os.path.exists('data/blocks/'):
|
||||||
os.mkdir('data/blocks/')
|
os.mkdir('data/blocks/')
|
||||||
|
|
||||||
# Copy default plugins into plugins folder
|
# Copy default plugins into plugins folder
|
||||||
if not os.path.exists(plugins.get_plugins_folder()):
|
if not os.path.exists(plugins.get_plugins_folder()):
|
||||||
if os.path.exists('static-data/default-plugins/'):
|
if os.path.exists('static-data/default-plugins/'):
|
||||||
names = [f for f in os.listdir("static-data/default-plugins/") if not os.path.isfile(f)]
|
names = [f for f in os.listdir("static-data/default-plugins/") if not os.path.isfile(f)]
|
||||||
|
|
|
@ -26,7 +26,7 @@ class OnionrCrypto:
|
||||||
self.keyPowFile = 'data/keyPow.txt'
|
self.keyPowFile = 'data/keyPow.txt'
|
||||||
self.pubKey = None
|
self.pubKey = None
|
||||||
self.privKey = None
|
self.privKey = None
|
||||||
|
|
||||||
self.pubKeyPowToken = None
|
self.pubKeyPowToken = None
|
||||||
self.pubKeyPowHash = None
|
self.pubKeyPowHash = None
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class OnionrCrypto:
|
||||||
except nacl.exceptions.BadSignatureError:
|
except nacl.exceptions.BadSignatureError:
|
||||||
pass
|
pass
|
||||||
return retData
|
return retData
|
||||||
|
|
||||||
def edSign(self, data, key, encodeResult=False):
|
def edSign(self, data, key, encodeResult=False):
|
||||||
'''Ed25519 sign data'''
|
'''Ed25519 sign data'''
|
||||||
try:
|
try:
|
||||||
|
@ -199,7 +199,7 @@ class OnionrCrypto:
|
||||||
if returnEncoded:
|
if returnEncoded:
|
||||||
decrypted = base64.b64encode(decrypted)
|
decrypted = base64.b64encode(decrypted)
|
||||||
return decrypted
|
return decrypted
|
||||||
|
|
||||||
def generateSymmetricPeer(self, peer):
|
def generateSymmetricPeer(self, peer):
|
||||||
'''Generate symmetric key for a peer and save it to the peer database'''
|
'''Generate symmetric key for a peer and save it to the peer database'''
|
||||||
key = self.generateSymmetric()
|
key = self.generateSymmetric()
|
||||||
|
@ -215,7 +215,7 @@ class OnionrCrypto:
|
||||||
private_key = nacl.signing.SigningKey.generate()
|
private_key = nacl.signing.SigningKey.generate()
|
||||||
public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder())
|
public_key = private_key.verify_key.encode(encoder=nacl.encoding.Base32Encoder())
|
||||||
return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode())
|
return (public_key.decode(), private_key.encode(encoder=nacl.encoding.Base32Encoder()).decode())
|
||||||
|
|
||||||
def pubKeyHashID(self, pubkey=''):
|
def pubKeyHashID(self, pubkey=''):
|
||||||
'''Accept a ed25519 public key, return a truncated result of X many sha3_256 hash rounds'''
|
'''Accept a ed25519 public key, return a truncated result of X many sha3_256 hash rounds'''
|
||||||
if pubkey == '':
|
if pubkey == '':
|
||||||
|
@ -237,10 +237,43 @@ class OnionrCrypto:
|
||||||
hasher = hashlib.sha3_256()
|
hasher = hashlib.sha3_256()
|
||||||
hasher.update(data)
|
hasher.update(data)
|
||||||
return hasher.hexdigest()
|
return hasher.hexdigest()
|
||||||
|
|
||||||
def blake2bHash(self, data):
|
def blake2bHash(self, data):
|
||||||
try:
|
try:
|
||||||
data = data.encode()
|
data = data.encode()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
return nacl.hash.blake2b(data)
|
return nacl.hash.blake2b(data)
|
||||||
|
|
||||||
|
def verifyPow(self, blockContent, metadata):
|
||||||
|
'''
|
||||||
|
Verifies the proof of work associated with a block
|
||||||
|
'''
|
||||||
|
retData = False
|
||||||
|
|
||||||
|
if not (('powToken' in metadata) and ('powHash' in metadata)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
dataLen = len(blockContent)
|
||||||
|
|
||||||
|
expectedHash = self.blake2bHash(base64.b64decode(metadata['powToken']) + self.blake2bHash(blockContent.encode()))
|
||||||
|
difficulty = 0
|
||||||
|
try:
|
||||||
|
expectedHash = expectedHash.decode()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if metadata['powHash'] == expectedHash:
|
||||||
|
difficulty = math.floor(dataLen / 1000000)
|
||||||
|
|
||||||
|
mainHash = '0000000000000000000000000000000000000000000000000000000000000000'#nacl.hash.blake2b(nacl.utils.random()).decode()
|
||||||
|
puzzle = mainHash[:difficulty]
|
||||||
|
|
||||||
|
if metadata['powHash'][:difficulty] == puzzle:
|
||||||
|
logger.info('Validated block pow')
|
||||||
|
retData = True
|
||||||
|
else:
|
||||||
|
logger.warn("Invalid token (#1)")
|
||||||
|
else:
|
||||||
|
logger.warn('Invalid token (#2): Expected hash %s, got hash %s...' % (metadata['powHash'], expectedHash))
|
||||||
|
|
||||||
|
return retData
|
||||||
|
|
|
@ -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 onionrplugins as plugins, logger
|
import onionrplugins, logger
|
||||||
|
|
||||||
class DaemonAPI:
|
class DaemonAPI:
|
||||||
def __init__(self, pluginapi):
|
def __init__(self, pluginapi):
|
||||||
|
@ -52,34 +52,34 @@ class PluginAPI:
|
||||||
self.pluginapi = pluginapi
|
self.pluginapi = pluginapi
|
||||||
|
|
||||||
def start(self, name):
|
def start(self, name):
|
||||||
plugins.start(name)
|
onionrplugins.start(name)
|
||||||
|
|
||||||
def stop(self, name):
|
def stop(self, name):
|
||||||
plugins.stop(name)
|
onionrplugins.stop(name)
|
||||||
|
|
||||||
def reload(self, name):
|
def reload(self, name):
|
||||||
plugins.reload(name)
|
onionrplugins.reload(name)
|
||||||
|
|
||||||
def enable(self, name):
|
def enable(self, name):
|
||||||
plugins.enable(name)
|
onionrplugins.enable(name)
|
||||||
|
|
||||||
def disable(self, name):
|
def disable(self, name):
|
||||||
plugins.disable(name)
|
onionrplugins.disable(name)
|
||||||
|
|
||||||
def event(self, name, data = {}):
|
def event(self, name, data = {}):
|
||||||
events.event(name, data = data, onionr = self.pluginapi.get_onionr())
|
events.event(name, data = data, onionr = self.pluginapi.get_onionr())
|
||||||
|
|
||||||
def is_enabled(self, name):
|
def is_enabled(self, name):
|
||||||
return plugins.is_enabled(name)
|
return onionrplugins.is_enabled(name)
|
||||||
|
|
||||||
def get_enabled_plugins(self):
|
def get_enabled_plugins(self):
|
||||||
return plugins.get_enabled()
|
return onionrplugins.get_enabled()
|
||||||
|
|
||||||
def get_folder(self, name = None, absolute = True):
|
def get_folder(self, name = None, absolute = True):
|
||||||
return plugins.get_plugins_folder(name = name, absolute = absolute)
|
return onionrplugins.get_plugins_folder(name = name, absolute = absolute)
|
||||||
|
|
||||||
def get_data_folder(self, name, absolute = True):
|
def get_data_folder(self, name, absolute = True):
|
||||||
return plugins.get_plugin_data_folder(name, absolute = absolute)
|
return onionrplugins.get_plugin_data_folder(name, absolute = absolute)
|
||||||
|
|
||||||
def daemon_event(self, event, plugin = None):
|
def daemon_event(self, event, plugin = None):
|
||||||
return # later make local command like /client/?action=makeEvent&event=eventname&module=modulename
|
return # later make local command like /client/?action=makeEvent&event=eventname&module=modulename
|
||||||
|
@ -153,6 +153,9 @@ class pluginapi:
|
||||||
def get_utils(self):
|
def get_utils(self):
|
||||||
return self.get_onionr().onionrUtils
|
return self.get_onionr().onionrUtils
|
||||||
|
|
||||||
|
def get_crypto():
|
||||||
|
return self.get_core().crypto
|
||||||
|
|
||||||
def get_daemonapi(self):
|
def get_daemonapi(self):
|
||||||
return self.daemon
|
return self.daemon
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ class OnionrUtils:
|
||||||
if block == '':
|
if block == '':
|
||||||
logger.error('Could not send PM')
|
logger.error('Could not send PM')
|
||||||
else:
|
else:
|
||||||
logger.info('Sent PM, hash: ' + block)
|
logger.info('Sent PM, hash: %s' % block)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error('Failed to send PM.', error=error)
|
logger.error('Failed to send PM.', error=error)
|
||||||
|
|
||||||
|
@ -103,14 +103,14 @@ class OnionrUtils:
|
||||||
for key in newKeyList.split(','):
|
for key in newKeyList.split(','):
|
||||||
key = key.split('-')
|
key = key.split('-')
|
||||||
if len(key[0]) > 60 or len(key[1]) > 1000:
|
if len(key[0]) > 60 or len(key[1]) > 1000:
|
||||||
logger.warn(key[0] + ' or its pow value is too large.')
|
logger.warn('%s or its pow value is too large.' % key[0])
|
||||||
continue
|
continue
|
||||||
if self._core._crypto.blake2bHash(base64.b64decode(key[1]) + key[0].encode()).startswith('0000'):
|
if self._core._crypto.blake2bHash(base64.b64decode(key[1]) + key[0].encode()).startswith('0000'):
|
||||||
if not key[0] in self._core.listPeers(randomOrder=False) and type(key) != None and key[0] != self._core._crypto.pubKey:
|
if not key[0] in self._core.listPeers(randomOrder=False) and type(key) != None and key[0] != self._core._crypto.pubKey:
|
||||||
if self._core.addPeer(key[0], key[1]):
|
if self._core.addPeer(key[0], key[1]):
|
||||||
retVal = True
|
retVal = True
|
||||||
else:
|
else:
|
||||||
logger.warn(key[0] + 'pow failed')
|
logger.warn('%s pow failed' % key[0])
|
||||||
return retVal
|
return retVal
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error('Failed to merge keys.', error=error)
|
logger.error('Failed to merge keys.', error=error)
|
||||||
|
@ -127,7 +127,7 @@ class OnionrUtils:
|
||||||
for adder in newAdderList.split(','):
|
for adder in newAdderList.split(','):
|
||||||
if not adder in self._core.listAdders(randomOrder = False) and adder.strip() != self.getMyAddress():
|
if not adder in self._core.listAdders(randomOrder = False) and adder.strip() != self.getMyAddress():
|
||||||
if self._core.addAddress(adder):
|
if self._core.addAddress(adder):
|
||||||
logger.info('Added ' + adder + ' to db.', timestamp = True)
|
logger.info('Added %s to db.' % adder, timestamp = True)
|
||||||
retVal = True
|
retVal = True
|
||||||
else:
|
else:
|
||||||
logger.debug('%s is either our address or already in our DB' % adder)
|
logger.debug('%s is either our address or already in our DB' % adder)
|
||||||
|
@ -156,7 +156,7 @@ class OnionrUtils:
|
||||||
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
|
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 Exception as error:
|
except Exception as error:
|
||||||
if not silent:
|
if not silent:
|
||||||
logger.error('Failed to make local request (command: ' + str(command) + ').', error=error)
|
logger.error('Failed to make local request (command: %s).' % command, error=error)
|
||||||
retData = False
|
retData = False
|
||||||
|
|
||||||
return retData
|
return retData
|
||||||
|
@ -362,8 +362,7 @@ class OnionrUtils:
|
||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
print('--------------------')
|
logger.info('Decrypted %s:' % i)
|
||||||
logger.info('Decrypted ' + i + ':')
|
|
||||||
logger.info(message["msg"])
|
logger.info(message["msg"])
|
||||||
|
|
||||||
signer = message["id"]
|
signer = message["id"]
|
||||||
|
@ -371,16 +370,16 @@ class OnionrUtils:
|
||||||
|
|
||||||
if self.validatePubKey(signer):
|
if self.validatePubKey(signer):
|
||||||
if self._core._crypto.edVerify(message["msg"], signer, sig, encodedData=True):
|
if self._core._crypto.edVerify(message["msg"], signer, sig, encodedData=True):
|
||||||
logger.info("Good signature by " + signer)
|
logger.info("Good signature by %s" % signer)
|
||||||
else:
|
else:
|
||||||
logger.warn("Bad signature by " + signer)
|
logger.warn("Bad signature by %s" % signer)
|
||||||
else:
|
else:
|
||||||
logger.warn("Bad sender id: " + signer)
|
logger.warn('Bad sender id: %s' % signer)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error('Failed to open block ' + str(i) + '.', error=error)
|
logger.error('Failed to open block %s.' % i, error=error)
|
||||||
return
|
return
|
||||||
|
|
||||||
def getPeerByHashId(self, hash):
|
def getPeerByHashId(self, hash):
|
||||||
|
@ -438,14 +437,14 @@ class OnionrUtils:
|
||||||
scanDir += '/'
|
scanDir += '/'
|
||||||
for block in glob.glob(scanDir + "*.dat"):
|
for block in glob.glob(scanDir + "*.dat"):
|
||||||
if block.replace(scanDir, '').replace('.dat', '') not in blockList:
|
if block.replace(scanDir, '').replace('.dat', '') not in blockList:
|
||||||
logger.info("Found new block on dist " + block)
|
logger.info('Found new block on dist %s' % block)
|
||||||
with open(block, 'rb') as newBlock:
|
with open(block, 'rb') as newBlock:
|
||||||
block = block.replace(scanDir, '').replace('.dat', '')
|
block = block.replace(scanDir, '').replace('.dat', '')
|
||||||
if self._core._crypto.sha3Hash(newBlock.read()) == block.replace('.dat', ''):
|
if self._core._crypto.sha3Hash(newBlock.read()) == block.replace('.dat', ''):
|
||||||
self._core.addToBlockDB(block.replace('.dat', ''), dataSaved=True)
|
self._core.addToBlockDB(block.replace('.dat', ''), dataSaved=True)
|
||||||
logger.info('Imported block.')
|
logger.info('Imported block %s.' % block)
|
||||||
else:
|
else:
|
||||||
logger.warn('Failed to verify hash for ' + block)
|
logger.warn('Failed to verify hash for %s' % block)
|
||||||
|
|
||||||
|
|
||||||
def progressBar(self, value = 0, endvalue = 100, width = None):
|
def progressBar(self, value = 0, endvalue = 100, width = None):
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# useful libraries
|
# useful libraries
|
||||||
import logger, config
|
import logger, config
|
||||||
import os, sys, json, time, random
|
import os, sys, json, time, random, shutil, base64, getpass, datetime
|
||||||
|
|
||||||
plugin_name = 'pluginmanager'
|
plugin_name = 'pluginmanager'
|
||||||
|
|
||||||
|
@ -56,6 +56,78 @@ def check():
|
||||||
if not os.path.isfile(keys_file):
|
if not os.path.isfile(keys_file):
|
||||||
writeKeys()
|
writeKeys()
|
||||||
|
|
||||||
|
# plugin management
|
||||||
|
|
||||||
|
def installBlock(hash, overwrite = True):
|
||||||
|
logger.debug('install')
|
||||||
|
|
||||||
|
def pluginToBlock(plugin, import_block = True):
|
||||||
|
try:
|
||||||
|
directory = pluginapi.get_pluginapi().get_folder(plugin)
|
||||||
|
data_directory = pluginapi.get_pluginapi().get_data_folder(plugin)
|
||||||
|
zipfile = pluginapi.get_pluginapi().get_data_folder(plugin_name) + 'plugin.zip'
|
||||||
|
|
||||||
|
if os.path.exists(directory) and not os.path.isfile(directory):
|
||||||
|
if os.path.exists(data_directory) and not os.path.isfile(data_directory):
|
||||||
|
shutil.rmtree(data_directory)
|
||||||
|
if os.path.exists(zipfile) and os.path.isfile(zipfile):
|
||||||
|
os.remove(zipfile)
|
||||||
|
if os.path.exists(directory + '__pycache__') and not os.path.isfile(directory + '__pycache__'):
|
||||||
|
shutil.rmtree(directory + '__pycache__')
|
||||||
|
|
||||||
|
shutil.make_archive(zipfile[:-4], 'zip', directory)
|
||||||
|
data = base64.b64encode(open(zipfile, 'rb').read())
|
||||||
|
|
||||||
|
metadata = {'author' : getpass.getuser(), 'date' : str(datetime.datetime.now()), 'content' : data.decode('utf-8'), 'name' : plugin, 'compiled-by' : plugin_name}
|
||||||
|
|
||||||
|
hash = pluginapi.get_core().insertBlock(json.dumps(metadata), header = 'plugin', sign = True)
|
||||||
|
|
||||||
|
if import_block:
|
||||||
|
pluginapi.get_utils().importNewBlocks()
|
||||||
|
|
||||||
|
return hash
|
||||||
|
else:
|
||||||
|
logger.error('Plugin %s does not exist.' % plugin)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Failed to convert plugin to block.', error = e, timestamp = False)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def parseBlock(hash, key):# deal with block metadata
|
||||||
|
blockContent = pluginapi.get_core().getData(hash)
|
||||||
|
|
||||||
|
try:
|
||||||
|
blockMetadata = json.loads(blockContent[:blockContent.decode().find(b'}') + 1].decode())
|
||||||
|
try:
|
||||||
|
blockMeta2 = json.loads(blockMetadata['meta'])
|
||||||
|
except KeyError:
|
||||||
|
blockMeta2 = {'type': ''}
|
||||||
|
pass
|
||||||
|
blockContent = blockContent[blockContent.rfind(b'}') + 1:]
|
||||||
|
try:
|
||||||
|
blockContent = blockContent.decode()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not pluginapi.get_crypto().verifyPow(blockContent, blockMeta2):
|
||||||
|
logger.debug("(pluginmanager): %s has invalid or insufficient proof of work" % str(hash))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not (('sig' in blockMetadata) and ('id' in blockMeta2)):
|
||||||
|
logger.debug('(pluginmanager): %s is missing required parameters' % hash)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if pluginapi.get_crypto().edVerify(blockMetaData['meta'] + blockContent, key, blockMetadata['sig'], encodedData=True):
|
||||||
|
logger.debug('(pluginmanager): %s was signed' % str(hash))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug('(pluginmanager): %s has an invalid signature' % str(hash))
|
||||||
|
return False
|
||||||
|
except json.decoder.JSONDecodeError as e:
|
||||||
|
logger.error('(pluginmanager): Could not decode block metadata.', error = e, timestamp = False)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
# command handlers
|
# command handlers
|
||||||
|
|
||||||
def help():
|
def help():
|
||||||
|
@ -101,13 +173,7 @@ def commandInstallPlugin():
|
||||||
blockhash = str(pkobh)
|
blockhash = str(pkobh)
|
||||||
logger.debug('Using block %s...' % blockhash)
|
logger.debug('Using block %s...' % blockhash)
|
||||||
|
|
||||||
logger.info('Downloading plugin...')
|
installBlock(blockhash)
|
||||||
for i in range(0, 100):
|
|
||||||
pluginapi.get_utils().progressBar(i, 100)
|
|
||||||
time.sleep(random.random() / 5)
|
|
||||||
logger.info('Finished downloading plugin, verifying and installing...')
|
|
||||||
time.sleep(1)
|
|
||||||
logger.info('Installation successful.')
|
|
||||||
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.')
|
||||||
|
@ -117,13 +183,14 @@ def commandInstallPlugin():
|
||||||
|
|
||||||
saveKey(pluginname, pkobh)
|
saveKey(pluginname, pkobh)
|
||||||
|
|
||||||
logger.info('Downloading plugin...')
|
blocks = pluginapi.get_core().getBlocksByType('plugin')
|
||||||
for i in range(0, 100):
|
|
||||||
pluginapi.get_utils().progressBar(i, 100)
|
for hash in blocks:
|
||||||
time.sleep(random.random() / 5)
|
logger.debug('Scanning block for plugin: %s' % hash)
|
||||||
logger.info('Finished downloading plugin, verifying and installing...')
|
if parseBlock(hash, publickey):
|
||||||
time.sleep(1)
|
logger.info('success')
|
||||||
logger.info('Installation successful.')
|
else:
|
||||||
|
logger.warn('fail')
|
||||||
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))
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue