Ejemplo n.º 1
0
def blockToPlugin(block):
    try:
        block = Block(block)
        blockContent = json.loads(block.getContent())

        name = sanitize(blockContent['name'])
        author = blockContent['author']
        date = blockContent['date']
        version = None

        if 'version' in blockContent['info']:
            version = blockContent['info']['version']

        content = base64.b64decode(blockContent['content'].encode())

        source = pluginapi.plugins.get_data_folder(plugin_name) + 'plugin.zip'
        destination = pluginapi.plugins.get_folder(name)

        with open(source, 'wb') as f:
            f.write(content)

        if os.path.exists(destination) and not os.path.isfile(destination):
            shutil.rmtree(destination)

        shutil.unpack_archive(source, destination)
        pluginapi.plugins.enable(name)

        logger.info('Installation of %s complete.' % name)

        return True
    except Exception as e:
        logger.error('Failed to install plugin.', error=e, timestamp=False)

    return False
Ejemplo n.º 2
0
def commandAddRepository():
    if len(sys.argv) >= 3:
        check()

        blockhash = sys.argv[2]

        if pluginapi.get_utils().validateHash(blockhash):
            if Block.exists(blockhash):
                try:
                    blockContent = json.loads(Block(blockhash, core = pluginapi.get_core()).getContent())

                    pluginslist = dict()

                    for pluginname, distributor in blockContent['plugins']:
                        if pluginapi.get_utils().validatePubKey(distributor):
                            pluginslist[pluginname] = distributor

                    logger.debug('Found %s records in repository.' % len(pluginslist))

                    if len(pluginslist) != 0:
                        addRepository(blockhash, pluginslist)
                        logger.info('Successfully added repository.')
                    else:
                        logger.error('Repository contains no records, not importing.', timestamp = False)
                except Exception as e:
                    logger.error('Failed to parse block.', error = e)
            else:
                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.')
        else:
            logger.error('Unknown data "%s"; must be block hash.' % str(pkobh), timestamp = False)
    else:
        logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' [block hash]')

    return True
Ejemplo n.º 3
0
def installBlock(block):
    try:
        block = Block(block, core = pluginapi.get_core())
        blockContent = json.loads(block.getContent())

        name = sanitize(blockContent['name'])
        author = blockContent['author']
        date = blockContent['date']
        version = None

        if 'version' in blockContent['info']:
            version = blockContent['info']['version']

        install = False

        logger.info(('Will install %s' + (' v' + version if not version is None else '') + ' (%s), by %s') % (name, date, author))

        # TODO: Convert to single line if statement
        if os.path.exists(pluginapi.plugins.get_folder(name)):
            install = logger.confirm(message = 'Continue with installation (will overwrite existing plugin) %s?')
        else:
            install = logger.confirm(message = 'Continue with installation %s?')

        if install:
            blockToPlugin(block.getHash())
            addPlugin(name)
        else:
            logger.info('Installation cancelled.')
            return False

        return True
    except Exception as e:
        logger.error('Failed to install plugin.', error = e, timestamp = False)
        return False
Ejemplo n.º 4
0
def getFile(o_inst):
    '''
        Get a file from onionr blocks
    '''
    try:
        fileName = sys.argv[2]
        bHash = sys.argv[3]
    except IndexError:
        logger.error("Syntax %s %s" %
                     (sys.argv[0], '/path/to/filename <blockhash>'))
    else:
        logger.info(fileName)

        contents = None
        if os.path.exists(fileName):
            logger.error("File already exists")
            return
        if not o_inst.onionrUtils.validateHash(bHash):
            logger.error('Block hash is invalid')
            return

        with open(fileName, 'wb') as myFile:
            myFile.write(
                base64.b64decode(
                    Block(bHash, core=o_inst.onionrCore).bcontent))
    return
