def test_omemo_state_raises_runtime_error_if_not_connected(self, mockdb):
        mockdb.return_value = get_test_db_connection()

        ProfOmemoUser.reset()

        with pytest.raises(RuntimeError):
            _ = ProfOmemoState()
    def test_set_omemo_user(self):
        account = '*****@*****.**'
        fulljid = '[email protected]/profanity'

        ProfOmemoUser().account is None
        ProfOmemoUser().fulljid is None

        ProfOmemoUser.set_user(account, fulljid)

        ProfOmemoUser().account == account
        ProfOmemoUser().fulljid == fulljid
    def test_omemo_state_returns_singleton(self, mockdb):
        mockdb.return_value = get_test_db_connection()
        account = '*****@*****.**'
        fulljid = '[email protected]/profanity'

        ProfOmemoUser.set_user(account, fulljid)

        state = ProfOmemoState()

        new_state = ProfOmemoState()

        assert state == new_state
Esempio n. 4
0
def unpack_devicelist_info(stanza):
    xml = stanza_as_xml(stanza)

    try:
        sender_jid = xml.attrib.get('from')
    except AttributeError:
        sender_jid = None

    if sender_jid is None:
        event_node = xml.find('./{%s}event' % 'http://jabber.org/protocol/pubsub#event')
        try:
            sender_jid = event_node.attrib.get('from')
        except AttributeError:
            # device list info is result of a request for our own account
            sender_jid = ProfOmemoUser().account

    logger.debug('Found sender jid {0}'.format(sender_jid))

    item_list = xml.find('.//{%s}list' % NS_OMEMO)
    if item_list is not None:
        device_ids = [int(d.attrib['id']) for d in item_list]
    else:
        device_ids = []

    logger.debug('Found device ids {0}'.format(device_ids))
    msg_dict = {'from': sender_jid,
                'devices': device_ids}

    return msg_dict
def prof_init(version, status, account_name, fulljid):
    log.info('prof_init() called')
    synopsis = [
        '/omemo',
        '/omemo on|off',
        '/omemo start|end [jid]',
        '/omemo set'
        '/omemo status',
        '/omemo account',
        '/omemo fulljid',
        '/omemo fingerprints',
        '/omemo show_devices',
        '/omemo reset_devicelist'
    ]

    description = 'Plugin to enable OMEMO encryption'
    args = [
        ['on|off', 'Enable/Disable the Profanity OMEMO Plugin'],
        ['start|end <jid>', ('Start an OMEMO based conversation with <jid> '
                             'window or current window.')],
        ['set', 'Set Settings like Message Prefix'],
        ['status', 'Display the current Profanity OMEMO Plugin status.'],
        ['fingerprints <jid>', 'Display the known fingerprints for <jid>'],
        ['account', 'Show current account name'],
        ['reset_devicelist <jid>', 'Manually reset a contacts devicelist.'],
        ['fulljid', 'Show current <full-jid>']
    ]

    examples = []

    # ensure the plugin is not registered if python-omemo is not available
    prof.register_command('/omemo', 1, 3,
                          synopsis, description, args, examples, _parse_args)

    prof.completer_add('/omemo', ['on', 'off', 'status', 'start', 'end', 'set'
                                  'account', 'fulljid', 'show_devices',
                                  'reset_devicelist', 'fingerprints'])

    prof.completer_add('/omemo set', ['message_prefix'])

    # set user and init omemo only if account_name and fulljid provided
    if account_name is not None and fulljid is not None:
        ProfOmemoUser.set_user(account_name, fulljid)
        _init_omemo()
    else:
        log.warning('No User logged in on plugin.prof_init()')
    def test_encrypt_stanza(self, mockdb):
        pytest.skip('Work in Progress')
        mockdb.return_value = get_test_db_connection()

        current_user = '******'
        ProfOmemoUser.set_user(current_user, current_user + '/profanity')

        recipient = '*****@*****.**'
        omemo_state = ProfOmemoState()
        omemo_state.set_devices(recipient, [4711, 995746])

        raw_stanza = ('<message id="msg0x001" to="{0}" type="chat">'
                      '<body>Hollo</body>'
                      '<active xmlns="http://jabber.org/protocol/chatstates"/>'
                      '</message>').format(recipient)

        encrypted = xmpp.encrypt_stanza(raw_stanza)
