Philipp Hörist pushed to branch master at gajim / gajim
Commits: eb0257bf by mjk at 2023-05-10T09:38:21+00:00 feat: JID sharing: Include verified OMEMO fingerprints
- - - - - ef9479b9 by mjk at 2023-05-10T09:49:45+00:00 perf: QR codes: Avoid roundtrip to PNG in storage and back
- - - - -
4 changed files:
- gajim/common/helpers.py - gajim/common/modules/omemo.py - gajim/gtk/chat_banner.py - gajim/gtk/omemo_trust_manager.py
Changes:
===================================== gajim/common/helpers.py ===================================== @@ -48,7 +48,6 @@ import socket import string import sys -import tempfile import unicodedata import weakref import webbrowser @@ -83,6 +82,7 @@ from nbxmpp.structs import ProxyData from packaging.requirements import Requirement from packaging.version import Version as V +from qrcode.image.pil import PilImage as QrcPilImage
from gajim.common import app from gajim.common import configpaths @@ -370,9 +370,6 @@ def get_contact_dict_for_account(account: str) -> dict[str, types.BareContact]:
def generate_qr_code(content: str) -> GdkPixbuf.Pixbuf | None: - image_path = os.path.join( - tempfile.gettempdir(), - f'{get_random_string()}.png') qr = qrcode.QRCode(version=None, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=6, @@ -380,9 +377,11 @@ def generate_qr_code(content: str) -> GdkPixbuf.Pixbuf | None: qr.add_data(content) qr.make(fit=True)
- img = qr.make_image(fill_color='black', back_color='white') - img.save(image_path) - return GdkPixbuf.Pixbuf.new_from_file(image_path) + img = qr.make_image(image_factory=QrcPilImage).convert('RGB') + return GdkPixbuf.Pixbuf.new_from_bytes( + GLib.Bytes.new(img.tobytes()), + GdkPixbuf.Colorspace.RGB, False, 8, + img.width, img.height, img.width*3)
def play_sound(sound_event: str,
===================================== gajim/common/modules/omemo.py ===================================== @@ -50,6 +50,7 @@ from omemo_dr.exceptions import KeyExchangeMessage from omemo_dr.exceptions import MessageNotForDevice from omemo_dr.exceptions import SelfMessage +from omemo_dr.identitykey import IdentityKey from omemo_dr.session_manager import OMEMOSessionManager from omemo_dr.structs import OMEMOBundle from omemo_dr.structs import OMEMOConfig @@ -61,6 +62,7 @@ from gajim.common.const import EncryptionData from gajim.common.const import EncryptionInfoMsg from gajim.common.const import Trust as GajimTrust +from gajim.common.const import XmppUriQuery from gajim.common.events import EncryptionInfo from gajim.common.events import MucAdded from gajim.common.events import MucDiscoUpdate @@ -92,6 +94,8 @@ ('origin-id', Namespace.SID), ]
+DeviceIdT = int +IdentityT = tuple[DeviceIdT, IdentityKey]
class OMEMO(BaseModule):
@@ -646,6 +650,25 @@ def _debug_print_stanza(self, stanza: Any) -> None: stanzastr = stanzastr[0:-1] self._log.debug(stanzastr)
+ def compose_trust_uri(self, jid: JID) -> str: + verified_identities = [ + (info.device_id, info.public_key) + for info in self._backend.get_identity_infos( + jid.bare, only_active=True, trust=OMEMOTrust.VERIFIED) + ] + if self._client.is_own_jid(jid): + verified_identities.insert(0, self._backend.get_our_identity()) + return compose_trust_uri(jid, verified_identities) + def cleanup(self) -> None: self._backend.destroy() del self._backend + + +def compose_trust_uri(jid: JID, devices: list[IdentityT]) -> str: + query = ( + XmppUriQuery.MESSAGE.value, + [(f'omemo-sid-{sid}', ik.get_fingerprint()) for sid, ik in devices] + ) if devices else None + uri = jid.new_as_bare().to_iri(query) + return uri
===================================== gajim/gtk/chat_banner.py ===================================== @@ -334,13 +334,13 @@ def _update_share_box(self) -> None: self._ui.jid_label.set_text(str(self._contact.jid))
def _get_share_uri(self) -> str: + assert self._client is not None assert self._contact is not None jid = self._contact.get_address() if self._contact.is_groupchat: return jid.to_iri(XmppUriQuery.JOIN.value) else: - # TODO: add verified OMEMO FPs - return jid.to_iri() + return self._client.get_module('OMEMO').compose_trust_uri(jid)
def _on_share_clicked(self, _button: Gtk.Button) -> None: # Generate QR code on demand (i.e. not when switching chats)
===================================== gajim/gtk/omemo_trust_manager.py ===================================== @@ -25,22 +25,20 @@ import logging import time
-from gi.repository import GdkPixbuf from gi.repository import Gtk -from nbxmpp.protocol import JID from omemo_dr.const import OMEMOTrust from omemo_dr.structs import IdentityInfo
from gajim.common import app from gajim.common import ged from gajim.common import types -from gajim.common.const import XmppUriQuery from gajim.common.events import AccountConnected from gajim.common.events import AccountDisconnected from gajim.common.ged import EventHelper from gajim.common.helpers import generate_qr_code from gajim.common.i18n import _ from gajim.common.modules.contacts import BareContact +from gajim.common.modules.omemo import compose_trust_uri
from .builder import get_builder from .dialogs import ConfirmationDialog @@ -196,25 +194,12 @@ def _load_fingerprints(self, contact: types.ChatContactT) -> None: str(contact.jid)): self._ui.list.add(KeyRow(contact, identity_info))
- @staticmethod - def _get_qrcode(jid: JID, - sid: int, - fingerprint: str - ) -> GdkPixbuf.Pixbuf | None: - - qry = (XmppUriQuery.MESSAGE.value, [(f'omemo-sid-{sid}', fingerprint)]) - ver_string = jid.new_as_bare().to_iri(qry) - log.debug('Verification String: %s', ver_string) - return generate_qr_code(ver_string) - def _load_qrcode(self) -> None: - client = app.get_client(self._account) - our_device_id, our_identity_key =\ - self._omemo.backend.get_our_identity() - pixbuf = self._get_qrcode(client.get_own_jid(), - our_device_id, - our_identity_key.get_fingerprint()) - self._ui.qr_code_image.set_from_pixbuf(pixbuf) + uri = compose_trust_uri( + app.get_client(self._account).get_own_jid(), + [self._omemo.backend.get_our_identity()]) + log.debug('Trust URI: %s', uri) + self._ui.qr_code_image.set_from_pixbuf(generate_qr_code(uri))
def _on_show_inactive(self, switch: Gtk.Switch, _param: Any) -> None: self._ui.list.invalidate_filter()
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/fa79e9be46bbb0bce80e2283cbd57a96...