Ejemplo n.º 5
0
 def showOutput(self):
     while type(self.channel) is type(None) and self.flowRunning:
         time.sleep(1)
     try:
         while self.flowRunning:
             for block in self.myCore.getBlocksByType('txt'):
                 block = Block(block)
                 if block.getMetadata('ch') != self.channel:
                     #print('not chan', block.getMetadata('ch'))
                     continue
                 if block.getHash() in self.alreadyOutputed:
                     #print('already')
                     continue
                 if not self.flowRunning:
                     break
                 logger.info('\n------------------------', prompt=False)
                 content = block.getContent()
                 # Escape new lines, remove trailing whitespace, and escape ansi sequences
                 content = self.myCore._utils.escapeAnsi(
                     content.replace('\n', '\\n').replace('\r',
                                                          '\\r').strip())
                 logger.info(block.getDate().strftime("%m/%d %H:%M") +
                             ' - ' + logger.colors.reset + content,
                             prompt=False)
                 self.alreadyOutputed.append(block.getHash())
             time.sleep(5)
     except KeyboardInterrupt:
         self.flowRunning = False
Ejemplo n.º 6
0
    def processBlockMetadata(self, blockHash):
        '''
            Read metadata from a block and cache it to the block database
        '''
        curTime = self.getRoundedEpoch(roundS=60)
        myBlock = Block(blockHash, self._core)
        if myBlock.isEncrypted:
            myBlock.decrypt()
        if (myBlock.isEncrypted
                and myBlock.decrypted) or (not myBlock.isEncrypted):
            blockType = myBlock.getMetadata(
                'type'
            )  # we would use myBlock.getType() here, but it is bugged with encrypted blocks
            signer = self.bytesToStr(myBlock.signer)
            valid = myBlock.verifySig()
            if myBlock.getMetadata('newFSKey') is not None:
                onionrusers.OnionrUser(self._core, signer).addForwardKey(
                    myBlock.getMetadata('newFSKey'))

            try:
                if len(blockType) <= 10:
                    self._core.updateBlockInfo(blockHash, 'dataType',
                                               blockType)
            except TypeError:
                logger.warn("Missing block information")
                pass
            # Set block expire time if specified
            try:
                expireTime = myBlock.getHeader('expire')
                assert len(
                    str(int(expireTime))
                ) < 20  # test that expire time is an integer of sane length (for epoch)
            except (AssertionError, ValueError, TypeError) as e:
                expireTime = onionrvalues.OnionrValues(
                ).default_expire + curTime
            finally:
                self._core.updateBlockInfo(blockHash, 'expire', expireTime)
            if not blockType is None:
                self._core.updateBlockInfo(blockHash, 'dataType', blockType)
            onionrevents.event('processblocks',
                               data={
                                   'block': myBlock,
                                   'type': blockType,
                                   'signer': signer,
                                   'validSig': valid
                               },
                               onionr=self._core.onionrInst)
        else:
            pass
Ejemplo n.º 7
0
def pluginToBlock(plugin, import_block = True):
    try:
        plugin = sanitize(plugin)

        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 = ''
            with open(zipfile, 'rb') as file:
                data = base64.b64encode(file.read())

            author = getpass.getuser()
            description = 'Default plugin description'
            info = {"name" : plugin}
            try:
                if os.path.exists(directory + 'info.json'):
                    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:
                        description = info['description']
            except:
                pass

            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)

            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
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
def update():
    global listedBlocks, listbox, runningCheckDelayCount, runningCheckDelay, root, daemonStatus

    for i in Block.getBlocks(type='txt'):
        if i.getContent().strip() == '' or i.getHash() in listedBlocks:
            continue
        listbox.insert(99999, str(i.getContent()))
        listedBlocks.append(i.getHash())
        listbox.see(99999)

    runningCheckDelayCount += 1

    if runningCheckDelayCount == runningCheckDelay:
        resp = pluginapi.daemon.local_command('ping')
        if resp == 'pong':
            daemonStatus.config(text="Onionr Daemon Status: Running")
        else:
            daemonStatus.config(text="Onionr Daemon Status: Not Running")
        runningCheckDelayCount = 0
    root.after(10000, update)