Esempio n. 7
0
def prof_init(version, status, account_name, fulljid):
    log.info('prof_init() called')
    synopsis = [
        '/omemo',
        '/omemo on|off',
        '/omemo start|end [jid]',
        '/omemo set'
        '/omemo status',
        '/omemo account',
        '/omemo fulljid',
        '/omemo fingerprints',
        '/omemo show_devices',
        '/omemo reset_devicelist'
    ]

    description = 'Plugin to enable OMEMO encryption'
    args = [
        ['on|off', 'Enable/Disable the Profanity OMEMO Plugin'],
        ['start|end <jid>', ('Start an OMEMO based conversation with <jid> '
                             'window or current window.')],
        ['set', 'Set Settings like Message Prefix'],
        ['status', 'Display the current Profanity OMEMO Plugin status.'],
        ['fingerprints <jid>', 'Display the known fingerprints for <jid>'],
        ['account', 'Show current account name'],
        ['reset_devicelist <jid>', 'Manually reset a contacts devicelist.'],
        ['fulljid', 'Show current <full-jid>']
    ]

    examples = []

    # ensure the plugin is not registered if python-omemo is not available
    prof.register_command('/omemo', 1, 3,
                          synopsis, description, args, examples, _parse_args)

    prof.completer_add('/omemo', ['on', 'off', 'status', 'start', 'end', 'set'
                                  'account', 'fulljid', 'show_devices',
                                  'reset_devicelist', 'fingerprints'])

    prof.completer_add('/omemo set', ['message_prefix'])

    # set user and init omemo only if account_name and fulljid provided
    if account_name is not None and fulljid is not None:
        ProfOmemoUser.set_user(account_name, fulljid)
        _init_omemo()
    else:
        log.warning('No User logged in on plugin.prof_init()')
    def test_encrypt_stanza(self, mockdb):
        pytest.skip('Work in Progress')
        mockdb.return_value = get_test_db_connection()

        current_user = '******'
        ProfOmemoUser.set_user(current_user, current_user + '/profanity')

        recipient = '*****@*****.**'
        omemo_state = ProfOmemoState()
        omemo_state.set_devices(recipient, [4711, 995746])

        raw_stanza = ('<message id="msg0x001" to="{0}" type="chat">'
                        '<body>Hollo</body>'
                        '<active xmlns="http://jabber.org/protocol/chatstates"/>'
                      '</message>'
                      ).format(recipient)

        encrypted = xmpp.encrypt_stanza(raw_stanza)
    def test_reset_omemo_user(self):
        account = '*****@*****.**'
        fulljid = '[email protected]/profanity'

        ProfOmemoUser.set_user(account, fulljid)

        ProfOmemoUser().account == account
        ProfOmemoUser().fulljid == fulljid

        ProfOmemoUser.reset()

        ProfOmemoUser().account is None
        ProfOmemoUser().fulljid is None
    def test_unpack_devicelist_request_result_for_own_devices(self, mockdb):
        mockdb.return_value = get_test_db_connection()
        test_stanza = (
            '<iq id="0x011" to="[email protected]/profanity" type="result">'
            '<pubsub xmlns="http://jabber.org/protocol/pubsub">'
            '<items node="{0}">'
            '<item id="1">'
            '<list xmlns="{1}">'
            '<device id="1426586702"/>'
            '</list>'
            '</item>'
            '</items>'
            '</pubsub>'
            '</iq>').format(NS_DEVICE_LIST, NS_OMEMO)

        current_user = '******'
        ProfOmemoUser.set_user(current_user, current_user + '/profanity')

        msg_dict = xmpp.unpack_devicelist_info(test_stanza)
        expected_msg_dict = {'from': current_user, 'devices': [1426586702]}

        assert msg_dict == expected_msg_dict
    def test_unpack_devicelist_request_result_for_own_devices(self, mockdb):
        mockdb.return_value = get_test_db_connection()
        test_stanza = ('<iq id="0x011" to="[email protected]/profanity" type="result">'
                           '<pubsub xmlns="http://jabber.org/protocol/pubsub">'
                               '<items node="{0}">'
                                '<item id="1">'
                                    '<list xmlns="{1}">'
                                        '<device id="1426586702"/>'
                                    '</list>'
                                '</item>'
                               '</items>'
                           '</pubsub>'
                       '</iq>'
        ).format(NS_DEVICE_LIST, NS_OMEMO)

        current_user = '******'
        ProfOmemoUser.set_user(current_user, current_user + '/profanity')

        msg_dict = xmpp.unpack_devicelist_info(test_stanza)
        expected_msg_dict = {'from': current_user,
                             'devices': [1426586702]}

        assert msg_dict == expected_msg_dict
Esempio n. 12
0
def _init_omemo():
    account = ProfOmemoUser().account
    if account:
        # subscribe to devicelist updates
        log.info('Adding Disco Feature {0}.'.format(NS_DEVICE_LIST_NOTIFY))
        # subscribe to device list updates
        prof.disco_add_feature(NS_DEVICE_LIST_NOTIFY)

        log.debug('Announcing own bundle info.')
        _announce_own_devicelist()  # announce own device list
        _announce_own_bundle()  # announce own bundle

        # we query our own devices to add possible other devices we own
        _query_device_list(account)
