Example #1
0
def process_block_metadata(blockHash: str):
    '''
        Read metadata from a block and cache it to the block database

        blockHash -> sha3_256 hex formatted hash of Onionr block
    '''
    curTime = epoch.get_rounded_epoch(roundS=60)
    myBlock = onionrblockapi.Block(blockHash)
    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 = bytesconverter.bytes_to_str(myBlock.signer)
        valid = myBlock.verifySig()
        if valid:
            if myBlock.getMetadata('newFSKey') is not None:
                try:
                    onionrusers.OnionrUser(signer).addForwardKey(
                        myBlock.getMetadata('newFSKey'))
                except onionrexceptions.InvalidPubkey:
                    logger.warn(
                        '%s has invalid forward secrecy key to add: %s' %
                        (signer, myBlock.getMetadata('newFSKey')))

        try:
            if len(blockType) <= onionrvalues.MAX_BLOCK_TYPE_LENGTH:
                blockmetadb.update_block_info(blockHash, 'dataType', blockType)
        except TypeError:
            logger.warn("Missing block information")
            pass
        # Set block expire time if specified
        try:
            expireTime = int(myBlock.getHeader('expire'))
            # test that expire time is an integer of sane length (for epoch)
            # doesn't matter if its too large because of the min() func below
            if not len(str(expireTime)) < 20:
                raise ValueError('timestamp invalid')
        except (ValueError, TypeError) as e:
            expireTime = onionrvalues.DEFAULT_EXPIRE + curTime
        finally:
            expireTime = min(expireTime, curTime + onionrvalues.DEFAULT_EXPIRE)
            blockmetadb.update_block_info(blockHash, 'expire', expireTime)

        if blockType == 'update': updater.update_event(myBlock)
        onionrevents.event('processblocks',
                           data={
                               'block': myBlock,
                               'type': blockType,
                               'signer': signer,
                               'validSig': valid
                           })
Example #2
0
def friend_command(o_inst):
    friend = ''
    try:
        # Get the friend command
        action = sys.argv[2]
    except IndexError:
        logger.info('Syntax: friend add/remove/list [address]')
    else:
        action = action.lower()
        if action == 'list':
            # List out peers marked as our friend
            for friend in onionrusers.OnionrUser.list_friends(
                    o_inst.onionrCore):
                logger.info(friend.publicKey + ' - ' + friend.getName())
        elif action in ('add', 'remove'):
            try:
                friend = sys.argv[3]
                if not o_inst.onionrUtils.validatePubKey(friend):
                    raise onionrexceptions.InvalidPubkey(
                        'Public key is invalid')
                if friend not in o_inst.onionrCore.listPeers():
                    raise onionrexceptions.KeyNotKnown
                friend = onionrusers.OnionrUser(o_inst.onionrCore, friend)
            except IndexError:
                logger.warn('Friend ID is required.')
                action = 'error'  # set to 'error' so that the finally block does not process anything
            except onionrexceptions.KeyNotKnown:
                o_inst.onionrCore.addPeer(friend)
                friend = onionrusers.OnionrUser(o_inst.onionrCore, friend)
            finally:
                if action == 'add':
                    friend.setTrust(1)
                    logger.info('Added %s as friend.' % (friend.publicKey, ))
                elif action == 'remove':
                    friend.setTrust(0)
                    logger.info('Removed %s as friend.' % (friend.publicKey, ))
        else:
            logger.info('Syntax: friend add/remove/list [address]')
Example #3
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
Example #4
0
    def test_forward_encrypt_bin(self):

        friend = crypto.generate()

        friendUser = onionrusers.OnionrUser(friend[0], saveUser=True)

        for x in range(5):
            message = os.urandom(32)
            forwardKey = friendUser.generateForwardKey()

            fakeForwardPair = crypto.generate()

            self.assertTrue(friendUser.addForwardKey(fakeForwardPair[0]))

            encrypted = friendUser.forwardEncrypt(message)

            decrypted = crypto.encryption.pub_key_decrypt(encrypted[0], privkey=fakeForwardPair[1], encodedData=True)
            self.assertEqual(decrypted, message)