Ejemplo n.º 10
0
def commandInstallPlugin():
    if len(sys.argv) >= 3:
        check()

        pluginname = sys.argv[2]
        pkobh = None  # public key or block hash

        version = None
        if ':' in pluginname:
            details = pluginname
            pluginname = sanitize(details[0])
            version = details[1]

        sanitize(pluginname)

        if len(sys.argv) >= 4:
            # public key or block hash specified
            pkobh = sys.argv[3]
        else:
            # none specified, check if in config file
            pkobh = getKey(pluginname)

        if pkobh is None:
            # still nothing found, try searching repositories
            logger.info('Searching for public key in repositories...')
            try:
                repos = getRepositories()
                distributors = list()
                for repo, records in repos.items():
                    if pluginname in records:
                        logger.debug(
                            'Found %s in repository %s for plugin %s.' %
                            (records[pluginname], repo, pluginname))
                        distributors.append(records[pluginname])

                if len(distributors) != 0:
                    distributor = None

                    if len(distributors) == 1:
                        logger.info('Found distributor: %s' % distributors[0])
                        distributor = distributors[0]
                    else:
                        distributors_message = ''

                        index = 1
                        for dist in distributors:
                            distributors_message += '    ' + logger.colors.bold + str(
                                index) + ') ' + logger.colors.reset + str(
                                    dist) + '\n'
                            index += 1

                        logger.info(
                            (logger.colors.bold + 'Found distributors (%s):' +
                             logger.colors.reset + '\n' + distributors_message)
                            % len(distributors))

                        valid = False
                        while not valid:
                            choice = logger.readline(
                                'Select the number of the key to use, from 1 to %s, or press Ctrl+C to cancel:'
                                % (index - 1))

                            try:
                                if int(choice) < index and int(choice) >= 1:
                                    distributor = distributors[int(choice)]
                                    valid = True
                            except KeyboardInterrupt:
                                logger.info('Installation cancelled.')
                                return True
                            except:
                                pass

                    if not distributor is None:
                        pkobh = distributor
            except Exception as e:
                logger.warn('Failed to lookup plugin in repositories.',
                            timestamp=False)
                logger.error('asdf', error=e, timestamp=False)

        if pkobh is None:
            logger.error(
                'No key for this plugin found in keystore or repositories, please specify.'
            )
            help()
            return True

        valid_hash = pluginapi.get_utils().validateHash(pkobh)
        real_block = False
        valid_key = pluginapi.get_utils().validatePubKey(pkobh)
        real_key = False

        if valid_hash:
            real_block = Block.exists(pkobh)
        elif valid_key:
            real_key = pluginapi.get_utils().hasKey(pkobh)

        blockhash = None

        if valid_hash and not real_block:
            logger.error(
                'Block hash not found. Perhaps it has not been synced yet?')
            logger.debug(
                'Is valid hash, but does not belong to a known block.')

            return True
        elif valid_hash and real_block:
            blockhash = str(pkobh)
            logger.debug('Using block %s...' % blockhash)

            installBlock(blockhash)
        elif valid_key and not real_key:
            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.')
        elif valid_key and real_key:
            publickey = str(pkobh)
            logger.debug('Using public key %s...' % publickey)

            saveKey(pluginname, pkobh)

            signedBlocks = Block.getBlocks(type='plugin',
                                           signed=True,
                                           signer=publickey)

            mostRecentTimestamp = None
            mostRecentVersionBlock = None

            for block in signedBlocks:
                try:
                    blockContent = json.loads(block.getContent())

                    if not (('author' in blockContent) and
                            ('info' in blockContent) and
                            ('date' in blockContent) and
                            ('name' in blockContent)):
                        raise ValueError(
                            'Missing required parameter `date` in block %s.' %
                            block.getHash())

                    blockDatetime = datetime.datetime.strptime(
                        blockContent['date'], '%Y-%m-%d %H:%M:%S')

                    if blockContent['name'] == pluginname:
                        if ('version' in blockContent['info']) and (
                                blockContent['info']['version']
                                == version) and (not version is None):
                            mostRecentTimestamp = blockDatetime
                            mostRecentVersionBlock = block.getHash()
                            break
                        elif mostRecentTimestamp is None:
                            mostRecentTimestamp = blockDatetime
                            mostRecentVersionBlock = block.getHash()
                        elif blockDatetime > mostRecentTimestamp:
                            mostRecentTimestamp = blockDatetime
                            mostRecentVersionBlock = block.getHash()
                except Exception as e:
                    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)
            installBlock(mostRecentVersionBlock)
        else:
            logger.error(
                'Unknown data "%s"; must be public key or block hash.' %
                str(pkobh))
            return
    else:
        logger.info(sys.argv[0] + ' ' + sys.argv[1] +
                    ' <plugin> [public key/block hash]')

    return True