Esempio n. 13
0
def encrypt_stanza(stanza):
    logger.debug('Enrypting stanza {0}'.format(stanza))
    logger.debug('Convert stanza to xml.')
    msg_xml = stanza_as_xml(stanza)
    fulljid = msg_xml.attrib.get('from', ProfOmemoUser().fulljid)
    logger.debug('Sender: {0}'.format(fulljid))
    jid = msg_xml.attrib['to']
    account, resource = jid.rsplit('/', 1)
    logger.debug('Recipient {0} [{1}]'.format(account, resource))
    msg_id = msg_xml.attrib['id']
    logger.debug('Message ID: {0}'.format(msg_id))
    body_node = msg_xml.find('.//body')
    plaintext = body_node.text
    logger.debug('Message: {0}'.format(plaintext))

    try:
        plaintext = plaintext.encode('utf-8')
    except:
        pass

    return create_encrypted_message(fulljid, account, plaintext, msg_id=msg_id)
    def test_initial_user_is_not_set(self):
        omemo_user = ProfOmemoUser()

        assert omemo_user.account is None
        assert omemo_user.fulljid is None
 def test_prof_omemo_user_is_singleton(self):
     assert ProfOmemoUser().account == ProfOmemoUser().account
     assert ProfOmemoUser().fulljid == ProfOmemoUser().fulljid
Esempio n. 16
0
def prof_on_disconnect(account_name, fulljid):
    log.debug('prof_on_disconnect() called')
    ProfOmemoUser.reset()
Esempio n. 17
0
def prof_on_shutdown():
    log.debug('prof_on_shutdown() called')
    ProfOmemoUser.reset()
def prof_on_disconnect(account_name, fulljid):
    log.debug('prof_on_disconnect() called')
    ProfOmemoUser.reset()
Esempio n. 19
0
def prof_on_connect(account_name, fulljid):
    log.debug('prof_on_connect() called')
    ProfOmemoUser.set_user(account_name, fulljid)
    _init_omemo()
Esempio n. 20
0
def prof_on_message_stanza_receive(stanza):
    stanza = ensure_unicode_stanza(stanza)

    log.info('Received Message: {0}'.format(stanza))
    if xmpp.is_devicelist_update(stanza):
        log.info('Device List update detected.')
        try:
            _handle_devicelist_update(stanza)
        except:
            log.exception('Failed to handle devicelist update.')

        return False

    if xmpp.is_encrypted_message(stanza):
        log.info('Received OMEMO encrypted message.')
        omemo_state = ProfOmemoState()

        try:
            msg_dict = xmpp.unpack_encrypted_stanza(stanza)
            sender = msg_dict['sender_jid']
            resource = msg_dict['sender_resource']
            sender_fulljid = sender + '/' + resource

            if sender_fulljid == ProfOmemoUser().fulljid:
                log.debug('Skipping own Message.')
                return False

            try:
                plain_msg = omemo_state.decrypt_msg(msg_dict)
            except Exception:
                log.exception('Could not decrypt Message.')
                return False

            if plain_msg is None:
                log.error('Could not decrypt Message')
                return True

            if plain_msg:
                # only mark the message if it was an OMEMO encrypted message
                try:
                    message_char = _get_omemo_message_char()
                    log.debug('Set incoming Message Character: {0}'.format(
                        message_char))
                    prof.chat_set_incoming_char(sender, message_char)
                    prof.incoming_message(sender, resource, plain_msg)
                finally:
                    prof.chat_unset_incoming_char(sender)

                # if this was the first OMEMO encrypted message received by
                # the sender (a.k.a. whenever profanity opens a new chat window
                # for a recipient), we automatically respond with OMEMO encrypted
                # messages. If encryption is turned off later by the user,
                # we respect that.
                if not ProfActiveOmemoChats.account_is_active(sender):
                    if not ProfActiveOmemoChats.account_is_deactivated(sender):
                        _start_omemo_session(sender)

            return False

        except Exception:
            # maybe not OMEMO encrypted, profanity will take care then
            log.exception('Could not handle encrypted message.')

    return True
 def teardown_method(self, test_method):
     ProfOmemoUser.reset()
     ProfActiveOmemoChats.reset()
Esempio n. 22
0
def _query_bundle_info_for(recipient, deviceid):
    log.info('Query Bundle for {0}:{1}'.format(recipient, deviceid))
    account = ProfOmemoUser().account
    stanza = xmpp.create_bundle_request_stanza(account, recipient, deviceid)
    send_stanza(stanza)
