cq: Format with black and isort

This commit is contained in:
Philipp Hörist
2025-01-25 19:15:37 +01:00
parent e6e71d82bf
commit 841b1fb25e
44 changed files with 1641 additions and 1660 deletions

View File

@@ -20,8 +20,8 @@
# You should have received a copy of the GNU General Public License
# along with PGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
import os
from functools import lru_cache
import gnupg
@@ -30,56 +30,51 @@ from gajim.common.util.classes import Singleton
from pgp.exceptions import SignError
logger = logging.getLogger('gajim.p.pgplegacy')
logger = logging.getLogger("gajim.p.pgplegacy")
if logger.getEffectiveLevel() == logging.DEBUG:
logger = logging.getLogger('gnupg')
logger = logging.getLogger("gnupg")
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
class PGP(gnupg.GPG, metaclass=Singleton):
def __init__(self, binary, encoding=None):
super().__init__(gpgbinary=binary,
use_agent=True)
super().__init__(gpgbinary=binary, use_agent=True)
if encoding is not None:
self.encoding = encoding
self.decode_errors = 'replace'
self.decode_errors = "replace"
def encrypt(self, payload, recipients, always_trust=False):
if not always_trust:
# check that we'll be able to encrypt
result = self.get_key(recipients[0])
for key in result:
if key['trust'] not in ('f', 'u'):
return '', 'NOT_TRUSTED ' + key['keyid'][-8:]
if key["trust"] not in ("f", "u"):
return "", "NOT_TRUSTED " + key["keyid"][-8:]
result = super().encrypt(
payload.encode('utf8'),
recipients,
always_trust=always_trust)
payload.encode("utf8"), recipients, always_trust=always_trust
)
if result.ok:
error = ''
error = ""
else:
error = result.status
return self._strip_header_footer(str(result)), error
def decrypt(self, payload):
data = self._add_header_footer(payload, 'MESSAGE')
result = super().decrypt(data.encode('utf8'))
data = self._add_header_footer(payload, "MESSAGE")
result = super().decrypt(data.encode("utf8"))
return result.data.decode('utf8')
return result.data.decode("utf8")
@lru_cache(maxsize=8)
def sign(self, payload, key_id):
if payload is None:
payload = ''
result = super().sign(payload.encode('utf8'),
keyid=key_id,
detach=True)
payload = ""
result = super().sign(payload.encode("utf8"), keyid=key_id, detach=True)
if result.fingerprint:
return self._strip_header_footer(str(result))
@@ -91,19 +86,20 @@ class PGP(gnupg.GPG, metaclass=Singleton):
# Text name for hash algorithms from RFC 4880 - section 9.4
if payload is None:
payload = ''
payload = ""
hash_algorithms = ['SHA512', 'SHA384', 'SHA256',
'SHA224', 'SHA1', 'RIPEMD160']
hash_algorithms = ["SHA512", "SHA384", "SHA256", "SHA224", "SHA1", "RIPEMD160"]
for algo in hash_algorithms:
data = os.linesep.join(
['-----BEGIN PGP SIGNED MESSAGE-----',
'Hash: ' + algo,
'',
payload,
self._add_header_footer(signed, 'SIGNATURE')]
)
result = super().verify(data.encode('utf8'))
[
"-----BEGIN PGP SIGNED MESSAGE-----",
"Hash: " + algo,
"",
payload,
self._add_header_footer(signed, "SIGNATURE"),
]
)
result = super().verify(data.encode("utf8"))
if result.valid:
return result.fingerprint
@@ -116,7 +112,7 @@ class PGP(gnupg.GPG, metaclass=Singleton):
for key in result:
# Take first not empty uid
keys[key['fingerprint']] = next(uid for uid in key['uids'] if uid)
keys[key["fingerprint"]] = next(uid for uid in key["uids"] if uid)
return keys
@staticmethod
@@ -125,19 +121,19 @@ class PGP(gnupg.GPG, metaclass=Singleton):
Remove header and footer from data
"""
if not data:
return ''
return ""
lines = data.splitlines()
while lines[0] != '':
while lines[0] != "":
lines.remove(lines[0])
while lines[0] == '':
while lines[0] == "":
lines.remove(lines[0])
i = 0
for line in lines:
if line:
if line[0] == '-':
if line[0] == "-":
break
i = i+1
line = '\n'.join(lines[0:i])
i = i + 1
line = "\n".join(lines[0:i])
return line
@staticmethod

View File

@@ -34,31 +34,30 @@ class KeyStore:
self._account = account
own_bare_jid = own_jid.bare
path = Path(configpaths.get('PLUGINS_DATA')) / 'pgplegacy' / own_bare_jid
path = Path(configpaths.get("PLUGINS_DATA")) / "pgplegacy" / own_bare_jid
if not path.exists():
path.mkdir(parents=True)
self._store_path = path / 'store'
self._store_path = path / "store"
if self._store_path.exists():
# having store v2 or higher
with self._store_path.open('r') as file:
with self._store_path.open("r") as file:
try:
self._store = json.load(file)
except Exception:
log.exception('Could not load config')
log.exception("Could not load config")
self._store = self._empty_store()
ver = self._store.get('_version', 2)
ver = self._store.get("_version", 2)
if ver > CURRENT_STORE_VERSION:
raise Exception('Unknown store version! '
'Please upgrade pgp plugin.')
raise Exception("Unknown store version! " "Please upgrade pgp plugin.")
elif ver == 2:
self._migrate_v2_store()
self._save_store()
elif ver != CURRENT_STORE_VERSION:
# garbled version
self._store = self._empty_store()
log.warning('Bad pgp key store version. Initializing new.')
log.warning("Bad pgp key store version. Initializing new.")
else:
# having store v1 or fresh install
self._store = self._empty_store()
@@ -69,15 +68,16 @@ class KeyStore:
@staticmethod
def _empty_store():
return {
'_version': CURRENT_STORE_VERSION,
'own_key_data': None,
'contact_key_data': {},
"_version": CURRENT_STORE_VERSION,
"own_key_data": None,
"contact_key_data": {},
}
def _migrate_v1_store(self):
keys = {}
attached_keys = app.settings.get_account_setting(
self._account, 'attached_gpg_keys')
self._account, "attached_gpg_keys"
)
if not attached_keys:
return
attached_keys = attached_keys.split()
@@ -86,23 +86,25 @@ class KeyStore:
keys[attached_keys[2 * i]] = attached_keys[2 * i + 1]
for jid, key_id in keys.items():
self._set_contact_key_data_nosync(jid, (key_id, ''))
self._set_contact_key_data_nosync(jid, (key_id, ""))
own_key_id = app.settings.get_account_setting(self._account, 'keyid')
own_key_user = app.settings.get_account_setting(
self._account, 'keyname')
own_key_id = app.settings.get_account_setting(self._account, "keyid")
own_key_user = app.settings.get_account_setting(self._account, "keyname")
if own_key_id:
self._set_own_key_data_nosync((own_key_id, own_key_user))
attached_keys = app.settings.set_account_setting(
self._account, 'attached_gpg_keys', '')
self._log.info('Migration from store v1 was successful')
self._account, "attached_gpg_keys", ""
)
self._log.info("Migration from store v1 was successful")
def _migrate_v2_store(self):
own_key_data = self.get_own_key_data()
if own_key_data is not None:
own_key_id, own_key_user = (own_key_data['key_id'],
own_key_data['key_user'])
own_key_id, own_key_user = (
own_key_data["key_id"],
own_key_data["key_user"],
)
try:
own_key_fp = self._resolve_short_id(own_key_id, has_secret=True)
self._set_own_key_data_nosync((own_key_fp, own_key_user))
@@ -111,38 +113,41 @@ class KeyStore:
prune_list = []
for dict_key, key_data in self._store['contact_key_data'].items():
for dict_key, key_data in self._store["contact_key_data"].items():
try:
key_data['key_id'] = self._resolve_short_id(key_data['key_id'])
key_data["key_id"] = self._resolve_short_id(key_data["key_id"])
except KeyResolveError:
prune_list.append(dict_key)
for dict_key in prune_list:
del self._store['contact_key_data'][dict_key]
del self._store["contact_key_data"][dict_key]
self._store['_version'] = CURRENT_STORE_VERSION
self._log.info('Migration from store v2 was successful')
self._store["_version"] = CURRENT_STORE_VERSION
self._log.info("Migration from store v2 was successful")
def _save_store(self):
with self._store_path.open('w') as file:
with self._store_path.open("w") as file:
json.dump(self._store, file)
def _get_dict_key(self, jid):
return '%s-%s' % (self._account, jid)
return "%s-%s" % (self._account, jid)
def _resolve_short_id(self, short_id, has_secret=False):
candidates = self._list_keys_func(
secret=has_secret, keys=(short_id,)).fingerprints
secret=has_secret, keys=(short_id,)
).fingerprints
if len(candidates) == 1:
return candidates[0]
elif len(candidates) > 1:
self._log.critical('Key collision during migration. '
'Key ID is %s. Removing binding...',
repr(short_id))
self._log.critical(
"Key collision during migration. " "Key ID is %s. Removing binding...",
repr(short_id),
)
else:
self._log.warning('Key %s was not found during migration. '
'Removing binding...',
repr(short_id))
self._log.warning(
"Key %s was not found during migration. " "Removing binding...",
repr(short_id),
)
raise KeyResolveError
def set_own_key_data(self, key_data):
@@ -151,18 +156,18 @@ class KeyStore:
def _set_own_key_data_nosync(self, key_data):
if key_data is None:
self._store['own_key_data'] = None
self._store["own_key_data"] = None
else:
self._store['own_key_data'] = {
'key_id': key_data[0],
'key_user': key_data[1]
self._store["own_key_data"] = {
"key_id": key_data[0],
"key_user": key_data[1],
}
def get_own_key_data(self):
return self._store['own_key_data']
return self._store["own_key_data"]
def get_contact_key_data(self, jid):
key_ids = self._store['contact_key_data']
key_ids = self._store["contact_key_data"]
dict_key = self._get_dict_key(jid)
return key_ids.get(dict_key)
@@ -171,12 +176,9 @@ class KeyStore:
self._save_store()
def _set_contact_key_data_nosync(self, jid, key_data):
key_ids = self._store['contact_key_data']
key_ids = self._store["contact_key_data"]
dict_key = self._get_dict_key(jid)
if key_data is None:
key_ids[dict_key] = None
else:
key_ids[dict_key] = {
'key_id': key_data[0],
'key_user': key_data[1]
}
key_ids[dict_key] = {"key_id": key_data[0], "key_user": key_data[1]}

View File

@@ -14,11 +14,14 @@
# You should have received a copy of the GNU General Public License
# along with PGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
class SignError(Exception):
pass
class KeyMismatch(Exception):
pass
class NoKeyIdFound(Exception):
pass

View File

@@ -16,12 +16,11 @@
from pathlib import Path
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib
from gi.repository import Gtk
from gajim.common import app
from gajim.plugins.helpers import get_builder
from gajim.plugins.plugins_i18n import _
@@ -33,14 +32,14 @@ class PGPConfigDialog(Gtk.ApplicationWindow):
Gtk.ApplicationWindow.__init__(self)
self.set_application(app.app)
self.set_show_menubar(False)
self.set_title(_('PGP Configuration'))
self.set_title(_("PGP Configuration"))
self.set_transient_for(parent)
self.set_resizable(True)
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.set_destroy_with_parent(True)
ui_path = Path(__file__).parent
self._ui = get_builder(ui_path.resolve() / 'config.ui')
self._ui = get_builder(ui_path.resolve() / "config.ui")
self.add(self._ui.config_box)
@@ -50,9 +49,7 @@ class PGPConfigDialog(Gtk.ApplicationWindow):
for account in app.settings.get_active_accounts():
page = Page(plugin, account)
self._ui.stack.add_titled(page,
account,
app.get_account_label(account))
self._ui.stack.add_titled(page, account, app.get_account_label(account))
self.show_all()
@@ -64,11 +61,11 @@ class Page(Gtk.Box):
self._client = app.get_client(account)
self._plugin = plugin
self._label = Gtk.Label()
self._button = Gtk.Button(label=_('Assign Key'))
self._button.get_style_context().add_class('suggested-action')
self._button = Gtk.Button(label=_("Assign Key"))
self._button.get_style_context().add_class("suggested-action")
self._button.set_halign(Gtk.Align.CENTER)
self._button.set_margin_top(18)
self._button.connect('clicked', self._on_assign)
self._button.connect("clicked", self._on_assign)
self._load_key()
self.add(self._label)
@@ -76,34 +73,34 @@ class Page(Gtk.Box):
self.show_all()
def _on_assign(self, _button):
backend = self._client.get_module('PGPLegacy').pgp_backend
backend = self._client.get_module("PGPLegacy").pgp_backend
secret_keys = backend.get_keys(secret=True)
dialog = ChooseGPGKeyDialog(secret_keys, self.get_toplevel())
dialog.connect('response', self._on_response)
dialog.connect("response", self._on_response)
def _load_key(self):
key_data = self._client.get_module('PGPLegacy').get_own_key_data()
key_data = self._client.get_module("PGPLegacy").get_own_key_data()
if key_data is None:
self._set_key(None)
else:
self._set_key((key_data['key_id'], key_data['key_user']))
self._set_key((key_data["key_id"], key_data["key_user"]))
def _on_response(self, dialog, response):
if response != Gtk.ResponseType.OK:
return
if dialog.selected_key is None:
self._client.get_module('PGPLegacy').set_own_key_data(None)
self._client.get_module("PGPLegacy").set_own_key_data(None)
self._set_key(None)
else:
self._client.get_module('PGPLegacy').set_own_key_data(
dialog.selected_key)
self._client.get_module("PGPLegacy").set_own_key_data(dialog.selected_key)
self._set_key(dialog.selected_key)
def _set_key(self, key_data):
if key_data is None:
self._label.set_text(_('No key assigned'))
self._label.set_text(_("No key assigned"))
else:
key_id, key_user = key_data
self._label.set_markup('<b><tt>%s</tt> %s</b>' % \
(key_id, GLib.markup_escape_text(key_user)))
self._label.set_markup(
"<b><tt>%s</tt> %s</b>" % (key_id, GLib.markup_escape_text(key_user))
)

View File

@@ -16,18 +16,17 @@
from pathlib import Path
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import Gtk
from gajim.common import app
from gajim.plugins.plugins_i18n import _
from gajim.plugins.helpers import get_builder
from gajim.plugins.plugins_i18n import _
class KeyDialog(Gtk.Dialog):
def __init__(self, plugin, account, jid, transient):
super().__init__(title=_('Assign key for %s') % jid,
destroy_with_parent=True)
super().__init__(title=_("Assign key for %s") % jid, destroy_with_parent=True)
self.set_transient_for(transient)
self.set_resizable(True)
@@ -39,11 +38,11 @@ class KeyDialog(Gtk.Dialog):
self._label = Gtk.Label()
self._assign_button = Gtk.Button(label=_('Assign Key'))
self._assign_button.get_style_context().add_class('suggested-action')
self._assign_button = Gtk.Button(label=_("Assign Key"))
self._assign_button.get_style_context().add_class("suggested-action")
self._assign_button.set_halign(Gtk.Align.CENTER)
self._assign_button.set_margin_top(18)
self._assign_button.connect('clicked', self._choose_key)
self._assign_button.connect("clicked", self._choose_key)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.set_border_width(18)
@@ -57,13 +56,12 @@ class KeyDialog(Gtk.Dialog):
self.show_all()
def _choose_key(self, *args):
backend = self._client.get_module('PGPLegacy').pgp_backend
backend = self._client.get_module("PGPLegacy").pgp_backend
dialog = ChooseGPGKeyDialog(backend.get_keys(), self)
dialog.connect('response', self._on_response)
dialog.connect("response", self._on_response)
def _load_key(self):
key_data = self._client.get_module('PGPLegacy').get_contact_key_data(
self._jid)
key_data = self._client.get_module("PGPLegacy").get_contact_key_data(self._jid)
if key_data is None:
self._set_key(None)
else:
@@ -74,42 +72,43 @@ class KeyDialog(Gtk.Dialog):
return
if dialog.selected_key is None:
self._client.get_module('PGPLegacy').set_contact_key_data(
self._jid, None)
self._client.get_module("PGPLegacy").set_contact_key_data(self._jid, None)
self._set_key(None)
else:
self._client.get_module('PGPLegacy').set_contact_key_data(
self._jid, dialog.selected_key)
self._client.get_module("PGPLegacy").set_contact_key_data(
self._jid, dialog.selected_key
)
self._set_key(dialog.selected_key)
def _set_key(self, key_data):
if key_data is None:
self._label.set_text(_('No key assigned'))
self._label.set_text(_("No key assigned"))
else:
key_id, key_user = key_data
self._label.set_markup('<b><tt>%s</tt> %s</b>' % \
(key_id, GLib.markup_escape_text(key_user)))
self._label.set_markup(
"<b><tt>%s</tt> %s</b>" % (key_id, GLib.markup_escape_text(key_user))
)
class ChooseGPGKeyDialog(Gtk.Dialog):
def __init__(self, secret_keys, transient_for):
Gtk.Dialog.__init__(self,
title=_('Assign PGP Key'),
transient_for=transient_for)
Gtk.Dialog.__init__(
self, title=_("Assign PGP Key"), transient_for=transient_for
)
secret_keys[_('None')] = _('None')
secret_keys[_("None")] = _("None")
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
self.set_resizable(True)
self.set_default_size(500, 300)
self.add_button(_('Cancel'), Gtk.ResponseType.CANCEL)
self.add_button(_('OK'), Gtk.ResponseType.OK)
self.add_button(_("Cancel"), Gtk.ResponseType.CANCEL)
self.add_button(_("OK"), Gtk.ResponseType.OK)
self._selected_key = None
ui_path = Path(__file__).parent
self._ui = get_builder(ui_path.resolve() / 'choose_key.ui')
self._ui = get_builder(ui_path.resolve() / "choose_key.ui")
self._ui.keys_treeview = self._ui.keys_treeview
@@ -124,7 +123,7 @@ class ChooseGPGKeyDialog(Gtk.Dialog):
self._ui.connect_signals(self)
self.connect_after('response', self._on_response)
self.connect_after("response", self._on_response)
self.show_all()
@@ -136,9 +135,9 @@ class ChooseGPGKeyDialog(Gtk.Dialog):
def _sort(model, iter1, iter2, _data):
value1 = model[iter1][1]
value2 = model[iter2][1]
if value1 == _('None'):
if value1 == _("None"):
return -1
if value2 == _('None'):
if value2 == _("None"):
return 1
if value1 < value2:
return -1
@@ -154,7 +153,7 @@ class ChooseGPGKeyDialog(Gtk.Dialog):
self._selected_key = None
else:
key_id, key_user = model[iter_][0], model[iter_][1]
if key_id == _('None'):
if key_id == _("None"):
self._selected_key = None
else:
self._selected_key = key_id, key_user

View File

@@ -12,9 +12,10 @@
# 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/>.
from __future__ import annotations
from __future__ import annotations
from typing import Any, Callable
from typing import Any
from typing import Callable
from dataclasses import dataclass
from dataclasses import field
@@ -24,12 +25,12 @@ from gajim.common.events import ApplicationEvent
@dataclass
class PGPNotTrusted(ApplicationEvent):
name: str = field(init=False, default='pgp-not-trusted')
name: str = field(init=False, default="pgp-not-trusted")
on_yes: Callable[..., Any]
on_no: Callable[..., Any]
@dataclass
class PGPFileEncryptionError(ApplicationEvent):
name: str = field(init=False, default='pgp-file-encryption-error')
name: str = field(init=False, default="pgp-file-encryption-error")
error: str

View File

@@ -15,57 +15,55 @@
# along with PGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import os
import time
import threading
import time
import nbxmpp
from gi.repository import GLib
from nbxmpp.namespaces import Namespace
from nbxmpp.protocol import Message
from nbxmpp.structs import EncryptionData
from nbxmpp.structs import StanzaHandler
from gi.repository import GLib
from gajim.common import app
from gajim.common.const import Trust
from gajim.common.events import MessageNotSent
from gajim.common.structs import OutgoingMessage
from gajim.common.modules.base import BaseModule
from gajim.common.structs import OutgoingMessage
from gajim.plugins.plugins_i18n import _
from pgp.backend.python_gnupg import PGP
from pgp.backend.store import KeyStore
from pgp.exceptions import KeyMismatch
from pgp.exceptions import NoKeyIdFound
from pgp.exceptions import SignError
from pgp.modules.events import PGPFileEncryptionError
from pgp.modules.events import PGPNotTrusted
from pgp.modules.util import prepare_stanza
from pgp.backend.store import KeyStore
from pgp.exceptions import SignError
from pgp.exceptions import KeyMismatch
from pgp.exceptions import NoKeyIdFound
# Module name
name = 'PGPLegacy'
name = "PGPLegacy"
zeroconf = True
ENCRYPTION_NAME = 'PGP'
ENCRYPTION_NAME = "PGP"
ALLOWED_TAGS = [
('request', Namespace.RECEIPTS),
('active', Namespace.CHATSTATES),
('gone', Namespace.CHATSTATES),
('inactive', Namespace.CHATSTATES),
('paused', Namespace.CHATSTATES),
('composing', Namespace.CHATSTATES),
('markable', Namespace.CHATMARKERS),
('no-store', Namespace.HINTS),
('store', Namespace.HINTS),
('no-copy', Namespace.HINTS),
('no-permanent-store', Namespace.HINTS),
('replace', Namespace.CORRECT),
('thread', None),
('reply', Namespace.REPLY),
('fallback', Namespace.FALLBACK),
('origin-id', Namespace.SID),
('reactions', Namespace.REACTIONS),
("request", Namespace.RECEIPTS),
("active", Namespace.CHATSTATES),
("gone", Namespace.CHATSTATES),
("inactive", Namespace.CHATSTATES),
("paused", Namespace.CHATSTATES),
("composing", Namespace.CHATSTATES),
("markable", Namespace.CHATMARKERS),
("no-store", Namespace.HINTS),
("store", Namespace.HINTS),
("no-copy", Namespace.HINTS),
("no-permanent-store", Namespace.HINTS),
("replace", Namespace.CORRECT),
("thread", None),
("reply", Namespace.REPLY),
("fallback", Namespace.FALLBACK),
("origin-id", Namespace.SID),
("reactions", Namespace.REACTIONS),
]
@@ -74,21 +72,26 @@ class PGPLegacy(BaseModule):
BaseModule.__init__(self, client, plugin=True)
self.handlers = [
StanzaHandler(name='message',
callback=self._message_received,
ns=Namespace.ENCRYPTED,
priority=9),
StanzaHandler(name='presence',
callback=self._on_presence_received,
ns=Namespace.SIGNED,
priority=48),
StanzaHandler(
name="message",
callback=self._message_received,
ns=Namespace.ENCRYPTED,
priority=9,
),
StanzaHandler(
name="presence",
callback=self._on_presence_received,
ns=Namespace.SIGNED,
priority=48,
),
]
self.own_jid = self._client.get_own_jid()
self._pgp = PGP()
self._store = KeyStore(self._account, self.own_jid, self._log,
self._pgp.list_keys)
self._store = KeyStore(
self._account, self.own_jid, self._log, self._pgp.list_keys
)
self._always_trust = []
self._presence_fingerprint_store = {}
@@ -112,7 +115,7 @@ class PGPLegacy(BaseModule):
key_data = self.get_contact_key_data(jid)
if key_data is None:
return False
key_id = key_data['key_id']
key_id = key_data["key_id"]
announced_fingerprint = self._presence_fingerprint_store.get(jid)
if announced_fingerprint is None:
@@ -130,24 +133,31 @@ class PGPLegacy(BaseModule):
fingerprint = self._pgp.verify(properties.status, properties.signed)
if fingerprint is None:
self._log.info('Presence from %s was signed but no corresponding '
'key was found', jid)
self._log.info(
"Presence from %s was signed but no corresponding " "key was found", jid
)
return
self._presence_fingerprint_store[jid] = fingerprint
self._log.info('Presence from %s was verified successfully, '
'fingerprint: %s', jid, fingerprint)
self._log.info(
"Presence from %s was verified successfully, " "fingerprint: %s",
jid,
fingerprint,
)
key_data = self.get_contact_key_data(jid)
if key_data is None:
self._log.info('No key assigned for contact: %s', jid)
self._log.info("No key assigned for contact: %s", jid)
return
if key_data['key_id'] != fingerprint:
self._log.warning('Fingerprint mismatch, '
'Presence was signed with fingerprint: %s, '
'Assigned key fingerprint: %s',
fingerprint, key_data['key_id'])
if key_data["key_id"] != fingerprint:
self._log.warning(
"Fingerprint mismatch, "
"Presence was signed with fingerprint: %s, "
"Assigned key fingerprint: %s",
fingerprint,
key_data["key_id"],
)
return
def _message_received(self, _con, stanza, properties):
@@ -155,15 +165,13 @@ class PGPLegacy(BaseModule):
return
remote_jid = properties.remote_jid
self._log.info('Message received from: %s', remote_jid)
self._log.info("Message received from: %s", remote_jid)
payload = self._pgp.decrypt(properties.pgp_legacy)
prepare_stanza(stanza, payload)
properties.encrypted = EncryptionData(
protocol=ENCRYPTION_NAME,
key='Unknown',
trust=Trust.UNDECIDED
protocol=ENCRYPTION_NAME, key="Unknown", trust=Trust.UNDECIDED
)
def encrypt_message(self, con, message: OutgoingMessage, callback):
@@ -181,7 +189,9 @@ class PGPLegacy(BaseModule):
always_trust = key_id in self._always_trust
self._encrypt(con, message, [key_id, own_key_id], callback, always_trust)
def _encrypt(self, con, message: OutgoingMessage, keys, callback, always_trust: bool):
def _encrypt(
self, con, message: OutgoingMessage, keys, callback, always_trust: bool
):
result = self._pgp.encrypt(message.get_text(), keys, always_trust)
encrypted_payload, error = result
if error:
@@ -194,15 +204,18 @@ class PGPLegacy(BaseModule):
message.set_encryption(
EncryptionData(
protocol=ENCRYPTION_NAME,
key='Unknown',
key="Unknown",
trust=Trust.VERIFIED,
)
)
callback(message)
def _handle_encrypt_error(self, con, error: str, message: OutgoingMessage, keys, callback):
if error.startswith('NOT_TRUSTED'):
def _handle_encrypt_error(
self, con, error: str, message: OutgoingMessage, keys, callback
):
if error.startswith("NOT_TRUSTED"):
def on_yes(checked):
if checked:
self._always_trust.append(keys[0])
@@ -219,64 +232,67 @@ class PGPLegacy(BaseModule):
@staticmethod
def _raise_message_not_sent(con, message: OutgoingMessage, error: str):
app.ged.raise_event(
MessageNotSent(client=con,
jid=str(message.contact.jid),
message=message.get_text(),
error=_('Encryption error: %s') % error,
time=time.time()))
MessageNotSent(
client=con,
jid=str(message.contact.jid),
message=message.get_text(),
error=_("Encryption error: %s") % error,
time=time.time(),
)
)
def _create_pgp_legacy_message(self, stanza: Message, payload: str) -> None:
stanza.setBody(self._get_info_message())
stanza.setTag('x', namespace=Namespace.ENCRYPTED).setData(payload)
eme_node = nbxmpp.Node('encryption',
attrs={'xmlns': Namespace.EME,
'namespace': Namespace.ENCRYPTED})
stanza.setTag("x", namespace=Namespace.ENCRYPTED).setData(payload)
eme_node = nbxmpp.Node(
"encryption",
attrs={"xmlns": Namespace.EME, "namespace": Namespace.ENCRYPTED},
)
stanza.addChild(node=eme_node)
def sign_presence(self, presence, status):
key_data = self.get_own_key_data()
if key_data is None:
self._log.warning('No own key id found, cant sign presence')
self._log.warning("No own key id found, cant sign presence")
return
try:
result = self._pgp.sign(status, key_data['key_id'])
result = self._pgp.sign(status, key_data["key_id"])
except SignError as error:
self._log.warning('Sign Error: %s', error)
self._log.warning("Sign Error: %s", error)
return
# self._log.debug(self._pgp.sign.cache_info())
self._log.info('Presence signed')
presence.setTag(Namespace.SIGNED + ' x').setData(result)
self._log.info("Presence signed")
presence.setTag(Namespace.SIGNED + " x").setData(result)
@staticmethod
def _get_info_message():
msg = '[This message is *encrypted* (See :XEP:`27`)]'
lang = os.getenv('LANG')
if lang is not None and not lang.startswith('en'):
msg = "[This message is *encrypted* (See :XEP:`27`)]"
lang = os.getenv("LANG")
if lang is not None and not lang.startswith("en"):
# we're not english: one in locale and one en
msg = _('[This message is *encrypted* (See :XEP:`27`)]') + \
' (' + msg + ')'
msg = _("[This message is *encrypted* (See :XEP:`27`)]") + " (" + msg + ")"
return msg
def _get_key_ids(self, jid):
key_data = self.get_contact_key_data(jid)
if key_data is None:
raise NoKeyIdFound('No key id found for %s' % jid)
key_id = key_data['key_id']
raise NoKeyIdFound("No key id found for %s" % jid)
key_id = key_data["key_id"]
own_key_data = self.get_own_key_data()
if own_key_data is None:
raise NoKeyIdFound('Own key id not found')
own_key_id = own_key_data['key_id']
raise NoKeyIdFound("Own key id not found")
own_key_id = own_key_data["key_id"]
return key_id, own_key_id
@staticmethod
def _cleanup_stanza(message: OutgoingMessage) -> None:
''' We make sure only allowed tags are in the stanza '''
"""We make sure only allowed tags are in the stanza"""
original_stanza = message.get_stanza()
stanza = nbxmpp.Message(
to=original_stanza.getTo(),
typ=original_stanza.getType())
to=original_stanza.getTo(), typ=original_stanza.getType()
)
stanza.setID(original_stanza.getID())
stanza.setThread(original_stanza.getThread())
for tag, ns in ALLOWED_TAGS:
@@ -286,8 +302,9 @@ class PGPLegacy(BaseModule):
message.set_stanza(stanza)
def encrypt_file(self, file, callback):
thread = threading.Thread(target=self._encrypt_file_thread,
args=(file, callback))
thread = threading.Thread(
target=self._encrypt_file_thread, args=(file, callback)
)
thread.daemon = True
thread.start()
@@ -299,8 +316,7 @@ class PGPLegacy(BaseModule):
return
stream = open(file.path, "rb")
encrypted = self._pgp.encrypt_file(stream,
[key_id, own_key_id])
encrypted = self._pgp.encrypt_file(stream, [key_id, own_key_id])
stream.close()
if not encrypted:
@@ -308,7 +324,7 @@ class PGPLegacy(BaseModule):
return
file.size = len(encrypted.data)
file.set_uri_transform_func(lambda uri: '%s.pgp' % uri)
file.set_uri_transform_func(lambda uri: "%s.pgp" % uri)
file.set_encrypted_data(encrypted.data)
GLib.idle_add(callback, file)
@@ -316,5 +332,6 @@ class PGPLegacy(BaseModule):
def _on_file_encryption_error(error):
app.ged.raise_event(PGPFileEncryptionError(error=error))
def get_instance(*args, **kwargs):
return PGPLegacy(*args, **kwargs), 'PGPLegacy'
return PGPLegacy(*args, **kwargs), "PGPLegacy"

View File

@@ -21,8 +21,8 @@ from nbxmpp.namespaces import Namespace
def prepare_stanza(stanza, plaintext):
delete_nodes(stanza, 'encrypted', Namespace.ENCRYPTED)
delete_nodes(stanza, 'body')
delete_nodes(stanza, "encrypted", Namespace.ENCRYPTED)
delete_nodes(stanza, "body")
stanza.setBody(plaintext)
@@ -34,16 +34,16 @@ def delete_nodes(stanza, name, namespace=None):
def find_gpg():
def _search(binary):
if os.name == 'nt':
gpg_cmd = binary + ' -h >nul 2>&1'
if os.name == "nt":
gpg_cmd = binary + " -h >nul 2>&1"
else:
gpg_cmd = binary + ' -h >/dev/null 2>&1'
gpg_cmd = binary + " -h >/dev/null 2>&1"
if subprocess.call(gpg_cmd, shell=True):
return False
return True
if _search('gpg2'):
return 'gpg2'
if _search("gpg2"):
return "gpg2"
if _search('gpg'):
return 'gpg'
if _search("gpg"):
return "gpg"

View File

@@ -14,29 +14,29 @@
# You should have received a copy of the GNU General Public License
# along with PGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
import logging
import os
import sys
import logging
from functools import partial
from packaging.version import Version as V
from gajim.common import app
from gajim.common import ged
from gajim.gtk.dialogs import ConfirmationCheckDialog
from gajim.gtk.dialogs import DialogButton
from gajim.gtk.dialogs import SimpleDialog
from gajim.plugins import GajimPlugin
from gajim.plugins.plugins_i18n import _
from gajim.gtk.dialogs import SimpleDialog
from gajim.gtk.dialogs import DialogButton
from gajim.gtk.dialogs import ConfirmationCheckDialog
from pgp.gtk.key import KeyDialog
from pgp.gtk.config import PGPConfigDialog
from pgp.exceptions import KeyMismatch
from pgp.gtk.config import PGPConfigDialog
from pgp.gtk.key import KeyDialog
from pgp.modules.util import find_gpg
ENCRYPTION_NAME = 'PGP'
ENCRYPTION_NAME = "PGP"
log = logging.getLogger('gajim.p.pgplegacy')
log = logging.getLogger("gajim.p.pgplegacy")
ERROR = False
try:
@@ -51,29 +51,29 @@ else:
# on a much lower version number than gnupg
# Also we need at least python-gnupg 0.3.8
v_gnupg = gnupg.__version__
if V(v_gnupg) < V('0.3.8') or V(v_gnupg) > V('1.0.0'):
log.error('We need python-gnupg >= 0.3.8')
if V(v_gnupg) < V("0.3.8") or V(v_gnupg) > V("1.0.0"):
log.error("We need python-gnupg >= 0.3.8")
ERROR = True
ERROR_MSG = None
BINARY = find_gpg()
log.info('Found GPG executable: %s', BINARY)
log.info("Found GPG executable: %s", BINARY)
if BINARY is None or ERROR:
if os.name == 'nt':
ERROR_MSG = _('Please install GnuPG / Gpg4win')
if os.name == "nt":
ERROR_MSG = _("Please install GnuPG / Gpg4win")
else:
ERROR_MSG = _('Please install python-gnupg and gnupg')
ERROR_MSG = _("Please install python-gnupg and gnupg")
else:
from pgp.modules import pgp_legacy
from pgp.backend.python_gnupg import PGP
from pgp.modules import pgp_legacy
class PGPPlugin(GajimPlugin):
def init(self):
# pylint: disable=attribute-defined-outside-init
self.description = _('PGP encryption as per XEP-0027')
self.description = _("PGP encryption as per XEP-0027")
if ERROR_MSG:
self.activatable = False
self.config_dialog = None
@@ -84,30 +84,26 @@ class PGPPlugin(GajimPlugin):
self.encryption_name = ENCRYPTION_NAME
self.allow_zeroconf = True
self.gui_extension_points = {
'encrypt' + ENCRYPTION_NAME: (self._encrypt_message, None),
'send_message' + ENCRYPTION_NAME: (
self._before_sendmessage, None),
'encryption_dialog' + ENCRYPTION_NAME: (
self._on_encryption_dialog, None),
'encryption_state' + ENCRYPTION_NAME: (
self._encryption_state, None),
'send-presence': (self._on_send_presence, None),
"encrypt" + ENCRYPTION_NAME: (self._encrypt_message, None),
"send_message" + ENCRYPTION_NAME: (self._before_sendmessage, None),
"encryption_dialog" + ENCRYPTION_NAME: (self._on_encryption_dialog, None),
"encryption_state" + ENCRYPTION_NAME: (self._encryption_state, None),
"send-presence": (self._on_send_presence, None),
}
self.modules = [pgp_legacy]
self.events_handlers = {
'pgp-not-trusted': (ged.PRECORE, self._on_not_trusted),
'pgp-file-encryption-error': (ged.PRECORE,
self._on_file_encryption_error),
"pgp-not-trusted": (ged.PRECORE, self._on_not_trusted),
"pgp-file-encryption-error": (ged.PRECORE, self._on_file_encryption_error),
}
encoding = 'utf8' if sys.platform == 'linux' else None
encoding = "utf8" if sys.platform == "linux" else None
self._pgp = PGP(BINARY, encoding=encoding)
@staticmethod
def get_pgp_module(account):
return app.get_client(account).get_module('PGPLegacy')
return app.get_client(account).get_module("PGPLegacy")
def activate(self):
pass
@@ -121,8 +117,8 @@ class PGPPlugin(GajimPlugin):
@staticmethod
def _encryption_state(_chat_control, state):
state['visible'] = True
state['authenticated'] = True
state["visible"] = True
state["authenticated"] = True
def _on_encryption_dialog(self, chat_control):
account = chat_control.account
@@ -137,17 +133,20 @@ class PGPPlugin(GajimPlugin):
@staticmethod
def _on_not_trusted(event):
ConfirmationCheckDialog(
_('Untrusted PGP key'),
_('The PGP key used to encrypt this chat is not '
'trusted. Do you really want to encrypt this '
'message?'),
_('_Do not ask me again'),
[DialogButton.make('Cancel',
text=_('_No'),
callback=event.on_no),
DialogButton.make('OK',
text=_('_Encrypt Anyway'),
callback=event.on_yes)]).show()
_("Untrusted PGP key"),
_(
"The PGP key used to encrypt this chat is not "
"trusted. Do you really want to encrypt this "
"message?"
),
_("_Do not ask me again"),
[
DialogButton.make("Cancel", text=_("_No"), callback=event.on_no),
DialogButton.make(
"OK", text=_("_Encrypt Anyway"), callback=event.on_yes
),
],
).show()
@staticmethod
def _before_sendmessage(chat_control):
@@ -156,24 +155,30 @@ class PGPPlugin(GajimPlugin):
client = app.get_client(account)
try:
valid = client.get_module('PGPLegacy').has_valid_key_assigned(jid)
valid = client.get_module("PGPLegacy").has_valid_key_assigned(jid)
except KeyMismatch as announced_key_id:
SimpleDialog(
_('PGP Key mismatch'),
_('The contact\'s key (%s) <b>does not match</b> the key '
'assigned in Gajim.') % announced_key_id)
_("PGP Key mismatch"),
_(
"The contact's key (%s) <b>does not match</b> the key "
"assigned in Gajim."
)
% announced_key_id,
)
chat_control.sendmessage = False
return
if not valid:
SimpleDialog(
_('No OpenPGP key assigned'),
_('No OpenPGP key is assigned to this contact.'))
_("No OpenPGP key assigned"),
_("No OpenPGP key is assigned to this contact."),
)
chat_control.sendmessage = False
elif client.get_module('PGPLegacy').get_own_key_data() is None:
elif client.get_module("PGPLegacy").get_own_key_data() is None:
SimpleDialog(
_('No OpenPGP key assigned'),
_('No OpenPGP key is assigned to your account.'))
_("No OpenPGP key assigned"),
_("No OpenPGP key is assigned to your account."),
)
chat_control.sendmessage = False
def _encrypt_message(self, conn, event, callback):
@@ -185,4 +190,4 @@ class PGPPlugin(GajimPlugin):
@staticmethod
def _on_file_encryption_error(event):
SimpleDialog(_('Error'), event.error)
SimpleDialog(_("Error"), event.error)