Ejemplo n.º 11
0
def send():
    global message
    block = Block()
    block.setType('txt')
    block.setContent(message)
    logger.debug('Sent message in block %s.' % block.save(sign=True))
Ejemplo n.º 12
0
    def inbox(self):
        blockCount = 0
        pmBlockMap = {}
        pmBlocks = {}
        logger.info('Decrypting messages...')
        choice = ''
        displayList = []
        subject = ''

        # this could use a lot of memory if someone has received a lot of messages
        for blockHash in self.myCore.getBlocksByType('pm'):
            pmBlocks[blockHash] = Block(blockHash, core=self.myCore)
            pmBlocks[blockHash].decrypt()
            blockCount = 0
        for blockHash in pmBlocks:
            if not pmBlocks[blockHash].decrypted:
                continue
            blockCount += 1
            pmBlockMap[blockCount] = blockHash

            block = pmBlocks[blockHash]
            senderKey = block.signer
            try:
                senderKey = senderKey.decode()
            except AttributeError:
                pass
            senderDisplay = onionrusers.OnionrUser(self.myCore,
                                                   senderKey).getName()
            if senderDisplay == 'anonymous':
                senderDisplay = senderKey

            blockDate = pmBlocks[blockHash].getDate().strftime("%m/%d %H:%M")
            try:
                subject = pmBlocks[blockHash].bmetadata['subject']
            except KeyError:
                subject = ''

            displayList.append('%s. %s - %s - <%s>: %s' %
                               (blockCount, blockDate, senderDisplay[:12],
                                subject[:10], blockHash))
        while choice not in ('-q', 'q', 'quit'):
            for i in displayList:
                logger.info(i)
            try:
                choice = logger.readline(
                    'Enter a block number, -r to refresh, or -q to stop: '
                ).strip().lower()
            except (EOFError, KeyboardInterrupt):
                choice = '-q'

            if choice in ('-q', 'q', 'quit'):
                continue

            if choice in ('-r', 'r', 'refresh'):
                # dirty hack
                self.inbox()
                return

            try:
                choice = int(choice)
            except ValueError:
                pass
            else:
                try:
                    pmBlockMap[choice]
                    readBlock = pmBlocks[pmBlockMap[choice]]
                except KeyError:
                    pass
                else:
                    cancel = ''
                    readBlock.verifySig()
                    senderDisplay = self.myCore._utils.bytesToStr(
                        readBlock.signer)
                    if len(senderDisplay.strip()) == 0:
                        senderDisplay = 'Anonymous'
                    logger.info('Message received from %s' % (senderDisplay, ))
                    logger.info('Valid signature: %s' % readBlock.validSig)

                    if not readBlock.validSig:
                        logger.warn(
                            'This message has an INVALID/NO signature. ANYONE could have sent this message.'
                        )
                        cancel = logger.readline(
                            'Press enter to continue to message, or -q to not open the message (recommended).'
                        )
                        print('')
                    if cancel != '-q':
                        try:
                            print(
                                draw_border(
                                    self.myCore._utils.escapeAnsi(
                                        readBlock.bcontent.decode().strip())))
                        except ValueError:
                            logger.warn(
                                'Error presenting message. This is usually due to a malformed or blank message.'
                            )
                            pass
                        if readBlock.validSig:
                            reply = logger.readline(
                                "Press enter to continue, or enter %s to reply"
                                % ("-r", ))
                            print('')
                            if reply == "-r":
                                self.draft_message(
                                    self.myCore._utils.bytesToStr(
                                        readBlock.signer, ))
                        else:
                            logger.readline("Press enter to continue")
                            print('')
        return
