Files
gajim-plugins/pgp/gtk/key.py
2026-01-02 17:43:40 +01:00

202 lines
6.1 KiB
Python

# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of the PGP Gajim Plugin.
#
# PGP Gajim Plugin 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.
#
# PGP Gajim Plugin 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 PGP Gajim Plugin. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import Any
from typing import cast
from typing import TYPE_CHECKING
from collections.abc import Callable
from pathlib import Path
from gi.repository import GLib
from gi.repository import Gtk
from nbxmpp import JID
from gajim.common import app
from gajim.gtk.window import GajimAppWindow
from gajim.plugins.helpers import get_builder
from gajim.plugins.plugins_i18n import _
from ..modules.pgp_legacy import PGPLegacy
if TYPE_CHECKING:
from ..plugin import PGPPlugin
class ChooseKeyBuilder(Gtk.Builder):
liststore: Gtk.ListStore
box: Gtk.Box
keys_treeview: Gtk.TreeView
cancel_button: Gtk.Button
ok_button: Gtk.Button
class KeyDialog(GajimAppWindow):
def __init__(
self, plugin: PGPPlugin, account: str, jid: JID, transient: Gtk.Window
) -> None:
GajimAppWindow.__init__(
self,
name="PGPKeyDialog",
title=_("Assign key for %s") % jid,
default_width=450,
transient_for=transient,
modal=True,
add_window_padding=True,
header_bar=True,
)
self.set_resizable(True)
self._plugin = plugin
self._jid = str(jid)
self._module = cast(
PGPLegacy,
app.get_client(account).get_module("PGPLegacy"), # pyright: ignore
)
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.set_halign(Gtk.Align.CENTER)
self._assign_button.set_margin_top(18)
self._connect(self._assign_button, "clicked", self._choose_key)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.append(self._label)
box.append(self._assign_button)
self.set_child(box)
self._load_key()
self.show()
def _cleanup(self) -> None:
del self._plugin
del self._module
def _choose_key(self, _button: Gtk.Button) -> None:
ChooseGPGKeyDialog(self._module.pgp_backend.get_keys(), self, self._on_response)
def _load_key(self) -> None:
key_data = self._module.get_contact_key_data(self._jid)
if key_data is None:
self._set_key(None)
else:
key_id, key_user = key_data.values()
self._set_key((key_id, key_user))
def _on_response(self, key: tuple[str, str] | None) -> None:
if key is None:
self._module.set_contact_key_data(self._jid, None)
self._set_key(None)
else:
self._module.set_contact_key_data(self._jid, key)
self._set_key(key)
def _set_key(self, key_data: tuple[str, str] | None) -> None:
if key_data is None:
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))
)
class ChooseGPGKeyDialog(GajimAppWindow):
def __init__(
self,
secret_keys: dict[str, str],
transient: Gtk.Window,
callback: Callable[[tuple[str, str] | None], None],
) -> None:
GajimAppWindow.__init__(
self,
name="PGPChooseKeyDialog",
title=_("Assign PGP Key"),
default_width=450,
default_height=400,
transient_for=transient,
modal=True,
add_window_padding=True,
header_bar=True,
)
secret_keys[_("None")] = _("None")
self.set_resizable(True)
self._callback = callback
self._selected_key = None
ui_path = Path(__file__).parent
self._ui = cast(
ChooseKeyBuilder, get_builder(str(ui_path.resolve() / "choose_key.ui"))
)
self._connect(self._ui.cancel_button, "clicked", self._on_cancel)
self._connect(self._ui.ok_button, "clicked", self._on_ok)
self._connect(self._ui.keys_treeview, "cursor-changed", self._on_row_changed)
model = cast(Gtk.ListStore, self._ui.keys_treeview.get_model())
model.set_sort_func(1, self._sort)
for key_id, key_label in secret_keys.items():
model.append((key_id, key_label))
self.set_child(self._ui.box)
self.show()
def _cleanup(self) -> None:
del self._callback
@staticmethod
def _sort(
model: Gtk.TreeModel, iter1: Gtk.TreeIter, iter2: Gtk.TreeIter, _data: Any
) -> int:
value1 = model[iter1][1]
value2 = model[iter2][1]
if value1 == _("None"):
return -1
if value2 == _("None"):
return 1
if value1 < value2:
return -1
return 1
def _on_cancel(self, _button: Gtk.Button) -> None:
self.close()
def _on_ok(self, _button: Gtk.Button) -> None:
self._callback(self._selected_key)
self.close()
def _on_row_changed(self, treeview: Gtk.TreeView) -> None:
selection = treeview.get_selection()
model, iter_ = selection.get_selected()
if iter_ is None:
self._selected_key = None
else:
key_id, key_user = model[iter_][0], model[iter_][1]
if key_id == _("None"):
self._selected_key = None
else:
self._selected_key = key_id, key_user