Example #5
0
    def test_forward_encrypt(self):

        friend = crypto.generate()

        friendUser = onionrusers.OnionrUser(friend[0], saveUser=True)

        for x in range(5):
            message = 'hello world %s' % (random.randint(1, 1000))
            forwardKey = friendUser.generateForwardKey()

            fakeForwardPair = crypto.generate()

            self.assertTrue(friendUser.addForwardKey(fakeForwardPair[0]))

            encrypted = friendUser.forwardEncrypt(message)

            decrypted = crypto.encryption.pub_key_decrypt(encrypted[0], privkey=fakeForwardPair[1], encodedData=True)
            self.assertEqual(decrypted, message.encode())
        return
    def test_forward_encrypt(self):
        os.environ["ONIONR_HOME"] = TEST_DIR_1
        o = onionr.Onionr()

        friend = o.onionrCore._crypto.generatePubKey()

        friendUser = onionrusers.OnionrUser(o.onionrCore,
                                            friend[0],
                                            saveUser=True)

        for x in range(5):
            message = 'hello world %s' % (random.randint(1, 1000))
            forwardKey = friendUser.generateForwardKey()

            fakeForwardPair = o.onionrCore._crypto.generatePubKey()

            self.assertTrue(friendUser.addForwardKey(fakeForwardPair[0]))

            encrypted = friendUser.forwardEncrypt(message)

            decrypted = o.onionrCore._crypto.pubKeyDecrypt(
                encrypted[0], privkey=fakeForwardPair[1], encodedData=True)
            self.assertEqual(decrypted, message.encode())
        return
Example #7
0
 def test_users(self):
     keypair = c._crypto.generatePubKey()
     onionrusers.OnionrUser(c, keypair[0])
     return
