[omemo] Refactor Plugin
This commit is contained in:
@@ -16,11 +16,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
import os
|
||||
import textwrap
|
||||
from enum import IntEnum, unique
|
||||
|
||||
from gi.repository import GdkPixbuf
|
||||
|
||||
@@ -29,6 +26,8 @@ from gajim.common import configpaths
|
||||
from gajim.plugins.gui import GajimPluginConfigDialog
|
||||
from gajim.plugins.helpers import get_builder
|
||||
|
||||
from omemo.backend.util import get_fingerprint
|
||||
|
||||
log = logging.getLogger('gajim.plugin_system.omemo')
|
||||
|
||||
PILLOW = False
|
||||
@@ -40,13 +39,6 @@ except ImportError as error:
|
||||
log.error('python-qrcode or dependencies of it are not available')
|
||||
|
||||
|
||||
@unique
|
||||
class State(IntEnum):
|
||||
UNTRUSTED = 0
|
||||
TRUSTED = 1
|
||||
UNDECIDED = 2
|
||||
|
||||
|
||||
class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
def init(self):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
@@ -62,19 +54,8 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = []
|
||||
self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS']
|
||||
|
||||
log.debug('Disabled Accounts:')
|
||||
log.debug(self.disabled_accounts)
|
||||
|
||||
self.device_model = self._ui.get_object('deviceid_store')
|
||||
|
||||
self.disabled_acc_store = self._ui.get_object('disabled_account_store')
|
||||
self.account_store = self._ui.get_object('account_store')
|
||||
|
||||
self.active_acc_view = self._ui.get_object('active_accounts_view')
|
||||
self.disabled_acc_view = self._ui.get_object('disabled_accounts_view')
|
||||
|
||||
box = self.get_content_area()
|
||||
box.pack_start(self._ui.get_object('notebook1'), True, True, 0)
|
||||
box.pack_start(self._ui.notebook1, True, True, 0)
|
||||
|
||||
self._ui.connect_signals(self)
|
||||
|
||||
@@ -91,7 +72,7 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
self.update_disabled_account_view()
|
||||
|
||||
def is_in_accountstore(self, account):
|
||||
for row in self.account_store:
|
||||
for row in self._ui.account_store:
|
||||
if row[0] == account:
|
||||
return True
|
||||
return False
|
||||
@@ -103,32 +84,34 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
if account == 'Local':
|
||||
continue
|
||||
if not self.is_in_accountstore(account):
|
||||
self.account_store.append(row=(account,))
|
||||
self._ui.account_store.append(row=(account,))
|
||||
|
||||
def update_account_combobox(self):
|
||||
if self.plugin_active is False:
|
||||
return
|
||||
if len(self.account_store) > 0:
|
||||
self._ui.get_object('account_combobox').set_active(0)
|
||||
if self._ui.account_store:
|
||||
self._ui.account_combobox.set_active(0)
|
||||
else:
|
||||
self.account_combobox_changed_cb(
|
||||
self._ui.get_object('account_combobox'))
|
||||
self.account_combobox_changed_cb(self._ui.account_combobox)
|
||||
|
||||
def account_combobox_changed_cb(self, box, *args):
|
||||
self.update_context_list()
|
||||
|
||||
def get_qrcode(self, jid, sid, fingerprint):
|
||||
@staticmethod
|
||||
def _get_qrcode(jid, sid, identity_key):
|
||||
fingerprint = get_fingerprint(identity_key)
|
||||
file_name = 'omemo_{}.png'.format(jid)
|
||||
path = os.path.join(
|
||||
configpaths.get('MY_DATA'), file_name)
|
||||
|
||||
ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint)
|
||||
log.debug('Verification String: ' + ver_string)
|
||||
log.debug('Verification String: %s', ver_string)
|
||||
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1)
|
||||
qr = qrcode.QRCode(version=None, error_correction=2,
|
||||
box_size=4, border=1)
|
||||
qr.add_data(ver_string)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image()
|
||||
@@ -136,99 +119,89 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
|
||||
return path
|
||||
|
||||
def update_disabled_account_view(self):
|
||||
self.disabled_acc_store.clear()
|
||||
self._ui.disabled_account_store.clear()
|
||||
for account in self.disabled_accounts:
|
||||
self.disabled_acc_store.append(row=(account,))
|
||||
self._ui.disabled_account_store.append(row=(account,))
|
||||
|
||||
def activate_accounts_btn_clicked(self, button, *args):
|
||||
mod, paths = self.disabled_acc_view.get_selection().get_selected_rows()
|
||||
def activate_accounts_btn_clicked(self, _button, *args):
|
||||
selection = self._ui.disabled_accounts_view.get_selection()
|
||||
mod, paths = selection.get_selected_rows()
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
account = mod.get(it, 0)
|
||||
if account[0] in self.disabled_accounts and \
|
||||
not self.is_in_accountstore(account[0]):
|
||||
self.account_store.append(row=(account[0],))
|
||||
self._ui.account_store.append(row=(account[0],))
|
||||
self.disabled_accounts.remove(account[0])
|
||||
self.update_disabled_account_view()
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
|
||||
self.update_account_combobox()
|
||||
|
||||
def disable_accounts_btn_clicked(self, button, *args):
|
||||
mod, paths = self.active_acc_view.get_selection().get_selected_rows()
|
||||
def disable_accounts_btn_clicked(self, _button, *args):
|
||||
selection = self._ui.active_accounts_view.get_selection()
|
||||
mod, paths = selection.get_selected_rows()
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
account = mod.get(it, 0)
|
||||
if account[0] not in self.disabled_accounts and \
|
||||
self.is_in_accountstore(account[0]):
|
||||
self.disabled_accounts.append(account[0])
|
||||
self.account_store.remove(it)
|
||||
self._ui.account_store.remove(it)
|
||||
self.update_disabled_account_view()
|
||||
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
|
||||
self.update_account_combobox()
|
||||
|
||||
def cleardevice_button_clicked_cb(self, button, *args):
|
||||
active = self._ui.get_object('account_combobox').get_active()
|
||||
account = self.account_store[active][0]
|
||||
app.connections[account].get_module('OMEMO').set_devicelist(new=True)
|
||||
active = self._ui.account_combobox.get_active()
|
||||
account = self._ui.account_store[active][0]
|
||||
app.connections[account].get_module('OMEMO').clear_devicelist()
|
||||
self.update_context_list()
|
||||
|
||||
def refresh_button_clicked_cb(self, button, *args):
|
||||
self.update_context_list()
|
||||
|
||||
def update_context_list(self):
|
||||
self.device_model.clear()
|
||||
self.qrcode = self._ui.get_object('qrcode')
|
||||
self.qrinfo = self._ui.get_object('qrinfo')
|
||||
if len(self.account_store) == 0:
|
||||
self._ui.get_object('ID').set_markup('')
|
||||
self._ui.get_object('fingerprint_label').set_markup('')
|
||||
self._ui.get_object('refresh').set_sensitive(False)
|
||||
self._ui.get_object('cleardevice_button').set_sensitive(False)
|
||||
self._ui.get_object('qrcode').clear()
|
||||
self._ui.deviceid_store.clear()
|
||||
|
||||
if not self._ui.account_store:
|
||||
self._ui.ID.set_markup('')
|
||||
self._ui.fingerprint_label.set_markup('')
|
||||
self._ui.refresh.set_sensitive(False)
|
||||
self._ui.cleardevice_button.set_sensitive(False)
|
||||
self._ui.qrcode.clear()
|
||||
return
|
||||
active = self._ui.get_object('account_combobox').get_active()
|
||||
account = self.account_store[active][0]
|
||||
active = self._ui.account_combobox.get_active()
|
||||
account = self._ui.account_store[active][0]
|
||||
|
||||
# Set buttons active
|
||||
self._ui.get_object('refresh').set_sensitive(True)
|
||||
self._ui.refresh.set_sensitive(True)
|
||||
if account == 'Local':
|
||||
self._ui.get_object('cleardevice_button').set_sensitive(False)
|
||||
self._ui.cleardevice_button.set_sensitive(False)
|
||||
else:
|
||||
self._ui.get_object('cleardevice_button').set_sensitive(True)
|
||||
self._ui.cleardevice_button.set_sensitive(True)
|
||||
|
||||
# Set FPR Label and DeviceID
|
||||
state = self.plugin.get_omemo(account)
|
||||
deviceid = state.own_device_id
|
||||
self._ui.get_object('ID').set_markup('<tt>%s</tt>' % deviceid)
|
||||
omemo = self.plugin.get_omemo(account)
|
||||
self._ui.ID.set_markup('<tt>%s</tt>' % omemo.backend.own_device)
|
||||
|
||||
ownfpr = binascii.hexlify(state.store.getIdentityKeyPair()
|
||||
.getPublicKey().serialize()).decode('utf-8')
|
||||
human_ownfpr = self.human_hash(ownfpr[2:])
|
||||
self._ui.get_object('fingerprint_label').set_markup('<tt>%s</tt>'
|
||||
% human_ownfpr)
|
||||
identity_key = omemo.backend.storage.getIdentityKeyPair()
|
||||
fpr = get_fingerprint(identity_key, formatted=True)
|
||||
self._ui.fingerprint_label.set_markup('<tt>%s</tt>' % fpr)
|
||||
|
||||
own_jid = app.get_jid_from_account(account)
|
||||
# Set Device ID List
|
||||
for item in state.own_devices:
|
||||
self.device_model.append([item])
|
||||
for item in omemo.backend.get_devices(own_jid, without_self=True):
|
||||
self._ui.deviceid_store.append([item])
|
||||
|
||||
# Set QR Verification Code
|
||||
if PILLOW:
|
||||
path = self.get_qrcode(
|
||||
app.get_jid_from_account(account), deviceid, ownfpr[2:])
|
||||
path = self._get_qrcode(own_jid,
|
||||
omemo.backend.own_device,
|
||||
identity_key)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
|
||||
self.qrcode.set_from_pixbuf(pixbuf)
|
||||
self.qrcode.show()
|
||||
self.qrinfo.hide()
|
||||
self._ui.qrcode.set_from_pixbuf(pixbuf)
|
||||
self._ui.qrcode.show()
|
||||
self._ui.qrinfo.hide()
|
||||
else:
|
||||
self.qrcode.hide()
|
||||
self.qrinfo.show()
|
||||
|
||||
def human_hash(self, fpr):
|
||||
fpr = fpr.upper()
|
||||
fplen = len(fpr)
|
||||
wordsize = fplen // 8
|
||||
buf = ''
|
||||
for w in range(0, fplen, wordsize):
|
||||
buf += '{0} '.format(fpr[w:w + wordsize])
|
||||
buf = textwrap.fill(buf, width=36)
|
||||
return buf.rstrip()
|
||||
self._ui.qrcode.hide()
|
||||
self._ui.qrinfo.show()
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
# along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import binascii
|
||||
import textwrap
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GdkPixbuf
|
||||
@@ -27,6 +25,7 @@ from gajim.plugins.plugins_i18n import _
|
||||
from omemo.gtk.util import DialogButton, ButtonAction
|
||||
from omemo.gtk.util import NewConfirmationDialog
|
||||
from omemo.gtk.util import Trust
|
||||
from omemo.backend.util import get_fingerprint
|
||||
|
||||
log = logging.getLogger('gajim.plugin_system.omemo')
|
||||
|
||||
@@ -44,23 +43,23 @@ TRUST_DATA = {
|
||||
|
||||
|
||||
class KeyDialog(Gtk.Dialog):
|
||||
def __init__(self, plugin, contact, transient, windowinstances,
|
||||
def __init__(self, plugin, contact, transient, windows,
|
||||
groupchat=False):
|
||||
super().__init__(title=_('OMEMO Fingerprints'), destroy_with_parent=True)
|
||||
super().__init__(title=_('OMEMO Fingerprints'),
|
||||
destroy_with_parent=True)
|
||||
|
||||
self.set_transient_for(transient)
|
||||
self.set_resizable(True)
|
||||
self.set_default_size(-1, 400)
|
||||
self.set_default_size(500, 450)
|
||||
|
||||
self.get_style_context().add_class('omemo-key-dialog')
|
||||
|
||||
self._groupchat = groupchat
|
||||
self._contact = contact
|
||||
self._windowinstances = windowinstances
|
||||
self._windows = windows
|
||||
self._account = self._contact.account.name
|
||||
self._plugin = plugin
|
||||
self._con = app.connections[self._account].get_module('OMEMO')
|
||||
self.omemostate = self._plugin.get_omemo(self._account)
|
||||
self._omemo = self._plugin.get_omemo(self._account)
|
||||
self._own_jid = app.get_jid_from_account(self._account)
|
||||
|
||||
# Header
|
||||
@@ -88,9 +87,8 @@ class KeyDialog(Gtk.Dialog):
|
||||
omemo_pixbuf = GdkPixbuf.Pixbuf.new_from_file(omemo_img_path)
|
||||
self._omemo_logo.set_from_pixbuf(omemo_pixbuf)
|
||||
|
||||
ownfpr = binascii.hexlify(self.omemostate.store.getIdentityKeyPair()
|
||||
.getPublicKey().serialize()).decode('utf-8')
|
||||
ownfpr_format = KeyRow._format_fingerprint(ownfpr[2:])
|
||||
identity_key = self._omemo.backend.storage.getIdentityKeyPair()
|
||||
ownfpr_format = get_fingerprint(identity_key, formatted=True)
|
||||
self._ownfpr = Gtk.Label(label=ownfpr_format)
|
||||
self._ownfpr.get_style_context().add_class('omemo-mono')
|
||||
self._ownfpr.set_selectable(True)
|
||||
@@ -113,52 +111,43 @@ class KeyDialog(Gtk.Dialog):
|
||||
self.show_all()
|
||||
|
||||
def update(self):
|
||||
self._listbox.foreach(lambda row: self._listbox.remove(row))
|
||||
self._listbox.foreach(self._listbox.remove)
|
||||
self._load_fingerprints(self._own_jid)
|
||||
self._load_fingerprints(self._contact.jid, self._groupchat is True)
|
||||
|
||||
def _load_fingerprints(self, contact_jid, groupchat=False):
|
||||
from axolotl.state.sessionrecord import SessionRecord
|
||||
state = self.omemostate
|
||||
|
||||
if groupchat:
|
||||
contact_jids = []
|
||||
for nick in self._con.groupchat[contact_jid]:
|
||||
real_jid = self._con.groupchat[contact_jid][nick]
|
||||
if real_jid == self._own_jid:
|
||||
continue
|
||||
contact_jids.append(real_jid)
|
||||
session_db = state.store.getSessionsFromJids(contact_jids)
|
||||
members = list(self._omemo.backend.get_muc_members(contact_jid))
|
||||
sessions = self._omemo.backend.storage.getSessionsFromJids(members)
|
||||
else:
|
||||
session_db = state.store.getSessionsFromJid(contact_jid)
|
||||
sessions = self._omemo.backend.storage.getSessionsFromJid(contact_jid)
|
||||
|
||||
for item in session_db:
|
||||
_id, jid, deviceid, record, active = item
|
||||
|
||||
active = bool(active)
|
||||
|
||||
identity_key = SessionRecord(serialized=record). \
|
||||
getSessionState().getRemoteIdentityKey()
|
||||
fpr = binascii.hexlify(identity_key.getPublicKey().serialize()).decode('utf-8')
|
||||
fpr = fpr[2:]
|
||||
trust = state.store.isTrustedIdentity(jid, identity_key)
|
||||
|
||||
log.info('Load: %s %s', fpr, trust)
|
||||
self._listbox.add(KeyRow(jid, deviceid, fpr, trust, active))
|
||||
for item in sessions:
|
||||
active = bool(item.active)
|
||||
session_record = SessionRecord(serialized=item.record)
|
||||
identity_key = session_record.getSessionState().getRemoteIdentityKey()
|
||||
trust = self._omemo.backend.storage.getTrustForIdentity(
|
||||
item.recipient_id, identity_key)
|
||||
self._listbox.add(KeyRow(item.recipient_id,
|
||||
item.device_id,
|
||||
identity_key,
|
||||
trust, active))
|
||||
|
||||
def _on_destroy(self, *args):
|
||||
del self._windowinstances['dialog']
|
||||
del self._windows['dialog']
|
||||
|
||||
|
||||
class KeyRow(Gtk.ListBoxRow):
|
||||
def __init__(self, jid, deviceid, fpr, trust, active):
|
||||
def __init__(self, jid, device_id, identity_key, trust, active):
|
||||
Gtk.ListBoxRow.__init__(self)
|
||||
self.set_activatable(False)
|
||||
|
||||
self.active = active
|
||||
self.trust = trust
|
||||
self.jid = jid
|
||||
self.deviceid = deviceid
|
||||
self.device_id = device_id
|
||||
|
||||
box = Gtk.Box()
|
||||
box.set_spacing(12)
|
||||
@@ -175,7 +164,8 @@ class KeyRow(Gtk.ListBoxRow):
|
||||
jid_label.set_hexpand(True)
|
||||
label_box.add(jid_label)
|
||||
|
||||
fingerprint = Gtk.Label(label=self._format_fingerprint(fpr))
|
||||
fingerprint = Gtk.Label(label=get_fingerprint(identity_key,
|
||||
formatted=True))
|
||||
fingerprint.get_style_context().add_class('omemo-mono')
|
||||
if not active:
|
||||
fingerprint.get_style_context().add_class('omemo-inactive-color')
|
||||
@@ -192,12 +182,12 @@ class KeyRow(Gtk.ListBoxRow):
|
||||
|
||||
def delete_fingerprint(self, *args):
|
||||
def _remove():
|
||||
state = self.get_toplevel().omemostate
|
||||
record = state.store.loadSession(self.jid, self.deviceid)
|
||||
backend = self.get_toplevel()._omemo.backend
|
||||
record = backend.storage.loadSession(self.jid, self.device_id)
|
||||
identity_key = record.getSessionState().getRemoteIdentityKey()
|
||||
|
||||
state.store.deleteSession(self.jid, self.deviceid)
|
||||
state.store.deleteIdentity(self.jid, identity_key)
|
||||
backend.storage.deleteSession(self.jid, self.device_id)
|
||||
backend.storage.deleteIdentity(self.jid, identity_key)
|
||||
self.get_parent().remove(self)
|
||||
self.destroy()
|
||||
|
||||
@@ -221,20 +211,10 @@ class KeyRow(Gtk.ListBoxRow):
|
||||
image.get_style_context().add_class(css_class)
|
||||
image.set_tooltip_text(tooltip)
|
||||
|
||||
state = self.get_toplevel().omemostate
|
||||
record = state.store.loadSession(self.jid, self.deviceid)
|
||||
backend = self.get_toplevel()._omemo.backend
|
||||
record = backend.storage.loadSession(self.jid, self.device_id)
|
||||
identity_key = record.getSessionState().getRemoteIdentityKey()
|
||||
state.store.setTrust(identity_key, self.trust)
|
||||
|
||||
@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])
|
||||
buf = textwrap.fill(buf, width=36)
|
||||
return buf.rstrip().upper()
|
||||
backend.storage.setTrust(identity_key, self.trust)
|
||||
|
||||
|
||||
class TrustButton(Gtk.MenuButton):
|
||||
@@ -278,7 +258,7 @@ class TrustPopver(Gtk.Popover):
|
||||
self._listbox.connect('row-activated', self._activated)
|
||||
self.get_style_context().add_class('omemo-trust-popover')
|
||||
|
||||
def _activated(self, listbox, row):
|
||||
def _activated(self, _listbox, row):
|
||||
self.popdown()
|
||||
if row.type_ is None:
|
||||
self._row.delete_fingerprint()
|
||||
@@ -289,7 +269,7 @@ class TrustPopver(Gtk.Popover):
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self._listbox.foreach(lambda row: self._listbox.remove(row))
|
||||
self._listbox.foreach(self._listbox.remove)
|
||||
if self._row.trust != Trust.VERIFIED:
|
||||
self._listbox.add(VerifiedOption())
|
||||
if self._row.trust != Trust.NOT_TRUSTED:
|
||||
|
||||
Reference in New Issue
Block a user