[omemo] Show QR code in Key Dialog

This commit is contained in:
Philipp Hörist
2019-02-23 23:49:10 +01:00
parent 77b7762cb5
commit eff7d037f7
5 changed files with 228 additions and 187 deletions

View File

@@ -17,12 +17,8 @@
# along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>. # along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import logging import logging
import os
from gi.repository import GdkPixbuf
from gajim.common import app from gajim.common import app
from gajim.common import configpaths
from gajim.plugins.gui import GajimPluginConfigDialog from gajim.plugins.gui import GajimPluginConfigDialog
from gajim.plugins.helpers import get_builder from gajim.plugins.helpers import get_builder
@@ -30,14 +26,6 @@ from omemo.backend.util import get_fingerprint
log = logging.getLogger('gajim.plugin_system.omemo') log = logging.getLogger('gajim.plugin_system.omemo')
PILLOW = False
try:
import qrcode
PILLOW = True
except ImportError as error:
log.debug(error)
log.error('python-qrcode or dependencies of it are not available')
class OMEMOConfigDialog(GajimPluginConfigDialog): class OMEMOConfigDialog(GajimPluginConfigDialog):
def init(self): def init(self):
@@ -97,27 +85,6 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
def account_combobox_changed_cb(self, box, *args): def account_combobox_changed_cb(self, box, *args):
self.update_context_list() self.update_context_list()
@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: %s', ver_string)
if os.path.exists(path):
return path
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()
img.save(path)
return path
def update_disabled_account_view(self): def update_disabled_account_view(self):
self._ui.disabled_account_store.clear() self._ui.disabled_account_store.clear()
for account in self.disabled_accounts: for account in self.disabled_accounts:
@@ -168,7 +135,6 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
self._ui.fingerprint_label.set_markup('') self._ui.fingerprint_label.set_markup('')
self._ui.refresh.set_sensitive(False) self._ui.refresh.set_sensitive(False)
self._ui.cleardevice_button.set_sensitive(False) self._ui.cleardevice_button.set_sensitive(False)
self._ui.qrcode.clear()
return return
active = self._ui.account_combobox.get_active() active = self._ui.account_combobox.get_active()
account = self._ui.account_store[active][0] account = self._ui.account_store[active][0]
@@ -192,16 +158,3 @@ class OMEMOConfigDialog(GajimPluginConfigDialog):
# Set Device ID List # Set Device ID List
for item in omemo.backend.get_devices(own_jid): for item in omemo.backend.get_devices(own_jid):
self._ui.deviceid_store.append([item]) self._ui.deviceid_store.append([item])
# Set QR Verification Code
if PILLOW:
path = self._get_qrcode(own_jid,
omemo.backend.own_device,
identity_key)
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
self._ui.qrcode.set_from_pixbuf(pixbuf)
self._ui.qrcode.show()
self._ui.qrinfo.hide()
else:
self._ui.qrcode.hide()
self._ui.qrinfo.show()

View File