Example #8
0
    def insertBlock(self,
                    data,
                    header='txt',
                    sign=False,
                    encryptType='',
                    symKey='',
                    asymPeer='',
                    meta={},
                    expire=None,
                    disableForward=False):
        '''
            Inserts a block into the network
            encryptType must be specified to encrypt a block
        '''
        allocationReachedMessage = 'Cannot insert block, disk allocation reached.'
        if self._utils.storageCounter.isFull():
            logger.error(allocationReachedMessage)
            return False
        retData = False

        if type(data) is None:
            raise ValueError('Data cannot be none')

        createTime = self._utils.getRoundedEpoch()

        # check nonce
        #print(data)
        dataNonce = self._utils.bytesToStr(self._crypto.sha3Hash(data))
        try:
            with open(self.dataNonceFile, 'r') as nonces:
                if dataNonce in nonces:
                    return retData
        except FileNotFoundError:
            pass
        # record nonce
        with open(self.dataNonceFile, 'a') as nonceFile:
            nonceFile.write(dataNonce + '\n')

        if type(data) is bytes:
            data = data.decode()
        data = str(data)
        plaintext = data
        plaintextMeta = {}
        plaintextPeer = asymPeer

        retData = ''
        signature = ''
        signer = ''
        metadata = {}
        # metadata is full block metadata, meta is internal, user specified metadata

        # only use header if not set in provided meta

        meta['type'] = str(header)

        if encryptType in ('asym', 'sym', ''):
            metadata['encryptType'] = encryptType
        else:
            raise onionrexceptions.InvalidMetadata(
                'encryptType must be asym or sym, or blank')

        try:
            data = data.encode()
        except AttributeError:
            pass

        if encryptType == 'asym':
            meta[
                'rply'] = createTime  # Duplicate the time in encrypted messages to prevent replays
            if not disableForward and sign and asymPeer != self._crypto.pubKey:
                try:
                    forwardEncrypted = onionrusers.OnionrUser(
                        self, asymPeer).forwardEncrypt(data)
                    data = forwardEncrypted[0]
                    meta['forwardEnc'] = True
                    expire = forwardEncrypted[
                        2]  # Expire time of key. no sense keeping block after that
                except onionrexceptions.InvalidPubkey:
                    pass
                    #onionrusers.OnionrUser(self, asymPeer).generateForwardKey()
                fsKey = onionrusers.OnionrUser(self,
                                               asymPeer).generateForwardKey()
                #fsKey = onionrusers.OnionrUser(self, asymPeer).getGeneratedForwardKeys().reverse()
                meta['newFSKey'] = fsKey
        jsonMeta = json.dumps(meta)
        plaintextMeta = jsonMeta
        if sign:
            signature = self._crypto.edSign(jsonMeta.encode() + data,
                                            key=self._crypto.privKey,
                                            encodeResult=True)
            signer = self._crypto.pubKey

        if len(jsonMeta) > 1000:
            raise onionrexceptions.InvalidMetadata(
                'meta in json encoded form must not exceed 1000 bytes')

        user = onionrusers.OnionrUser(self, symKey)

        # encrypt block metadata/sig/content
        if encryptType == 'sym':

            if len(symKey) < self.requirements.passwordLength:
                raise onionrexceptions.SecurityError('Weak encryption key')
            jsonMeta = self._crypto.symmetricEncrypt(
                jsonMeta, key=symKey, returnEncoded=True).decode()
            data = self._crypto.symmetricEncrypt(data,
                                                 key=symKey,
                                                 returnEncoded=True).decode()
            signature = self._crypto.symmetricEncrypt(
                signature, key=symKey, returnEncoded=True).decode()
            signer = self._crypto.symmetricEncrypt(
                signer, key=symKey, returnEncoded=True).decode()
        elif encryptType == 'asym':
            if self._utils.validatePubKey(asymPeer):
                # Encrypt block data with forward secrecy key first, but not meta
                jsonMeta = json.dumps(meta)
                jsonMeta = self._crypto.pubKeyEncrypt(
                    jsonMeta, asymPeer, encodedData=True).decode()
                data = self._crypto.pubKeyEncrypt(data,
                                                  asymPeer,
                                                  encodedData=True).decode()
                signature = self._crypto.pubKeyEncrypt(
                    signature, asymPeer, encodedData=True).decode()
                signer = self._crypto.pubKeyEncrypt(signer,
                                                    asymPeer,
                                                    encodedData=True).decode()
                onionrusers.OnionrUser(self, asymPeer, saveUser=True)
            else:
                raise onionrexceptions.InvalidPubkey(
                    asymPeer + ' is not a valid base32 encoded ed25519 key')

        # compile metadata
        metadata['meta'] = jsonMeta
        metadata['sig'] = signature
        metadata['signer'] = signer
        metadata['time'] = createTime

        # ensure expire is integer and of sane length
        if type(expire) is not type(None):
            assert len(str(int(expire))) < 14
            metadata['expire'] = expire

        # send block data (and metadata) to POW module to get tokenized block data
        if self.use_subprocess:
            payload = subprocesspow.SubprocessPOW(data, metadata, self).start()
        else:
            payload = onionrproofs.POW(metadata, data).waitForResult()
        if payload != False:
            try:
                retData = self.setData(payload)
            except onionrexceptions.DiskAllocationReached:
                logger.error(allocationReachedMessage)
                retData = False
            else:
                # Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult
                if self._utils.localCommand('/ping', maxWait=10) == 'pong!':
                    self._utils.localCommand('/waitforshare/' + retData,
                                             post=True,
                                             maxWait=5)
                    self.daemonQueueAdd('uploadBlock', retData)
                self.addToBlockDB(retData, selfInsert=True, dataSaved=True)
                self._utils.processBlockMetadata(retData)

        if retData != False:
            if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:
                events.event('insertdeniable', {
                    'content': plaintext,
                    'meta': plaintextMeta,
                    'hash': retData,
                    'peer': self._utils.bytesToStr(asymPeer)
                },
                             onionr=self.onionrInst,
                             threaded=True)
            else:
                events.event('insertblock', {
                    'content': plaintext,
                    'meta': plaintextMeta,
                    'hash': retData,
                    'peer': self._utils.bytesToStr(asymPeer)
                },
                             onionr=self.onionrInst,
                             threaded=True)
        return retData
