...
 
Commits (2)
__pycache__/
\ No newline at end of file
2.5.6 / 2018-01-26
- Fix decrypting MAM MUC messages
2.5.5 / 2017-12-17
- Bug fix
2.5.4 / 2017-12-16
- Bug fix
2.5.3 / 2017-12-10
- Bug fix
2.5.2 / 2017-12-10
- Small refactoring
2.5.1 / 2017-11-21
- Bug fix
2.5.0 / 2017-11-20
- Add MAM for MUC decryption
2.4.3 / 2017-11-15
- Use Gajim API to announce caps
2.4.2 / 2017-11-15
- Query devicelists for contacts where we have none, this makes us a bit more independent from PEP
- Fix encrypting in Groupchats
- Improve error messages
2.4.1 / 2017-11-12
- Bug fix
2.4.0 / 2017-11-10
- Refactoring
2.3.8 / 2017-10-07
- Bug Fixes
2.3.7 / 2017-08-26
- Query only the most recent PEP items
2.3.6 / 2017-08-21
- Adapt to Gaim beeing now a Package
2.3.5 / 2017-08-07
- Support 12bit IVs on httpupload files
2.3.4 / 2017-06-10
- Bugfixes
- Some Refactoring
2.3.3 / 2017-06-09
- Move encryption logic for files from the HTTPUploadPlugin to the OMEMOPlugin
2.3.2 / 2017-06-02
- Adapt to patches regarding LMC in Gajim
2.3.1 / 2017-05-23
- Bugfixes
2.3.0 / 2017-05-07
- Make plugin compatible with Gajims encryption API
2.2.1 / 2017-04-15
- Recognize aesgcm uri scheme
2.2.0 / 2017-04-06
- Add auth tag to key instead of payload
- Support decryption of aesgcm:// uri scheme
- Make python-cryptography mandatory
- small bugfixes
2.1.0 / 2017-03-26
- Add file decryption
2.0.4 / 2017-03-01
- Use correct tag name for EME
2.0.3 / 2017-02-28
- Set an inactive device active again after receiving a message from it
2.0.2 / 2017-02-28
- Fix a bug when publishing devices
- Fix copying fingerprint
- Fix layout issue
- Dont handle type 'normal' messages
2.0.1 / 2017-01-14
- Better XEP Compliance
- Bugfixes
2.0.0 / 2016-12-04
- Port Plugin from GTK2
This diff is collapsed.
......@@ -35,6 +35,7 @@ else:
log = logging.getLogger('gajim.plugin_system.omemo')
def aes_decrypt(_key, iv, payload):
""" Use AES128 GCM with the given key and iv to decrypt the payload. """
if len(_key) >= 32:
......
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0384: OMEMO Encryption
import logging
import time
from gi.repository import Gtk
from gajim.common import app
from gajim.common.const import DialogButton, ButtonAction
from gajim.gtk import NewConfirmationDialog
from openpgp.modules.util import Trust
log = logging.getLogger('gajim.plugin_system.omemo.keydialog')
TRUST_DATA = {
Trust.NOT_TRUSTED: ('dialog-error-symbolic',
_('Not Trusted'),
'error-color'),
Trust.UNKNOWN: ('security-low-symbolic',
_('Not Decided'),
'warning-color'),
Trust.BLIND: ('security-medium-symbolic',
_('Blind Trust'),
'openpgp-dark-success-color'),
Trust.VERIFIED: ('security-high-symbolic',
_('Verified'),
'success-color')
}
class KeyDialog(Gtk.Dialog):
def __init__(self, account, jid, transient):
flags = Gtk.DialogFlags.DESTROY_WITH_PARENT
super().__init__(_('Public Keys for %s') % jid, None, flags)
self.set_transient_for(transient)
self.set_resizable(True)
self.set_default_size(500, 300)
self.get_style_context().add_class('openpgp-key-dialog')
self.con = app.connections[account]
self._listbox = Gtk.ListBox()
self._listbox.set_selection_mode(Gtk.SelectionMode.NONE)
self._scrolled = Gtk.ScrolledWindow()
self._scrolled.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC)
self._scrolled.add(self._listbox)
box = self.get_content_area()
box.pack_start(self._scrolled, True, True, 0)
keys = self.con.get_module('OpenPGP').get_keys(jid, only_trusted=False)
for key in keys:
log.info('Load: %s', key.fingerprint)
self._listbox.add(KeyRow(key))
self.show_all()
class KeyRow(Gtk.ListBoxRow):
def __init__(self, key):
Gtk.ListBoxRow.__init__(self)
self.set_activatable(False)
self._dialog = self.get_toplevel()
self.key = key
box = Gtk.Box()
box.set_spacing(12)
self._trust_button = TrustButton(self)
box.add(self._trust_button)
label_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
fingerprint = Gtk.Label(
label=self._format_fingerprint(key.fingerprint))
fingerprint.get_style_context().add_class('openpgp-mono')
if not key.active:
fingerprint.get_style_context().add_class('openpgp-inactive-color')
fingerprint.set_selectable(True)
fingerprint.set_halign(Gtk.Align.START)
fingerprint.set_valign(Gtk.Align.START)
fingerprint.set_hexpand(True)
label_box.add(fingerprint)
date = Gtk.Label(label=self._format_timestamp(key.timestamp))
date.set_halign(Gtk.Align.START)
date.get_style_context().add_class('openpgp-mono')
if not key.active:
date.get_style_context().add_class('openpgp-inactive-color')
label_box.add(date)
box.add(label_box)
self.add(box)
self.show_all()
def delete_fingerprint(self, *args):
def _remove():
self.get_parent().remove(self)
self.key.delete()
self.destroy()
buttons = {
Gtk.ResponseType.CANCEL: DialogButton('Cancel'),
Gtk.ResponseType.OK: DialogButton('Delete',
_remove,
ButtonAction.DESTRUCTIVE),
}
NewConfirmationDialog(
_('Delete Public Key'),
_('This will permanently delete this public key'),
buttons,
transient_for=self.get_toplevel())
def set_trust(self, trust):
icon_name, tooltip, css_class = TRUST_DATA[trust]
image = self._trust_button.get_child()
image.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
image.get_style_context().add_class(css_class)
@staticmethod
def _format_fingerprint(fingerprint):
fplen = len(fingerprint)
wordsize = fplen // 8
buf = ''
for w in range(0, fplen, wordsize):
buf += '{0} '.format(fingerprint[w:w + wordsize])
return buf.rstrip()
@staticmethod
def _format_timestamp(timestamp):
return time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(timestamp))
class TrustButton(Gtk.MenuButton):
def __init__(self, row):
Gtk.MenuButton.__init__(self)
self._row = row
self._css_class = ''
self.set_popover(TrustPopver(row))
self.update()
def update(self):
icon_name, tooltip, css_class = TRUST_DATA[self._row.key.trust]
image = self.get_child()
image.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
# remove old color from icon
image.get_style_context().remove_class(self._css_class)
if not self._row.key.active:
css_class = 'openpgp-inactive-color'
tooltip = '%s - %s' % (_('Inactive'), tooltip)
image.get_style_context().add_class(css_class)
self._css_class = css_class
self.set_tooltip_text(tooltip)
class TrustPopver(Gtk.Popover):
def __init__(self, row):
Gtk.Popover.__init__(self)
self._row = row
self._listbox = Gtk.ListBox()
self._listbox.set_selection_mode(Gtk.SelectionMode.NONE)
if row.key.trust != Trust.VERIFIED:
self._listbox.add(VerifiedOption())
if row.key.trust != Trust.NOT_TRUSTED:
self._listbox.add(NotTrustedOption())
self._listbox.add(DeleteOption())
self.add(self._listbox)
self._listbox.show_all()
self._listbox.connect('row-activated', self._activated)
self.get_style_context().add_class('openpgp-trust-popover')
def _activated(self, listbox, row):
self.popdown()
if row.type_ is None:
self._row.delete_fingerprint()
else:
self._row.key.trust = row.type_
self.get_relative_to().update()
self.update()
def update(self):
self._listbox.foreach(lambda row: self._listbox.remove(row))
if self._row.key.trust != Trust.VERIFIED:
self._listbox.add(VerifiedOption())
if self._row.key.trust != Trust.NOT_TRUSTED:
self._listbox.add(NotTrustedOption())
self._listbox.add(DeleteOption())
class MenuOption(Gtk.ListBoxRow):
def __init__(self):
Gtk.ListBoxRow.__init__(self)
box = Gtk.Box()
box.set_spacing(6)
image = Gtk.Image.new_from_icon_name(self.icon,
Gtk.IconSize.MENU)
label = Gtk.Label(label=self.label)
image.get_style_context().add_class(self.color)
box.add(image)
box.add(label)
self.add(box)
self.show_all()
class VerifiedOption(MenuOption):
type_ = Trust.VERIFIED
icon = 'security-high-symbolic'
label = _('Verified')
color = 'success-color'
def __init__(self):
MenuOption.__init__(self)
class NotTrustedOption(MenuOption):
type_ = Trust.NOT_TRUSTED
icon = 'dialog-error-symbolic'
label = _('Not Trusted')
color = 'error-color'
def __init__(self):
MenuOption.__init__(self)
class DeleteOption(MenuOption):
type_ = None
icon = 'user-trash-symbolic'
label = _('Delete')
color = ''
def __init__(self):
MenuOption.__init__(self)
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0373: OpenPGP for XMPP
import logging
import nbxmpp
from gajim.common import app
from gajim.common.exceptions import StanzaMalformed
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
from openpgp.modules import util
log = logging.getLogger('gajim.plugin_system.omemo.pep')
# Module name
name = 'OMEMODevicelist'
zeroconf = False
class OMEMODevicelistData(AbstractPEPData):
type_ = 'omemo-devicelist'
def __init__(self, devicelist):
self._pep_specific_data = devicelist
self.data = devicelist
class OMEMODevicelist(AbstractPEPModule):
'''
<item>
<list xmlns='eu.siacs.conversations.axolotl'>
<device id='12345' />
<device id='4223' />
</list>
</item>
'''
name = 'omemo-devicelist'
namespace = util.NS_DEVICE_LIST
pep_class = OMEMODevicelistData
store_publish = True
_log = log
def __init__(self, con):
AbstractPEPModule.__init__(self, con, con.name)
self.handlers = []
def _extract_info(self, item):
list_ = item.getTag('list', namespace=util.NS_OMEMO)
if list_ is None:
raise StanzaMalformed('No list node')
device_list = list_.getTags('device')
devices = []
for device in device_list:
id_ = device.getAttr('id')
if id_ is None:
raise StanzaMalformed('No id for device found')
devices.append(int(id_))
return devices
def _notification_received(self, jid, devicelist):
con = app.connections[self._account]
con.get_module('OMEMO').device_list_received(devicelist.data,
jid.getStripped())
def _build_node(self, devicelist):
list_node = nbxmpp.Node('list', {'xmlns': util.NS_OMEMO})
if devicelist is None:
return list_node
for device in devicelist:
list_node.addChild('device', attrs={'id': device})
return list_node
def get_instance(*args, **kwargs):
return OMEMODevicelist(*args, **kwargs), 'OMEMODevicelist'
This diff is collapsed.
import logging
import omemo
from .storage import SQLiteDatabase
from omemo.util import generateDeviceID
log = logging.getLogger('gajim.plugin_system.omemo.session_manager')
class KeepingOTPKPolicy(omemo.OTPKPolicy):
@staticmethod
def decideOTPK(preKeyMessages):
# Always keep the OTPK.
# This is the unsafest behaviour possible and should
# be avoided at all costs.
return True
class SessionManager:
def __init__(self, own_jid, db_path):
# Database Inferface
self._store = SQLiteDatabase(db_path)
self._store = SQLiteDatabase(db_path, own_jid)
# OmemoSessionManager
self._sm = omemo.SessionManager(own_jid, self._store, generateDeviceID())
self._sm = omemo.SessionManager.create(self._store,
KeepingOTPKPolicy(),
own_jid,
self._store.own_device_id)
def build_session(self, bundle):
self._store.createSession()
......@@ -23,13 +39,13 @@ class SessionManager:
return self._sm.getDevices(jid)
def get_own_device_id(self):
return self._sm.my_device_id
return self._store.own_device_id
def get_own_devices(self):
devices = self._sm.getDevices()['active']
if self._sm.my_device_id not in devices:
if self.get_own_device_id() not in devices:
devices = list(devices)
devices.append(self._sm.my_device_id)
devices.append(self.get_own_device_id())
return devices
def get_devices_without_session(self, jid):
......@@ -45,13 +61,30 @@ class SessionManager:
def clear_devicelist(self):
return
def encrypt(self, jids, plaintext, bundles=None, devices=None, callback=None):
return self._sm.encryptMessage(jids, plaintext, bundles, devices, callback)
def encrypt(self, jids, plaintext,
bundles=None, devices=None, callback=None):
return self._sm.encryptMessage(
jids, plaintext, bundles, devices, callback)
def decrypt(self, msg_dict):
own_id = self.get_own_device_id()
if msg_dict['sid'] == own_id:
log.info('Received previously sent message by us')
return
if own_id not in msg_dict['keys']:
log.warning('OMEMO message does not contain our device key')
return
iv = msg_dict['iv']
sid = msg_dict['sid']
jid = msg_dict['sender_jid']
payload = msg_dict['payload']
encrypted_key, prekey = msg_dict['keys'][own_id]
def decrypt(self, jid, sid, iv, message, payload, prekey):
if prekey:
return self._sm.decryptMessage(jid, sid, iv, message, payload)
return self._sm.decryptPreKeyMessage(jid, sid, iv, message, payload)
return self._sm.decryptMessage(
jid, sid, iv, encrypted_key, prekey, payload)
def buid_session(self, jid, device, bundle, callback):
return self._sm.buildSession(jid, device, bundle, callback)
......@@ -19,7 +19,6 @@
import logging
import time
import os
from base64 import b64encode
from axolotl.ecc.djbec import DjbECPublicKey
......
......@@ -24,7 +24,10 @@ from collections import namedtuple
from omemo.storage import Storage
from omemo.x3dhdoubleratchet import X3DHDoubleRatchet
import json
from omemo.signal.doubleratchet.doubleratchet import DoubleRatchet
from omemo.util import generateDeviceID
from .db_helpers import user_version
......@@ -34,13 +37,13 @@ log = logging.getLogger('gajim.plugin_system.omemo.db')
class SQLiteDatabase(Storage):
""" SQLite Database """
def __init__(self, db_path):
sqlite3.register_adapter(X3DHDoubleRatchet, self._pickle_object)
sqlite3.register_adapter(DoubleRatchet, self._pickle_object)
def __init__(self, db_path, own_bare_jid):
sqlite3.register_adapter(dict, self._json_dumps)
sqlite3.register_adapter(dict, self._json_dumps)
sqlite3.register_converter("omemo_state", self._unpickle_object)
sqlite3.register_converter("omemo_session", self._unpickle_object)
self._con = sqlite3.connect(db_path,
sqlite3.register_converter("omemo_state", self._json_loads)
sqlite3.register_converter("omemo_session", self._json_loads)
self._con = sqlite3.connect(db_path / 'omemo.db',
detect_types=sqlite3.PARSE_DECLTYPES)
self._con.text_factory = bytes
self._con.row_factory = self.namedtuple_factory
......@@ -48,8 +51,16 @@ class SQLiteDatabase(Storage):
self._migrate_database()
self._con.execute("PRAGMA synchronous=FULL;")
self._con.commit()
self._own_jid = own_bare_jid
self._own_device_id = None
@property
def own_device_id(self):
if self._own_device_id is None:
self._own_device_id = self._load_own_device_id()
return self._own_device_id
def _create_database(self):
if user_version(self._con) == 0:
create_tables = '''
......@@ -85,12 +96,12 @@ class SQLiteDatabase(Storage):
pass
@staticmethod
def _pickle_object(session):
return pickle.dumps(session, pickle.HIGHEST_PROTOCOL)
def _json_dumps(session):
return json.dumps(session)
@staticmethod
def _unpickle_object(session):
return pickle.loads(session)
def _json_loads(session):
return json.loads(session)
@staticmethod
def namedtuple_factory(cursor, row):
......@@ -99,32 +110,50 @@ class SQLiteDatabase(Storage):
named_row = Row(*row)
return named_row
def loadState(self):
def _load_own_device_id(self):
q = 'SELECT device_id FROM state'
result = self._con.execute(q).fetchone()
if result is None:
log.info('Generate new device id')
device_id = generateDeviceID()
else:
device_id = result.device_id
log.info('Load own device id: %s', device_id)
return device_id
def loadOwnData(self, callback):
return {'own_bare_jid': self._own_jid,
'own_device_id': self.own_device_id}
def storeOwnData(self, *args):
# useless
return
def loadState(self, callback):
log.info('Load State')
q = 'SELECT device_id, state FROM state'
q = 'SELECT state FROM state'
result = self._con.execute(q).fetchone()
if result is not None:
self._own_device_id = result.device_id
return {'state': result.state, 'device_id': result.device_id}
return result.state
def storeState(self, state, device_id):
def storeState(self, callback, state):
log.info('Store State')
self._own_device_id = device_id
q = 'INSERT OR REPLACE INTO state(device_id, state) VALUES(?, ?)'
self._con.execute(q, (device_id, state))
q = 'INSERT OR REPLACE INTO state(state) VALUES(?)'
self._con.execute(q, (state,))
self._con.commit()
def loadSession(self, jid, device_id):
def loadSession(self, callback, bare_jid, device_id):
log.info('Load Session')
q = 'SELECT session FROM sessions WHERE jid = ? AND device_id = ?'
result = self._con.execute(q, (jid, device_id)).fetchone()
result = self._con.execute(q, (bare_jid, device_id)).fetchone()
if result is not None:
return result.session
def storeSession(self, jid, device_id, session):
log.info('Store Session: %s, %s', jid, device_id)
def storeSession(self, callback, bare_jid, device_id, session):
log.info('Store Session: %s, %s', bare_jid, device_id)
q = 'UPDATE sessions SET session = ? WHERE jid= ? AND device_id = ?'
self._con.execute(q, (session, jid, device_id))
self._con.execute(q, (session, bare_jid, device_id))
self._con.commit()
def createSession(self, jid, device_id, session):
......@@ -134,37 +163,37 @@ class SQLiteDatabase(Storage):
self._con.execute(q, (jid, device_id, session))
self._con.commit()
def loadActiveDevices(self, jid):
return self.loadDevices(jid, 1)
def loadActiveDevices(self, callback, bare_jid):
return self.loadDevices(bare_jid, 1)
def loadInactiveDevices(self, jid):
return self.loadDevices(jid, 0)
def loadInactiveDevices(self, callback, bare_jid):
return self.loadDevices(bare_jid, 0)
def loadDevices(self, jid, active):
def loadDevices(self, bare_jid, active):
q = 'SELECT device_id FROM sessions WHERE jid = ? AND active = ?'
result = self._con.execute(q, (jid, active)).fetchall()
result = self._con.execute(q, (bare_jid, active)).fetchall()
if result:
devices = [row.device_id for row in result]
state = 'Active' if active else 'Inactive'
log.info('Load %s Devices: %s, %s', state, jid, devices)
log.info('Load %s Devices: %s, %s', state, bare_jid, devices)
return devices
return []
def storeActiveDevices(self, jid, devices):
def storeActiveDevices(self, callback, bare_jid, devices):
if not devices:
return
# python-omemo returns own device as active,
# dont store it in this table
if self._own_device_id in devices:
devices.remove(self._own_device_id)
log.info('Store Active Devices: %s, %s', jid, devices)
self.storeDevices(jid, devices, 1)
log.info('Store Active Devices: %s, %s', bare_jid, devices)
self.storeDevices(bare_jid, devices, 1)
def storeInactiveDevices(self, jid, devices):
def storeInactiveDevices(self, callback, bare_jid, devices):
if not devices:
return
log.info('Store Inactive Devices: %s, %s', jid, devices)
self.storeDevices(jid, devices, 0)
log.info('Store Inactive Devices: %s, %s', bare_jid, devices)
self.storeDevices(bare_jid, devices, 0)
def storeDevices(self, jid, devices, active):
for device_id in devices:
......@@ -202,4 +231,8 @@ class SQLiteDatabase(Storage):
self._con.commit()
def isTrusted(self, *args):
return True
\ No newline at end of file
return True
@property
def is_async(self):
return False
......@@ -29,11 +29,11 @@ from gi.repository import GLib
from gajim import dialogs
from gajim.common import app, ged
from gajim.common.pep import SUPPORTED_PERSONAL_USER_EVENTS
from gajim.common import helpers
from gajim.plugins import GajimPlugin
from gajim.groupchat_control import GroupchatControl
from omemo2.xmpp import DevicelistPEP
from omemo2.modules.util import NS_NOTIFY
CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography'
AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version'
......@@ -50,16 +50,10 @@ except Exception as error:
log.exception(error)
ERROR_MSG = CRYPTOGRAPHY_MISSING
try:
import google.protobuf
except Exception as error:
log.error(error)
ERROR_MSG = PROTOBUF_MISSING
if not ERROR_MSG:
try:
from omemo2.omemo_connection import OMEMOConnection
from omemo2.ui import OMEMOConfigDialog, FingerprintWindow
from omemo2.ui import OMEMOConfigDialog
except Exception as error:
log.error(error)
ERROR_MSG = 'Error: %s' % error
......@@ -85,7 +79,7 @@ class OmemoPlugin(GajimPlugin):
self.encryption_name = 'OMEMO'
self.allow_groupchat = True
self.events_handlers = {
'signed-in': (ged.PRECORE, self.signed_in),
'signed-in': (ged.PRECORE, self._signed_in),
}
self.config_dialog = OMEMOConfigDialog(self)
......@@ -103,63 +97,44 @@ class OmemoPlugin(GajimPlugin):
self.encryption_state, None),
'update_caps': (self._update_caps, None)}
SUPPORTED_PERSONAL_USER_EVENTS.append(DevicelistPEP)
self.disabled_accounts = []
self.windowinstances = {}
self.connections = {}
self.config_default_values = {'DISABLED_ACCOUNTS': ([], ''), }
for account in self.config['DISABLED_ACCOUNTS']:
self.disabled_accounts.append(account)
# add aesgcm:// uri scheme to config
schemes = app.config.get('uri_schemes')
if 'aesgcm://' not in schemes.split():
schemes += ' aesgcm://'
app.config.set('uri_schemes', schemes)
def signed_in(self, event):
""" Method called on SignIn
Parameters
----------
event : SignedInEvent
"""
def _signed_in(self, event):
account = event.conn.name
if account == 'Local':
return
if account in self.disabled_accounts:
return
if account not in self.connections:
self.connections[account] = OMEMOConnection(account, self)
self.connections[account].signed_in(event)
con = app.connections[account]
if con.get_module('OMEMO').available:
con.get_module('OMEMO').publish_bundle()
con.get_module('OMEMO').query_devicelist()
def activate(self):
""" Method called when the Plugin is activated in the PluginManager
"""
for account in app.connections:
if account == 'Local':
continue
if account in self.disabled_accounts:
continue
self.connections[account] = OMEMOConnection(account, self)
self.connections[account].activate()
if app.caps_hash[account] != '':
# Gajim has already a caps hash calculated, update it
helpers.update_optional_features(account)
con = app.connections[account]
if app.account_is_connected(account):
if con.get_module('OMEMO').available:
con.get_module('OMEMO').query_devicelist()
con.get_module('OMEMO').publish_bundle()
def deactivate(self):
""" Method called when the Plugin is deactivated in the PluginManager
"""
for account in self.connections:
if account == 'Local':
continue
self.connections[account].deactivate()
def _update_caps(self, account):
if account == 'Local':
return
if account not in self.connections:
self.connections[account] = OMEMOConnection(account, self)
self.connections[account].update_caps(account)
pass
@staticmethod
def _update_caps(account):
if NS_NOTIFY not in app.gajim_optional_features[account]:
app.gajim_optional_features[account].append(NS_NOTIFY)
def activate_encryption(self, chat_control):
if isinstance(chat_control, GroupchatControl):
......@@ -172,14 +147,14 @@ class OmemoPlugin(GajimPlugin):
return False
return True
def _message_received(self, conn, obj, callback):
self.connections[conn.name].message_received(conn, obj, callback)
def _message_received(self, con, obj, callback):
con.get_module('OMEMO').message_received(con, obj, callback)
def _gc_encrypt_message(self, conn, obj, callback):
self.connections[conn.name].gc_encrypt_message(conn, obj, callback)
def _gc_encrypt_message(self, con, obj, callback):
con.get_module('OMEMO').gc_encrypt_message(con, obj, callback)
def _encrypt_message(self, conn, obj, callback):
self.connections[conn.name].encrypt_message(conn, obj, callback)
def _encrypt_message(self, con, obj, callback):
con.get_module('OMEMO').encrypt_message(con, obj, callback)
def _file_decryption(self, url, kind, instance, window):
file_crypto.FileDecryption(self).hyperlink_handler(
......@@ -217,38 +192,38 @@ class OmemoPlugin(GajimPlugin):
def before_sendmessage(self, chat_control):
account = chat_control.account
contact = chat_control.contact
con = self.connections[account]
self.new_fingerprints_available(chat_control)
if isinstance(chat_control, GroupchatControl):
room = chat_control.room_jid
missing = True
own_jid = app.get_jid_from_account(account)
for nick in con.groupchat[room]:
real_jid = con.groupchat[room][nick]
if real_jid == own_jid:
continue
if not con.are_keys_missing(real_jid):
missing = False
if missing:
log.info('%s => No Trusted Fingerprints for %s',
account, room)
self.print_message(chat_control, UserMessages.NO_FINGERPRINTS)
else:
# check if we have devices for the contact
if not self.get_omemo(account).get_devicelist(contact.jid):
con.query_devicelist(contact.jid, True)
self.print_message(chat_control, UserMessages.QUERY_DEVICES)
chat_control.sendmessage = False
return
# check if bundles are missing for some devices
if con.are_keys_missing(contact.jid):
log.info('%s => No Trusted Fingerprints for %s',
account, contact.jid)
self.print_message(chat_control, UserMessages.NO_FINGERPRINTS)
chat_control.sendmessage = False
else:
log.debug('%s => Sending Message to %s',
account, contact.jid)
con = app.connections[account]
# self.new_fingerprints_available(chat_control)
# if isinstance(chat_control, GroupchatControl):
# room = chat_control.room_jid
# missing = True
# own_jid = app.get_jid_from_account(account)
# for nick in con.groupchat[room]:
# real_jid = con.groupchat[room][nick]
# if real_jid == own_jid:
# continue
# if not con.are_keys_missing(real_jid):
# missing = False
# if missing:
# log.info('%s => No Trusted Fingerprints for %s',
# account, room)
# self.print_message(chat_control, UserMessages.NO_FINGERPRINTS)
# else:
# # check if we have devices for the contact
# if not self.get_omemo(account).get_devicelist(contact.jid):
# con.query_devicelist(contact.jid, True)
# self.print_message(chat_control, UserMessages.QUERY_DEVICES)
# chat_control.sendmessage = False
# return
# # check if bundles are missing for some devices
# if con.are_keys_missing(contact.jid):
# log.info('%s => No Trusted Fingerprints for %s',
# account, contact.jid)
# self.print_message(chat_control, UserMessages.NO_FINGERPRINTS)
# chat_control.sendmessage = False
# else:
# log.debug('%s => Sending Message to %s',
# account, contact.jid)
def new_fingerprints_available(self, chat_control):
return
......