@@ -30,74 +30,6 @@
<property name="border_width">18</property> <property name="border_width">18</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">6</property> <property name="spacing">6</property>
<child>
<object class="GtkInfoBar" id="qrinfo">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="margin_bottom">6</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">start</property>
<property name="label" translatable="yes">For verification via QR-Code you have to install</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">python-qrcode</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child> <child>
<object class="GtkGrid"> <object class="GtkGrid">
<property name="visible">True</property> <property name="visible">True</property>
@@ -213,15 +145,20 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkImage" id="qrcode"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="tooltip_text" translatable="yes">Scan this QR-Code with your mobile device for easy verification</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="margin_top">6</property> <property name="label" translatable="yes">Note: Fingerprints of your contacts are managed in the message window.</property>
<property name="margin_bottom">6</property> <property name="wrap">True</property>
<property name="stock">gtk-missing-image</property> <property name="max_width_chars">50</property>
<property name="icon_size">1</property> <property name="xalign">0</property>
<attributes>
<attribute name="style" value="italic"/>
</attributes>
<style>
<class name="dim-label"/>
</style>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
@@ -232,41 +169,19 @@
<object class="GtkImage" id="image"> <object class="GtkImage" id="image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="tooltip_text">OMEMO</property> <property name="halign">end</property>
<property name="valign">start</property> <property name="stock">gtk-missing-image</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">3</property> <property name="top_attach">3</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Note: Fingerprints of your contacts are managed in the message window.</property>
<property name="wrap">True</property>
<attributes>
<attribute name="style" value="italic"/>
</attributes>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@@ -14,14 +14,17 @@
# You should have received a copy of the GNU General Public License # 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/>. # along with OMEMO Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import os
import time import time
import logging import logging
import tempfile
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
from gajim.common import app from gajim.common import app
from gajim.plugins.plugins_i18n import _ from gajim.plugins.plugins_i18n import _
from gajim.plugins.helpers import get_builder
from omemo.gtk.util import DialogButton, ButtonAction from omemo.gtk.util import DialogButton, ButtonAction
from omemo.gtk.util import NewConfirmationDialog from omemo.gtk.util import NewConfirmationDialog
@@ -31,6 +34,7 @@ from omemo.backend.util import get_fingerprint
log = logging.getLogger('gajim.plugin_system.omemo') log = logging.getLogger('gajim.plugin_system.omemo')
TRUST_DATA = { TRUST_DATA = {
Trust.NOT_TRUSTED: ('dialog-error-symbolic', Trust.NOT_TRUSTED: ('dialog-error-symbolic',
_('Not Trusted'), _('Not Trusted'),
@@ -64,56 +68,27 @@ class KeyDialog(Gtk.Dialog):
self._omemo = self._plugin.get_omemo(self._account) self._omemo = self._plugin.get_omemo(self._account)
self._own_jid = app.get_jid_from_account(self._account) self._own_jid = app.get_jid_from_account(self._account)
# Header path = self._plugin.local_file_path('gtk/key.ui')
jid = self._contact.jid self._ui = get_builder(path)
self._header = Gtk.Label(label=_('Fingerprints for %s') % jid)
self._header.get_style_context().add_class('bold')
self._header.get_style_context().add_class('dim-label')
# Fingerprints list self._ui.header.set_text(_('Fingerprints for %s') % self._contact.jid)
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)
# Own fingerprint
self._label = Gtk.Label(label=_('Own Fingerprint'))
self._label.get_style_context().add_class('bold')
self._label.get_style_context().add_class('dim-label')
self._omemo_logo = Gtk.Image()
omemo_img_path = self._plugin.local_file_path('omemo.png') omemo_img_path = self._plugin.local_file_path('omemo.png')
omemo_pixbuf = GdkPixbuf.Pixbuf.new_from_file(omemo_img_path) self._ui.omemo_image.set_from_file(omemo_img_path)
self._omemo_logo.set_from_pixbuf(omemo_pixbuf)
identity_key = self._omemo.backend.storage.getIdentityKeyPair() self._identity_key = self._omemo.backend.storage.getIdentityKeyPair()
ownfpr_format = get_fingerprint(identity_key, formatted=True) ownfpr_format = get_fingerprint(self._identity_key, formatted=True)
self._ownfpr = Gtk.Label(label=ownfpr_format) self._ui.own_fingerprint.set_text(ownfpr_format)
self._ownfpr.get_style_context().add_class('omemo-mono')
self._ownfpr.set_selectable(True)
self._ownfpr_box = Gtk.Box(spacing=12) self.get_content_area().add(self._ui.grid)
self._ownfpr_box.set_halign(Gtk.Align.CENTER)
self._ownfpr_box.pack_start(self._omemo_logo, True, True, 0)
self._ownfpr_box.pack_start(self._ownfpr, True, True, 0)
box = self.get_content_area()
box.set_orientation(Gtk.Orientation.VERTICAL)
box.set_spacing(12)
box.pack_start(self._header, False, True, 0)
box.pack_start(self._scrolled, True, True, 0)
box.pack_start(self._label, False, True, 0)
box.pack_start(self._ownfpr_box, False, True, 0)
self.update() self.update()
self._load_qrcode()
self.connect('destroy', self._on_destroy) self.connect('destroy', self._on_destroy)
self.show_all() self.show_all()
def update(self): def update(self):
self._listbox.foreach(self._listbox.remove) self._ui.list.foreach(self._ui.list.remove)
self._load_fingerprints(self._own_jid) self._load_fingerprints(self._own_jid)
self._load_fingerprints(self._contact.jid, self._groupchat is True) self._load_fingerprints(self._contact.jid, self._groupchat is True)
@@ -153,7 +128,45 @@ class KeyDialog(Gtk.Dialog):
key_row.device_id = item.device_id key_row.device_id = item.device_id
for row in rows.values(): for row in rows.values():
self._listbox.add(row) self._ui.list.add(row)
@staticmethod
def _get_qrcode(jid, sid, identity_key):
fingerprint = get_fingerprint(identity_key)
path = os.path.join(tempfile.gettempdir(),
'omemo_{}.png'.format(jid))
ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint)
log.debug('Verification String: %s', ver_string)
import qrcode
qr = qrcode.QRCode(version=None, error_correction=2,
box_size=4, border=1)
qr.add_data(ver_string)
qr.make(fit=True)
qr.make()
back_color = 'transparent'
if app.css_config.prefer_dark:
back_color = 'white'
img = qr.make_image(fill_color='black', back_color=back_color)
img.save(path)
return path
def _load_qrcode(self):
try:
path = self._get_qrcode(self._own_jid,
self._omemo.backend.own_device,
self._identity_key)
except ImportError:
log.exception('Failed to generate QR code')
self._ui.qrcode.hide()
self._ui.qrinfo.show()
else:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
self._ui.qrcode.set_from_pixbuf(pixbuf)
self._ui.qrcode.show()
self._ui.qrinfo.hide()
def _on_destroy(self, *args): def _on_destroy(self, *args):
del self._windows['dialog'] del self._windows['dialog']

158
omemo/gtk/key.ui Normal file
View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkPopover" id="popover">
<property name="can_focus">False</property>
<property name="constrain_to">none</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">12</property>
<property name="margin_right">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="own_fingerprint">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selectable">True</property>
<style>
<class name="omemo-mono"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="qrcode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="qrinfo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">For verification via QR-Code
you have to install python-qrcode</property>
<style>
<class name="omemo-qr-not-available"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="min_content_height">270</property>
<property name="overlay_scrolling">False</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="direction">up</property>
<property name="popover">popover</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Own Fingerprint</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="spacing">11</property>
<child>
<object class="GtkImage" id="omemo_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<style>
<class name="dim-label"/>
<class name="bold"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</interface>

View File

@@ -1,6 +1,8 @@
.omemo-dark-success-color { color: darker(@success_color); } .omemo-dark-success-color { color: darker(@success_color); }
.omemo-inactive-color { color: @insensitive_fg_color; } .omemo-inactive-color { color: @insensitive_fg_color; }
.omemo-qr-not-available {color: red;}
.omemo-mono { font-size: 12px; font-family: monospace; } .omemo-mono { font-size: 12px; font-family: monospace; }
.omemo-last-seen { font-size: 11px; } .omemo-last-seen { font-size: 11px; }