Example #9
0
    def decrypt(self, encodedData=True):
        '''
            Decrypt a block, loading decrypted data into their vars
        '''

        if self.decrypted:
            return True
        retData = False
        core = self.getCore()
        # decrypt data
        if self.getHeader('encryptType') == 'asym':
            try:
                self.bcontent = core._crypto.pubKeyDecrypt(
                    self.bcontent, encodedData=encodedData)
                bmeta = core._crypto.pubKeyDecrypt(self.bmetadata,
                                                   encodedData=encodedData)
                try:
                    bmeta = bmeta.decode()
                except AttributeError:
                    # yet another bytes fix
                    pass
                self.bmetadata = json.loads(bmeta)
                self.signature = core._crypto.pubKeyDecrypt(
                    self.signature, encodedData=encodedData)
                self.signer = core._crypto.pubKeyDecrypt(
                    self.signer, encodedData=encodedData)
                self.bheader['signer'] = self.signer.decode()
                self.signedData = json.dumps(
                    self.bmetadata) + self.bcontent.decode()

                # Check for replay attacks
                try:
                    if self.core._utils.getEpoch() - self.core.getBlockDate(
                            self.hash) < 60:
                        assert self.core._crypto.replayTimestampValidation(
                            self.bmetadata['rply'])
                except (AssertionError, KeyError, TypeError) as e:
                    if not self.bypassReplayCheck:
                        # Zero out variables to prevent reading of replays
                        self.bmetadata = {}
                        self.signer = ''
                        self.bheader['signer'] = ''
                        self.signedData = ''
                        self.signature = ''
                        raise onionrexceptions.ReplayAttack(
                            'Signature is too old. possible replay attack')
                try:
                    assert self.bmetadata['forwardEnc'] is True
                except (AssertionError, KeyError) as e:
                    pass
                else:
                    try:
                        self.bcontent = onionrusers.OnionrUser(
                            self.getCore(),
                            self.signer).forwardDecrypt(self.bcontent)
                    except (onionrexceptions.DecryptionError,
                            nacl.exceptions.CryptoError) as e:
                        logger.error(str(e))
                        pass
            except nacl.exceptions.CryptoError:
                pass
                #logger.debug('Could not decrypt block. Either invalid key or corrupted data')
            except onionrexceptions.ReplayAttack:
                logger.warn('%s is possibly a replay attack' % (self.hash, ))
            else:
                retData = True
                self.decrypted = True
        else:
            logger.warn(
                'symmetric decryption is not yet supported by this API')
        return retData