Ejemplo n.º 13
0
def show_stats(o_inst):
    try:
        # define stats messages here
        totalBlocks = len(o_inst.onionrCore.getBlockList())
        signedBlocks = len(Block.getBlocks(signed=True))
        messages = {
            # info about local client
            'Onionr Daemon Status':
            ((logger.colors.fg.green +
              'Online') if o_inst.onionrUtils.isCommunicatorRunning(
                  timeout=9) else logger.colors.fg.red + 'Offline'),

            # file and folder size stats
            'div1':
            True,  # this creates a solid line across the screen, a div
            'Total Block Size':
            onionrutils.humanSize(onionrutils.size(o_inst.dataDir +
                                                   'blocks/')),
            'Total Plugin Size':
            onionrutils.humanSize(onionrutils.size(o_inst.dataDir +
                                                   'plugins/')),
            'Log File Size':
            onionrutils.humanSize(
                onionrutils.size(o_inst.dataDir + 'output.log')),

            # count stats
            'div2':
            True,
            'Known Peers':
            str(max(len(o_inst.onionrCore.listPeers()) - 1, 0)),
            'Enabled Plugins':
            str(len(o_inst.onionrCore.config.get('plugins.enabled', list()))) +
            ' / ' + str(len(os.listdir(o_inst.dataDir + 'plugins/'))),
            'Stored Blocks':
            str(totalBlocks),
            'Percent Blocks Signed':
            str(round(100 * signedBlocks / max(totalBlocks, 1), 2)) + '%'
        }

        # color configuration
        colors = {
            'title': logger.colors.bold,
            'key': logger.colors.fg.lightgreen,
            'val': logger.colors.fg.green,
            'border': logger.colors.fg.lightblue,
            'reset': logger.colors.reset
        }

        # pre-processing
        maxlength = 0
        width = o_inst.getConsoleWidth()
        for key, val in messages.items():
            if not (type(val) is bool and val is True):
                maxlength = max(len(key), maxlength)
        prewidth = maxlength + len(' | ')
        groupsize = width - prewidth - len('[+] ')

        # generate stats table
        logger.info(colors['title'] +
                    'Onionr v%s Statistics' % onionr.ONIONR_VERSION +
                    colors['reset'])
        logger.info(colors['border'] + '-' * (maxlength + 1) + '+' +
                    colors['reset'])
        for key, val in messages.items():
            if not (type(val) is bool and val is True):
                val = [
                    str(val)[i:i + groupsize]
                    for i in range(0, len(str(val)), groupsize)
                ]

                logger.info(colors['key'] + str(key).rjust(maxlength) +
                            colors['reset'] + colors['border'] + ' | ' +
                            colors['reset'] + colors['val'] + str(val.pop(0)) +
                            colors['reset'])

                for value in val:
                    logger.info(' ' * maxlength + colors['border'] + ' | ' +
                                colors['reset'] + colors['val'] + str(value) +
                                colors['reset'])
            else:
                logger.info(colors['border'] + '-' * (maxlength + 1) + '+' +
                            colors['reset'])
        logger.info(colors['border'] + '-' * (maxlength + 1) + '+' +
                    colors['reset'])
    except Exception as e:
        logger.error('Failed to generate statistics table.',
                     error=e,
                     timestamp=False)