Add Encryption Plugin API
- Add extension points when receiving/sending a message - Add extension point for setting the lock image - Add extension point after clicking the send button - Add extension point when typing - Add a new menu button to choose the desired encryption - Extend the PluginManager to hold a list of encryption plugins
This commit is contained in:
parent
3e6ecccc26
commit
5116af037b
|
@ -939,6 +939,26 @@
|
|||
<property name="position">11</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="encryption_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">channel-secure-symbolic.symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">12</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="audio_buttons_hbox">
|
||||
<property name="can_focus">False</property>
|
||||
|
@ -1039,7 +1059,7 @@ audio-mic-volume-low</property>
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">12</property>
|
||||
<property name="position">13</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1050,12 +1070,9 @@ audio-mic-volume-low</property>
|
|||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">13</property>
|
||||
<property name="position">14</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="send_button">
|
||||
<property name="label" translatable="yes">_Send</property>
|
||||
|
@ -1077,6 +1094,9 @@ audio-mic-volume-low</property>
|
|||
<property name="position">15</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkWindow" id="message_window">
|
||||
<object class="GtkApplicationWindow" id="message_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="default_width">480</property>
|
||||
<property name="default_height">440</property>
|
||||
|
|
|
@ -94,6 +94,7 @@ class ChatControl(ChatControlBase):
|
|||
self.last_recv_message_id = None
|
||||
self.last_recv_message_marks = None
|
||||
self.last_message_timestamp = None
|
||||
|
||||
# for muc use:
|
||||
# widget = self.xml.get_object('muc_window_actions_button')
|
||||
self.actions_button = self.xml.get_object('message_window_actions_button')
|
||||
|
@ -302,6 +303,11 @@ class ChatControl(ChatControlBase):
|
|||
True)
|
||||
|
||||
self.update_ui()
|
||||
self.set_lock_image()
|
||||
|
||||
self.encryption_menu = self.xml.get_object('encryption_menu')
|
||||
self.encryption_menu.set_menu_model(
|
||||
gui_menu_builder.get_encryption_menu(self.contact))
|
||||
# restore previous conversation
|
||||
self.restore_conversation()
|
||||
self.msg_textview.grab_focus()
|
||||
|
@ -907,6 +913,21 @@ class ChatControl(ChatControlBase):
|
|||
self._show_lock_image(self.gpg_is_active, 'OpenPGP',
|
||||
self.gpg_is_active, loggable, True)
|
||||
|
||||
def set_lock_image(self):
|
||||
visible = self.encryption != 'disabled'
|
||||
loggable = self.session and self.session.is_loggable()
|
||||
|
||||
encryption_state = {'visible': visible,
|
||||
'enc_type': self.encryption,
|
||||
'enc_enabled': False,
|
||||
'chat_logged': loggable,
|
||||
'authenticated': False}
|
||||
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'encryption_state' + self.encryption, self, encryption_state)
|
||||
|
||||
self._show_lock_image(**encryption_state)
|
||||
|
||||
def _show_lock_image(self, visible, enc_type='', enc_enabled=False,
|
||||
chat_logged=False, authenticated=False):
|
||||
"""
|
||||
|
@ -940,6 +961,8 @@ class ChatControl(ChatControlBase):
|
|||
self.lock_image.set_sensitive(enc_enabled)
|
||||
|
||||
def _on_authentication_button_clicked(self, widget):
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'encryption_dialog' + self.encryption, self)
|
||||
if self.gpg_is_active:
|
||||
dialogs.GPGInfoWindow(self, self.parent_win.window)
|
||||
elif self.session and self.session.enable_encryption:
|
||||
|
@ -950,6 +973,14 @@ class ChatControl(ChatControlBase):
|
|||
"""
|
||||
Send a message to contact
|
||||
"""
|
||||
|
||||
if self.encryption:
|
||||
self.sendmessage = True
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'send_message' + self.encryption, self)
|
||||
if not self.sendmessage:
|
||||
return
|
||||
|
||||
message = helpers.remove_invalid_xml_chars(message)
|
||||
if message in ('', None, '\n'):
|
||||
return None
|
||||
|
@ -1481,6 +1512,8 @@ class ChatControl(ChatControlBase):
|
|||
def _on_message_tv_buffer_changed(self, textbuffer):
|
||||
super()._on_message_tv_buffer_changed(textbuffer)
|
||||
if textbuffer.get_char_count():
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'typing' + self.encryption, self)
|
||||
e2e_is_active = self.session and \
|
||||
self.session.enable_encryption
|
||||
e2e_pref = gajim.config.get_per('accounts', self.account,
|
||||
|
|
|
@ -34,6 +34,7 @@ from gi.repository import Gdk
|
|||
from gi.repository import Pango
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
import gtkgui_helpers
|
||||
import message_control
|
||||
import dialogs
|
||||
|
@ -395,6 +396,10 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self._on_window_motion_notify)
|
||||
self.handlers[id_] = parent_win.window
|
||||
|
||||
self.encryption = 'disabled'
|
||||
self.set_encryption_state()
|
||||
self.add_window_actions()
|
||||
|
||||
# PluginSystem: adding GUI extension point for ChatControlBase
|
||||
# instance object (also subclasses, eg. ChatControl or GroupchatControl)
|
||||
gajim.plugin_manager.gui_extension_point('chat_control_base', self)
|
||||
|
@ -412,6 +417,38 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
# to properly use the super, because of the old code.
|
||||
CommandTools.__init__(self)
|
||||
|
||||
def add_window_actions(self):
|
||||
action = Gio.SimpleAction.new_stateful(
|
||||
"%s-encryptiongroup" % self.contact.jid,
|
||||
GLib.VariantType.new("s"),
|
||||
GLib.Variant("s", self.encryption))
|
||||
action.connect("change-state", self.activate_encryption)
|
||||
self.parent_win.window.add_action(action)
|
||||
|
||||
def activate_encryption(self, action, param):
|
||||
encryption = param.get_string()
|
||||
if self.encryption == encryption:
|
||||
return
|
||||
|
||||
if encryption != 'disabled':
|
||||
plugin = gajim.plugin_manager.encryption_plugins[encryption]
|
||||
if not plugin.activate_encryption(self):
|
||||
return
|
||||
action.set_state(param)
|
||||
gajim.config.set_per(
|
||||
'contacts', self.contact.jid, 'encryption', encryption)
|
||||
self.encryption = encryption
|
||||
self.set_lock_image()
|
||||
|
||||
def set_encryption_state(self):
|
||||
enc = gajim.config.get_per('contacts', self.contact.jid, 'encryption')
|
||||
if enc not in gajim.plugin_manager.encryption_plugins:
|
||||
self.encryption = 'disabled'
|
||||
gajim.config.set_per(
|
||||
'contacts', self.contact.jid, 'encryption', 'disabled')
|
||||
else:
|
||||
self.encryption = enc
|
||||
|
||||
def set_speller(self):
|
||||
# now set the one the user selected
|
||||
per_type = 'contacts'
|
||||
|
@ -723,7 +760,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id,
|
||||
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
|
||||
label=label, callback=_cb, callback_args=[callback] + callback_args,
|
||||
control=self, attention=attention, correction_msg=correction_msg, automatic_message=False))
|
||||
control=self, attention=attention, correction_msg=correction_msg,
|
||||
automatic_message=False, encryption=self.encryption))
|
||||
|
||||
# Record the history of sent messages
|
||||
self.save_message(message, 'sent')
|
||||
|
|
|
@ -481,6 +481,7 @@ class Config:
|
|||
}, {}),
|
||||
'contacts': ({
|
||||
'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')],
|
||||
'encryption': [ opt_str, '', _('Encryption used for this contact.')],
|
||||
'autonegotiate_esessions': [opt_bool, False, _('Should Gajim automatically start an encrypted session with this contact when possible?')],
|
||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||
}, {}),
|
||||
|
|
|
@ -2136,6 +2136,14 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
def _nec_stanza_message_outgoing(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
encryption = gajim.config.get_per('contacts', obj.jid, 'encryption')
|
||||
if encryption != 'disabled':
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'encrypt' + encryption, self, obj, self.send_message)
|
||||
else:
|
||||
self.send_message(obj)
|
||||
|
||||
def send_message(self, obj):
|
||||
obj.msg_id = self.connection.send(obj.msg_iq, now=obj.now)
|
||||
|
||||
gajim.nec.push_incoming_event(MessageSentEvent(
|
||||
|
|
|
@ -1091,6 +1091,12 @@ class ConnectionHandlersBase:
|
|||
def _nec_message_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
|
||||
gajim.plugin_manager.gui_extension_point(
|
||||
'decrypt', self, obj, self._on_message_received)
|
||||
if not obj.encrypted:
|
||||
self._on_message_received(obj)
|
||||
|
||||
if obj.encrypted == 'xep200':
|
||||
try:
|
||||
obj.stanza = obj.session.decrypt_stanza(obj.stanza)
|
||||
|
@ -1153,6 +1159,14 @@ class ConnectionHandlersBase:
|
|||
gajim.nec.push_incoming_event(MamDecryptedMessageReceivedEvent(None,
|
||||
conn=self, msg_obj=obj))
|
||||
|
||||
def _on_message_received(self, obj):
|
||||
if isinstance(obj, MessageReceivedEvent):
|
||||
gajim.nec.push_incoming_event(
|
||||
DecryptedMessageReceivedEvent(None, conn=self, msg_obj=obj))
|
||||
else:
|
||||
gajim.nec.push_incoming_event(
|
||||
MamDecryptedMessageReceivedEvent(None, conn=self, msg_obj=obj))
|
||||
|
||||
def _nec_decrypted_message_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
|
|
|
@ -2796,6 +2796,7 @@ class MessageOutgoingEvent(nec.NetworkOutgoingEvent):
|
|||
self.attention = False
|
||||
self.correction_msg = None
|
||||
self.automatic_message = True
|
||||
self.encryption = ''
|
||||
|
||||
def get_full_jid(self):
|
||||
if self.resource:
|
||||
|
|
|
@ -781,3 +781,14 @@ def build_bookmark_menu(account):
|
|||
label = menu.get_item_attribute_value(1, 'label').get_string()
|
||||
menu.remove(1)
|
||||
menu.insert_submenu(1, label, bookmark_menu)
|
||||
|
||||
|
||||
def get_encryption_menu(contact):
|
||||
menu = Gio.Menu()
|
||||
menu.append(
|
||||
'Disabled', 'win.{}-encryptiongroup::{}'.format(contact.jid, 'disabled'))
|
||||
for encryption in gajim.plugin_manager.encryption_plugins:
|
||||
menu_action = 'win.{}-encryptiongroup::{}'.format(
|
||||
contact.jid, encryption)
|
||||
menu.append(encryption, menu_action)
|
||||
return menu
|
||||
|
|
|
@ -58,6 +58,16 @@ class GajimPlugin(object):
|
|||
|
||||
:todo: decide whether we really need this one, because class name (with
|
||||
module name) can act as such short name
|
||||
'''
|
||||
encryption_name = ''
|
||||
'''
|
||||
Name of the encryption scheme.
|
||||
|
||||
The name that Gajim displays in the encryption menu.
|
||||
Leave empty if the plugin is not an encryption plugin.
|
||||
|
||||
:type: str
|
||||
|
||||
'''
|
||||
version = ''
|
||||
'''
|
||||
|
|
|
@ -101,6 +101,12 @@ class PluginManager(metaclass=Singleton):
|
|||
'''
|
||||
Registered handlers of GUI extension points.
|
||||
'''
|
||||
|
||||
self.encryption_plugins = {}
|
||||
'''
|
||||
Registered names with instances of encryption Plugins.
|
||||
'''
|
||||
|
||||
for path in [gajim.PLUGINS_DIRS[1], gajim.PLUGINS_DIRS[0]]:
|
||||
pc = PluginManager.scan_dir_for_plugins(path)
|
||||
self.add_plugins(pc)
|
||||
|
@ -291,6 +297,10 @@ class PluginManager(metaclass=Singleton):
|
|||
elif issubclass(event_class, nec.NetworkOutgoingEvent):
|
||||
gajim.nec.unregister_outgoing_event(event_class)
|
||||
|
||||
def _remove_name_from_encryption_plugins(self, plugin):
|
||||
if plugin.encryption_name:
|
||||
del self.encryption_plugins[plugin.encryption_name]
|
||||
|
||||
@log_calls('PluginManager')
|
||||
def activate_plugin(self, plugin):
|
||||
'''
|
||||
|
@ -300,6 +310,7 @@ class PluginManager(metaclass=Singleton):
|
|||
if not plugin.active and plugin.activatable:
|
||||
|
||||
self._add_gui_extension_points_handlers_from_plugin(plugin)
|
||||
self._add_encryption_name_from_plugin(plugin)
|
||||
self._handle_all_gui_extension_points_with_plugin(plugin)
|
||||
self._register_events_handlers_in_ged(plugin)
|
||||
self._register_network_events_in_nec(plugin)
|
||||
|
@ -339,6 +350,7 @@ class PluginManager(metaclass=Singleton):
|
|||
|
||||
self._remove_events_handler_from_ged(plugin)
|
||||
self._remove_network_events_from_nec(plugin)
|
||||
self._remove_name_from_encryption_plugins(plugin)
|
||||
|
||||
# removing plug-in from active plug-ins list
|
||||
plugin.deactivate()
|
||||
|
@ -357,6 +369,10 @@ class PluginManager(metaclass=Singleton):
|
|||
self.gui_extension_points_handlers.setdefault(gui_extpoint_name,
|
||||
[]).append(gui_extpoint_handlers)
|
||||
|
||||
def _add_encryption_name_from_plugin(self, plugin):
|
||||
if plugin.encryption_name:
|
||||
self.encryption_plugins[plugin.encryption_name] = plugin
|
||||
|
||||
@log_calls('PluginManager')
|
||||
def _handle_all_gui_extension_points_with_plugin(self, plugin):
|
||||
for gui_extpoint_name, gui_extpoint_handlers in \
|
||||
|
|
Loading…
Reference in New Issue