Esempio n. 23
0
def _query_device_list(contact_jid):
    log.info('Query Device list for {0}'.format(contact_jid))
    fulljid = ProfOmemoUser().fulljid
    query_msg = xmpp.create_devicelist_query_msg(fulljid, contact_jid)
    send_stanza(query_msg)
Esempio n. 24
0
def _announce_own_devicelist():
    fulljid = ProfOmemoUser().fulljid
    query_msg = xmpp.create_devicelist_update_msg(fulljid)
    log.info('Announce own device list.')
    log.info(query_msg)
    send_stanza(query_msg)
def prof_on_unload():
    log.debug('prof_on_unload() called')
    ProfOmemoUser.reset()
def prof_on_shutdown():
    log.debug('prof_on_shutdown() called')
    ProfOmemoUser.reset()
    def setup_method(self, test_method):
        account = '*****@*****.**'
        fulljid = '[email protected]/profanity'

        ProfOmemoUser.set_user(account, fulljid)
Esempio n. 28
0
def _parse_args(arg1=None, arg2=None, arg3=None):
    """ Parse arguments given in command window

    arg1: start || end
    arg2: muc || jid (optional)

    Starts or ends an encrypted chat session

    """
    account = ProfOmemoUser().account
    fulljid = ProfOmemoUser().fulljid

    if arg1 == 'on':
        _set_omemo_enabled_setting(True)

    elif arg1 == 'off':
        _set_omemo_enabled_setting(False)

    elif arg1 == 'start':
        # ensure we are in a chat window

        current_recipient = prof.get_current_recipient()

        if not current_recipient and arg2 != current_recipient:
            log.info('Opening Chat Window for {0}'.format(arg2))
            prof.send_line('/msg {0}'.format(arg2))

        recipient = arg2 or current_recipient
        if recipient:
            log.info('Start OMEMO session with: {0}'.format(recipient))
            _start_omemo_session(recipient)

    elif arg1 == 'end':
        # ensure we are in a chat window
        jid = arg2 or prof.get_current_muc() or prof.get_current_recipient()
        log.info('Ending OMEMO session with: {0}'.format(jid))
        if jid:
            _end_omemo_session(jid)

    elif arg1 == 'set':
        if arg2 == 'message_prefix':
            if arg3 is not None:
                _set_omemo_message_char(arg3)

    elif arg1 == 'account':
        prof.cons_show('Account: {0}'.format(account))

    elif arg1 == 'status':
        enabled = _get_omemo_enabled_setting()
        prof.cons_show('OMEMO Plugin Enabled: {0}'.format(enabled))

    elif arg1 == 'fulljid':
        prof.cons_show('Current JID: {0}'.format(fulljid))

    elif arg1 == 'show_devices' and arg2 is not None:
        account = arg2
        omemo_state = ProfOmemoState()
        prof.cons_show('Requesting Devices...')
        devices = omemo_state.device_list_for(account)
        prof.cons_show('Devices: {0}'.format(devices))
        prof.cons_show('{0}: {1}'.format(account, ', '.join(devices)))

    elif arg1 == 'reset_devicelist' and arg2 is not None:
        contact_jid = arg2
        if contact_jid != ProfOmemoUser.account:
            omemo_state = ProfOmemoState()
            omemo_state.set_devices(contact_jid, [])
            _query_device_list(contact_jid)

    elif arg1 == 'fingerprints':
        if arg2:
            contact_jid = query_jid = arg2
        else:
            # The local account is identified as '-1' in the OMEMO database
            contact_jid = ProfOmemoUser.account
            query_jid = '-1'
        omemo_state = ProfOmemoState()

        fingerprints = omemo_state.getFingerprints(query_jid)
        prof.cons_show('Fingerprints for account: {0}'.format(contact_jid))

        for record in fingerprints:
            _id, recipient_id, public_key, trust = record
            fpr = binascii.hexlify(public_key)
            fpr = human_hash(fpr[2:])

            prof.cons_show(' {0}'.format(fpr))

    else:
        prof.cons_show('Argument {0} not supported.'.format(arg1))
 def teardown_method(self, test_method):
     ProfActiveOmemoChats.reset()
     ProfOmemoUser.reset()
Esempio n. 30
0
def prof_on_unload():
    log.debug('prof_on_unload() called')
    ProfOmemoUser.reset()
    def setup_method(self, test_method):
        account = '*****@*****.**'
        fulljid = '[email protected]/profanity'

        ProfOmemoUser.set_user(account, fulljid)
def prof_on_connect(account_name, fulljid):
    log.debug('prof_on_connect() called')
    ProfOmemoUser.set_user(account_name, fulljid)
    _init_omemo()