Example #10
0
def insert_block(data: Union[str, bytes],
                 header: str = 'txt',
                 sign: bool = False,
                 encryptType: str = '',
                 symKey: str = '',
                 asymPeer: str = '',
                 meta: dict = {},
                 expire: Union[int, None] = None,
                 disableForward: bool = False,
                 signing_key: UserIDSecretKey = '') -> Union[str, bool]:
    """
    Create and insert a block into the network.

    encryptType must be specified to encrypt a block
    if expire is less than date, assumes seconds into future.
        if not assume exact epoch
    """
    our_private_key = crypto.priv_key
    our_pub_key = crypto.pub_key

    storage_counter = storagecounter.StorageCounter()

    allocationReachedMessage = 'Cannot insert block, disk allocation reached.'
    if storage_counter.is_full():
        logger.error(allocationReachedMessage)
        raise onionrexceptions.DiskAllocationReached

    if signing_key != '':
        # if it was specified to use an alternative private key
        our_private_key = signing_key
        our_pub_key = bytesconverter.bytes_to_str(
            crypto.cryptoutils.get_pub_key_from_priv(our_private_key))

    retData = False

    if type(data) is None:
        raise ValueError('Data cannot be none')

    createTime = epoch.get_epoch()

    dataNonce = bytesconverter.bytes_to_str(crypto.hashers.sha3_hash(data))
    try:
        with open(filepaths.data_nonce_file, 'r') as nonces:
            if dataNonce in nonces:
                return retData
    except FileNotFoundError:
        pass
    # record nonce
    with open(filepaths.data_nonce_file, 'a') as nonceFile:
        nonceFile.write(dataNonce + '\n')

    plaintext = data
    plaintextMeta = {}
    plaintextPeer = asymPeer

    retData = ''
    signature = ''
    signer = ''
    metadata = {}

    # metadata is full block metadata
    # meta is internal, user specified metadata

    # only use header if not set in provided meta

    meta['type'] = str(header)

    if encryptType in ('asym', 'sym'):
        metadata['encryptType'] = encryptType
    else:
        if not config.get('general.store_plaintext_blocks', True):
            raise onionrexceptions.InvalidMetadata(
                "Plaintext blocks are disabled, " +
                "yet a plaintext block was being inserted")
        if encryptType not in ('', None):
            raise onionrexceptions.InvalidMetadata(
                'encryptType must be asym or sym, or blank')

    try:
        data = data.encode()
    except AttributeError:
        pass

    if encryptType == 'asym':
        # Duplicate the time in encrypted messages to help prevent replays
        meta['rply'] = createTime
        if sign and asymPeer != our_pub_key:
            try:
                forwardEncrypted = onionrusers.OnionrUser(
                    asymPeer).forwardEncrypt(data)
                data = forwardEncrypted[0]
                meta['forwardEnc'] = True
                # Expire time of key. no sense keeping block after that
                expire = forwardEncrypted[2]
            except onionrexceptions.InvalidPubkey:
                pass
            if not disableForward:
                fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey()
                meta['newFSKey'] = fsKey
    jsonMeta = json.dumps(meta)
    plaintextMeta = jsonMeta
    if sign:
        signature = crypto.signing.ed_sign(jsonMeta.encode() + data,
                                           key=our_private_key,
                                           encodeResult=True)
        signer = our_pub_key

    if len(jsonMeta) > 1000:
        raise onionrexceptions.InvalidMetadata(
            'meta in json encoded form must not exceed 1000 bytes')

    # encrypt block metadata/sig/content
    if encryptType == 'sym':
        raise NotImplementedError("not yet implemented")
    elif encryptType == 'asym':
        if stringvalidators.validate_pub_key(asymPeer):
            # Encrypt block data with forward secrecy key first, but not meta
            jsonMeta = json.dumps(meta)
            jsonMeta = crypto.encryption.pub_key_encrypt(
                jsonMeta, asymPeer, encodedData=True).decode()
            data = crypto.encryption.pub_key_encrypt(data,
                                                     asymPeer,
                                                     encodedData=False)
            signature = crypto.encryption.pub_key_encrypt(
                signature, asymPeer, encodedData=True).decode()
            signer = crypto.encryption.pub_key_encrypt(
                signer, asymPeer, encodedData=True).decode()
            try:
                onionrusers.OnionrUser(asymPeer, saveUser=True)
            except ValueError:
                # if peer is already known
                pass
        else:
            raise onionrexceptions.InvalidPubkey(
                asymPeer + ' is not a valid base32 encoded ed25519 key')

    # compile metadata
    metadata['meta'] = jsonMeta
    if len(signature) > 0:  # I don't like not pattern
        metadata['sig'] = signature
        metadata['signer'] = signer
    metadata['time'] = createTime

    # ensure expire is integer and of sane length
    if type(expire) is not type(None):  # noqa
        if not len(str(int(expire))) < 20:
            raise ValueError(
                'expire must be valid int less than 20 digits in length')
        # if expire is less than date, assume seconds into future
        if expire < epoch.get_epoch():
            expire = epoch.get_epoch() + expire
        metadata['expire'] = expire

    # send block data (and metadata) to POW module to get tokenized block data
    payload = subprocesspow.SubprocessPOW(data, metadata).start()
    if payload != False:  # noqa
        try:
            retData = onionrstorage.set_data(payload)
        except onionrexceptions.DiskAllocationReached:
            logger.error(allocationReachedMessage)
            retData = False
        else:
            if disableForward:
                logger.warn(
                    f'{retData} asym encrypted block created w/o ephemerality')
            """
            Tell the api server through localCommand to wait for the daemon to
            upload this block to make statistical analysis more difficult
            """
            spawn(localcommand.local_command,
                  '/daemon-event/upload_event',
                  post=True,
                  is_json=True,
                  post_data={
                      'block': retData
                  }).get(timeout=5)
            coredb.blockmetadb.add.add_to_block_DB(retData,
                                                   selfInsert=True,
                                                   dataSaved=True)

            if expire is None:
                coredb.blockmetadb.update_block_info(
                    retData, 'expire', createTime + min(
                        onionrvalues.DEFAULT_EXPIRE,
                        config.get('general.max_block_age',
                                   onionrvalues.DEFAULT_EXPIRE)))
            else:
                coredb.blockmetadb.update_block_info(retData, 'expire', expire)

            blockmetadata.process_block_metadata(retData)

    if retData != False:  # noqa
        if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:
            events.event('insertdeniable', {
                'content': plaintext,
                'meta': plaintextMeta,
                'hash': retData,
                'peer': bytesconverter.bytes_to_str(asymPeer)
            },
                         threaded=True)
        else:
            events.event('insertblock', {
                'content': plaintext,
                'meta': plaintextMeta,
                'hash': retData,
                'peer': bytesconverter.bytes_to_str(asymPeer)
            },
                         threaded=True)

    spawn(localcommand.local_command,
          '/daemon-event/remove_from_insert_queue_wrapper',
          post=True,
          post_data={
              'block_hash': retData
          },
          is_json=True).get(timeout=5)
    return retData
Example #11
0
    def decrypt(self, encodedData=True):
        """
            Decrypt a block, loading decrypted data into their vars
        """

        if self.decrypted:
            return True
        retData = False
        # decrypt data
        if self.getHeader('encryptType') == 'asym':
            try:
                try:
                    self.bcontent = encryption.pub_key_decrypt(
                        self.bcontent, encodedData=encodedData)
                except (binascii.Error, ValueError) as e:
                    self.bcontent = encryption.pub_key_decrypt(
                        self.bcontent, encodedData=False)
                bmeta = encryption.pub_key_decrypt(self.bmetadata,
                                                   encodedData=encodedData)
                try:
                    bmeta = bmeta.decode()
                except AttributeError:
                    # yet another bytes fix
                    pass
                self.bmetadata = json.loads(bmeta)
                self.signature = encryption.pub_key_decrypt(
                    self.signature, encodedData=encodedData)
                self.signer = encryption.pub_key_decrypt(
                    self.signer, encodedData=encodedData)
                self.bheader['signer'] = self.signer.decode()
                self.signedData = json.dumps(
                    self.bmetadata).encode() + self.bcontent

                if not self.signer is None:
                    if not self.verifySig():
                        raise onionrexceptions.SignatureError(
                            "Block has invalid signature")

                # Check for replay attacks
                try:
                    if epoch.get_epoch() - blockmetadb.get_block_date(
                            self.hash) > 60:
                        if not cryptoutils.replay_validator(
                                self.bmetadata['rply']):
                            raise onionrexceptions.ReplayAttack
                except (AssertionError, KeyError, TypeError,
                        onionrexceptions.ReplayAttack) as e:
                    if not self.bypassReplayCheck:
                        # Zero out variables to prevent reading of replays
                        self.bmetadata = {}
                        self.signer = ''
                        self.bheader['signer'] = ''
                        self.signedData = ''
                        self.signature = ''
                        raise onionrexceptions.ReplayAttack(
                            'Signature is too old. possible replay attack')
                try:
                    if not self.bmetadata['forwardEnc']: raise KeyError
                except (AssertionError, KeyError) as e:
                    pass
                else:
                    try:
                        self.bcontent = onionrusers.OnionrUser(
                            self.signer).forwardDecrypt(self.bcontent)
                    except (onionrexceptions.DecryptionError,
                            nacl.exceptions.CryptoError) as e:
                        #logger.error(str(e))
                        pass
            except nacl.exceptions.CryptoError:
                pass
                #logger.debug('Could not decrypt block. Either invalid key or corrupted data')
            except onionrexceptions.ReplayAttack:
                logger.warn('%s is possibly a replay attack' % (self.hash, ))
            else:
                retData = True
                self.decrypted = True
        return retData
Example #12
0
 def test_is_friend(self):
     contact = crypto.generate()[0]
     contact = onionrusers.OnionrUser(contact, saveUser=True)
     self.assertFalse(contact.isFriend())
     contact.setTrust(1)
     self.assertTrue(contact.isFriend())
Example #13
0
 def test_users(self):
     keypair = crypto.generate()
     onionrusers.OnionrUser(keypair[0])
Example #14
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