Commit 9d75c779 authored by Philipp Hörist's avatar Philipp Hörist

Remove GPG code from Gajim

Code moved into plugin
parent 64bac1d9
......@@ -179,11 +179,6 @@ def on_merge_accounts(action, param):
app.interface.roster.setup_and_draw_roster()
def on_use_pgp_agent(action, param):
action.set_state(param)
app.config.set('use_gpg_agent', param.get_boolean())
def on_add_account(action, param):
if 'account_creation_wizard' in app.interface.instances:
app.interface.instances['account_creation_wizard'].window.present()
......
......@@ -388,12 +388,6 @@ def add_actions(self):
act.connect('change-state', app_actions.on_merge_accounts)
self.add_action(act)
act = Gio.SimpleAction.new_stateful(
'agent', None,
GLib.Variant.new_boolean(app.config.get('use_gpg_agent')))
act.connect('change-state', app_actions.on_use_pgp_agent)
self.add_action(act)
# General Actions
general_actions = [
......
......@@ -399,12 +399,8 @@ def _update_toolbar(self):
'Show a list of formattings'))
else:
self._formattings_button.set_sensitive(False)
if self.contact.supports(NS_XHTML_IM):
self._formattings_button.set_tooltip_text(_('Formatting is not '
'available so long as GPG is active'))
else:
self._formattings_button.set_tooltip_text(_('This contact does '
'not support HTML'))
self._formattings_button.set_tooltip_text(
_('This contact does not support HTML'))
# Jingle detection
if self.contact.supports(NS_JINGLE_ICE_UDP) and \
......@@ -922,7 +918,7 @@ def _message_sent(self, obj):
correct_id=obj.correct_id,
additional_data=obj.additional_data)
def send_message(self, message, keyID='', xhtml=None,
def send_message(self, message, xhtml=None,
process_commands=True, attention=False):
"""
Send a message to contact
......@@ -939,12 +935,8 @@ def send_message(self, message, keyID='', xhtml=None,
if message in ('', None, '\n'):
return None
contact = self.contact
keyID = contact.keyID
ChatControlBase.send_message(self,
message,
keyID,
type_='chat',
xhtml=xhtml,
process_commands=process_commands,
......@@ -1426,9 +1418,6 @@ def got_disconnected(self):
self.update_actions()
def update_status_display(self, name, uf_show, status):
"""
Print the contact's status and update the status/GPG image
"""
self.update_ui()
self.parent_win.redraw_tab(self)
......
......@@ -773,7 +773,7 @@ def get_seclabel(self):
label = labels[lname]
return label
def send_message(self, message, keyID='', type_='chat',
def send_message(self, message, type_='chat',
resource=None, xhtml=None, process_commands=True, attention=False):
"""
Send the given message to the active tab. Doesn't return None if error
......@@ -797,7 +797,7 @@ def send_message(self, message, keyID='', type_='chat',
app.nec.push_outgoing_event(MessageOutgoingEvent(None,
account=self.account, jid=self.contact.jid, message=message,
keyID=keyID, type_=type_, chatstate=chatstate,
type_=type_, chatstate=chatstate,
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label, control=self, attention=attention, correct_id=correct_id,
automatic_message=False, encryption=self.encryption))
......
......@@ -35,7 +35,6 @@
import logging
import uuid
from pathlib import Path
from distutils.version import LooseVersion as V
from collections import namedtuple
import nbxmpp
......@@ -191,8 +190,6 @@
_dependencies = {
'AVAHI': False,
'PYBONJOUR': False,
'PYGPG': False,
'GPG_BINARY': False,
'FARSTREAM': False,
'GEOCLUE': False,
'UPNP': False,
......@@ -203,9 +200,6 @@
def is_installed(dependency):
if dependency == 'GPG':
# Alias for checking python-gnupg and the GPG binary
return _dependencies['PYGPG'] and _dependencies['GPG_BINARY']
if dependency == 'ZEROCONF':
# Alias for checking zeroconf libs
return _dependencies['AVAHI'] or _dependencies['PYBONJOUR']
......@@ -246,40 +240,6 @@ def detect_dependencies():
except Exception:
pass
# python-gnupg
try:
import gnupg
# We need https://pypi.python.org/pypi/python-gnupg
# but https://pypi.python.org/pypi/gnupg shares the same package name.
# It cannot be used as a drop-in replacement.
# We test with a version check if python-gnupg is installed as it is
# 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('gajim').info('Gajim needs python-gnupg >= 0.3.8')
raise ImportError
_dependencies['PYGPG'] = True
except ImportError:
pass
# GPG BINARY
import subprocess
def test_gpg(binary='gpg'):
if os.name == 'nt':
gpg_cmd = binary + ' -h >nul 2>&1'
else:
gpg_cmd = binary + ' -h >/dev/null 2>&1'
if subprocess.call(gpg_cmd, shell=True):
return False
return True
if test_gpg(binary='gpg2'):
_dependencies['GPG_BINARY'] = 'gpg2'
elif test_gpg(binary='gpg'):
_dependencies['GPG_BINARY'] = 'gpg'
# FARSTREAM
try:
if os.name == 'nt':
......@@ -354,9 +314,6 @@ def test_gpg(binary='gpg'):
log('gajim').info('Used language: %s', LANG)
def get_gpg_binary():
return _dependencies['GPG_BINARY']
def get_an_id():
return str(uuid.uuid4())
......
......@@ -167,7 +167,6 @@ class Config:
'time_stamp': [opt_str, '[%X] ', _('This option let you customize timestamp that is printed in conversation. For example "[%H:%M] " will show "[hour:minute] ". See python doc on strftime for full documentation: http://docs.python.org/lib/module-time.html')],
'before_nickname': [opt_str, '', _('Characters that are printed before the nickname in conversations')],
'after_nickname': [opt_str, ':', _('Characters that are printed after the nickname in conversations')],
'use_gpg_agent': [opt_bool, False],
'change_roster_title': [opt_bool, True, _('Add * and [n] in roster title?')],
'restore_lines': [opt_int, 10, _('How many history messages should be restored when a chat tab/window is reopened?')],
'restore_timeout': [opt_int, -1, _('How far back in time (minutes) history is restored. -1 means no limit.')],
......@@ -285,7 +284,6 @@ class Config:
'positive_184_ack': [opt_bool, False, _('If enabled, Gajim will show an icon to show that sent message has been received by your contact')],
'show_avatar_in_tabs': [opt_bool, False, _('Show a mini avatar in chat window tabs and in window icon')],
'use_keyring': [opt_bool, True, _('If true, Gajim will use the Systems Keyring to store account passwords.')],
'pgp_encoding': [opt_str, '', _('Sets the encoding used by python-gnupg'), True],
'remote_commands': [opt_bool, False, _('If true, Gajim will execute XEP-0146 Commands.')],
'dark_theme': [opt_int, 2, _('2: System, 1: Enabled, 0: Disabled')],
'threshold_options': [opt_str, '1, 2, 4, 10, 0', _('Options in days which can be chosen in the sync threshold menu'), True],
......@@ -325,7 +323,6 @@ class Config:
'active': [opt_bool, True, _('If False, this account will be disabled and will not appear in roster window.'), True],
'proxy': [opt_str, '', '', True],
'keyid': [opt_str, '', '', True],
'gpg_sign_presence': [opt_bool, True, _('If disabled, don\'t sign presences with GPG key, even if GPG is configured.')],
'keyname': [opt_str, '', '', True],
'allow_plaintext_connection': [opt_bool, False, _('Allow plaintext connections')],
'tls_version': [opt_str, '1.2', ''],
......
......@@ -55,7 +55,6 @@
from gajim import common
from gajim.common import helpers
from gajim.common import app
from gajim.common import gpg
from gajim.common import passwords
from gajim.common import idle
from gajim.common import modules
......@@ -66,8 +65,6 @@
from gajim.common.contacts import GC_Contact
from gajim.common.connection_handlers import ConnectionHandlers
from gajim.common.connection_handlers_events import OurShowEvent
from gajim.common.connection_handlers_events import BadGPGPassphraseEvent
from gajim.common.connection_handlers_events import GPGPasswordRequiredEvent
from gajim.common.connection_handlers_events import InformationEvent
from gajim.common.connection_handlers_events import StanzaMessageOutgoingEvent
from gajim.common.connection_handlers_events import GcStanzaMessageOutgoingEvent
......@@ -105,11 +102,6 @@ def __init__(self, name):
self.is_zeroconf = False
self.password = None
self.server_resource = self._compute_resource()
self.gpg = None
self.USE_GPG = False
if app.is_installed('GPG'):
self.USE_GPG = True
self.gpg = gpg.GnuPG()
self.status = ''
self.old_show = ''
self.priority = app.get_priority(name, 'offline')
......@@ -187,43 +179,6 @@ def quit(self, kill_core):
if kill_core and app.account_is_connected(self.name):
self.disconnect(reconnect=False)
def test_gpg_passphrase(self, password):
"""
Returns 'ok', 'bad_pass' or 'expired'
"""
if not self.gpg:
return False
self.gpg.passphrase = password
keyID = app.config.get_per('accounts', self.name, 'keyid')
signed = self.gpg.sign('test', keyID)
self.gpg.password = None
if signed == 'KEYEXPIRED':
return 'expired'
if signed == 'BAD_PASSPHRASE':
return 'bad_pass'
return 'ok'
def get_signed_msg(self, msg, callback=None):
"""
Returns the signed message if possible or an empty string if gpg is not
used or None if waiting for passphrase
callback is the function to call when user give the passphrase
"""
signed = ''
keyID = app.config.get_per('accounts', self.name, 'keyid')
if keyID and self.USE_GPG:
if self.gpg.passphrase is None and not self.gpg.use_agent:
# We didn't set a passphrase
return None
signed = self.gpg.sign(msg, keyID)
if signed == 'BAD_PASSPHRASE':
self.USE_GPG = False
signed = ''
app.nec.push_incoming_event(BadGPGPassphraseEvent(None,
conn=self))
return signed
def get_status(self):
return app.SHOW_LIST[self.connected]
......@@ -432,25 +387,6 @@ def send_agent_status(self, agent, ptype):
"""
raise NotImplementedError
def gpg_passphrase(self, passphrase):
if self.gpg:
if self.gpg.use_agent:
self.gpg.passphrase = None
else:
self.gpg.passphrase = passphrase
def ask_gpg_keys(self, keyID=None):
if self.gpg:
if keyID:
return self.gpg.get_key(keyID)
return self.gpg.get_keys()
return None
def ask_gpg_secrete_keys(self):
if self.gpg:
return self.gpg.get_secret_keys()
return None
def _event_dispatcher(self, realm, event, data):
if realm == '':
if event == 'STANZA RECEIVED':
......@@ -467,9 +403,7 @@ def _event_dispatcher(self, realm, event, data):
def change_status(self, show, msg, auto=False):
if not msg:
msg = ''
sign_msg = False
if not auto and not show == 'offline':
sign_msg = True
if show != 'invisible':
# We save it only when privacy list is accepted
self.status = msg
......@@ -478,10 +412,7 @@ def change_status(self, show, msg, auto=False):
# recconect before we auth to server
self.old_show = show
self.server_resource = self._compute_resource()
if app.is_installed('GPG'):
self.USE_GPG = True
self.gpg = gpg.GnuPG()
self.connect_and_init(show, msg, sign_msg)
self.connect_and_init(show, msg)
return
if show == 'offline':
......@@ -615,7 +546,7 @@ def reconnect(self):
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='connecting'))
self.retrycount += 1
self.connect_and_init(self.old_show, self.status, self.USE_GPG)
self.connect_and_init(self.old_show, self.status)
else:
log.info('Reconnect successfull')
# reconnect succeeded
......@@ -784,9 +715,7 @@ def _on_register_result(result):
app.nec.push_incoming_event(NetworkEvent(
'account-not-created', conn=self, reason=reason))
return
if app.is_installed('GPG'):
self.USE_GPG = True
self.gpg = gpg.GnuPG()
app.nec.push_incoming_event(
NetworkEvent('account-created',
conn=self,
......@@ -1439,7 +1368,7 @@ def _send_keepalive(self):
if self.connection:
self.connection.send(' ')
def send_invisible_presence(self, msg, signed, initial=False):
def send_invisible_presence(self, msg, initial=False):
if not app.account_is_connected(self.name):
return
if not self.get_module('PrivacyLists').supported:
......@@ -1461,7 +1390,6 @@ def send_invisible_presence(self, msg, signed, initial=False):
self.get_module('PrivacyLists').set_invisible_rule(
callback=self._continue_invisible,
msg=msg,
signed=signed,
initial=initial)
def _continue_invisible(self, con, iq_obj, msg, signed, initial):
......@@ -1475,8 +1403,7 @@ def _continue_invisible(self, con, iq_obj, msg, signed, initial):
self.get_module('Presence').send_presence(
priority=priority,
status=msg,
sign=signed)
status=msg)
self.priority = priority
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
......@@ -1501,19 +1428,14 @@ def _continue_invisible(self, con, iq_obj, msg, signed, initial):
# Inform GUI we just signed in
app.nec.push_incoming_event(NetworkEvent('signed-in', conn=self))
def get_signed_presence(self, msg, callback=None):
if app.config.get_per('accounts', self.name, 'gpg_sign_presence'):
return self.get_signed_msg(msg, callback)
return ''
def connect_and_auth(self):
self.on_connect_success = self._connect_success
self.on_connect_failure = self._connect_failure
self.connect()
def connect_and_init(self, show, msg, sign_msg):
def connect_and_init(self, show, msg):
self.disable_reconnect_timer()
self.continue_connect_info = [show, msg, sign_msg]
self.continue_connect_info = [show, msg]
self.connect_and_auth()
def _discover_server(self):
......@@ -1564,40 +1486,16 @@ def discover_ft_proxies(self):
app.proxy65_manager.resolve(proxy, self.connection, our_jid,
testit=testit)
def send_first_presence(self):
if self.connected > 1 and self.continue_connect_info:
msg = self.continue_connect_info[1]
sign_msg = self.continue_connect_info[2]
signed = ''
send_first_presence = True
if sign_msg:
signed = self.get_signed_presence(msg,
self._send_first_presence)
if signed is None:
app.nec.push_incoming_event(GPGPasswordRequiredEvent(None,
conn=self, callback=self._send_first_presence))
# _send_first_presence will be called when user enter
# passphrase
send_first_presence = False
if send_first_presence:
self._send_first_presence(signed)
def _send_first_presence(self, signed=''):
def send_first_presence(self, signed=''):
if self.connected <= 1 or not self.continue_connect_info:
return
show = self.continue_connect_info[0]
msg = self.continue_connect_info[1]
sign_msg = self.continue_connect_info[2]
if sign_msg and not signed:
signed = self.get_signed_presence(msg)
if signed is None:
app.nec.push_incoming_event(BadGPGPassphraseEvent(None,
conn=self))
self.USE_GPG = False
signed = ''
self.connected = app.SHOW_LIST.index(show)
sshow = helpers.get_xmpp_show(show)
# send our presence
if show == 'invisible':
self.send_invisible_presence(msg, signed, True)
self.send_invisible_presence(msg, True)
return
if show not in ['offline', 'online', 'chat', 'away', 'xa', 'dnd']:
return
......@@ -1606,8 +1504,7 @@ def _send_first_presence(self, signed=''):
self.get_module('Presence').send_presence(
priority=priority,
show=sshow,
status=msg,
sign=signed)
status=msg)
if self.connection:
self.priority = priority
......@@ -1643,18 +1540,15 @@ def send_custom_status(self, show, msg, jid):
status=msg)
else:
signed = self.get_signed_presence(msg)
priority = app.get_priority(self.name, sshow)
self.get_module('Presence').send_presence(
jid,
priority=priority,
show=sshow,
status=msg,
sign=signed)
status=msg)
def _change_to_invisible(self, msg):
signed = self.get_signed_presence(msg)
self.send_invisible_presence(msg, signed)
self.send_invisible_presence(msg)
def _change_from_invisible(self):
if self.get_module('PrivacyLists').supported:
......@@ -1663,13 +1557,11 @@ def _change_from_invisible(self):
def _update_status(self, show, msg, idle_time=None):
xmpp_show = helpers.get_xmpp_show(show)
priority = app.get_priority(self.name, xmpp_show)
signed = self.get_signed_presence(msg)
self.get_module('Presence').send_presence(
priority=priority,
show=xmpp_show,
status=msg,
sign=signed,
idle_time=idle_time)
if self.connection:
......@@ -1862,7 +1754,7 @@ def _nec_gc_stanza_message_outgoing(self, obj):
def send_gc_message(self, obj):
obj.stanza_id = self.connection.send(obj.msg_iq)
app.nec.push_incoming_event(MessageSentEvent(
None, conn=self, jid=obj.jid, message=obj.message, keyID=None,
None, conn=self, jid=obj.jid, message=obj.message,
automatic_message=obj.automatic_message,
stanza_id=obj.stanza_id, additional_data=obj.additional_data))
......
......@@ -153,15 +153,6 @@ def generate(self):
class NewAccountNotConnectedEvent(nec.NetworkIncomingEvent):
name = 'new-account-not-connected'
class BadGPGPassphraseEvent(nec.NetworkIncomingEvent):
name = 'bad-gpg-passphrase'
def generate(self):
self.account = self.conn.name
self.use_gpg_agent = app.config.get('use_gpg_agent')
self.keyID = app.config.get_per('accounts', self.conn.name, 'keyid')
return True
class ConnectionLostEvent(nec.NetworkIncomingEvent):
name = 'connection-lost'
......@@ -170,13 +161,6 @@ def generate(self):
show='offline'))
return True
class GPGPasswordRequiredEvent(nec.NetworkIncomingEvent):
name = 'gpg-password-required'
def generate(self):
self.keyid = app.config.get_per('accounts', self.conn.name, 'keyid')
return True
class FileRequestReceivedEvent(nec.NetworkIncomingEvent):
name = 'file-request-received'
......@@ -610,7 +594,6 @@ class MessageOutgoingEvent(nec.NetworkOutgoingEvent):
def init(self):
self.additional_data = AdditionalDataDict()
self.message = None
self.keyID = None
self.type_ = 'chat'
self.kind = None
self.timestamp = None
......
......@@ -23,7 +23,6 @@ class OptionKind(IntEnum):
PRIORITY = 9
FILECHOOSER = 10
CHANGEPASSWORD = 11
GPG = 12
@unique
......
......@@ -137,7 +137,7 @@ class Contact(CommonContact):
Information concerning a contact
"""
def __init__(self, jid, account, name='', groups=None, show='', status='',
sub='', ask='', resource='', priority=0, keyID='', client_caps=None,
sub='', ask='', resource='', priority=0, client_caps=None,
chatstate=None, idle_time=None, avatar_sha=None, groupchat=False,
is_pm_contact=False):
if not isinstance(jid, str):
......@@ -159,7 +159,6 @@ def __init__(self, jid, account, name='', groups=None, show='', status='',
self.ask = ask
self.priority = priority
self.keyID = keyID
self.idle_time = idle_time
self.pep = {}
......@@ -306,7 +305,7 @@ def remove_account(self, account):
self._metacontact_manager.remove_account(account)
def create_contact(self, jid, account, name='', groups=None, show='',
status='', sub='', ask='', resource='', priority=0, keyID='',
status='', sub='', ask='', resource='', priority=0,
client_caps=None, chatstate=None, idle_time=None,
avatar_sha=None, groupchat=False):
if groups is None:
......@@ -315,36 +314,36 @@ def create_contact(self, jid, account, name='', groups=None, show='',
account = self._accounts.get(account, account)
return Contact(jid=jid, account=account, name=name, groups=groups,
show=show, status=status, sub=sub, ask=ask, resource=resource,
priority=priority, keyID=keyID, client_caps=client_caps,
priority=priority, client_caps=client_caps,
chatstate=chatstate, idle_time=idle_time, avatar_sha=avatar_sha,
groupchat=groupchat)
def create_self_contact(self, jid, account, resource, show, status, priority,
name='', keyID=''):
name=''):
conn = common.app.connections[account]
nick = name or common.app.nicks[account]
account = self._accounts.get(account, account) # Use Account object if available
self_contact = self.create_contact(jid=jid, account=account,
name=nick, groups=['self_contact'], show=show, status=status,
sub='both', ask='none', priority=priority, keyID=keyID,
sub='both', ask='none', priority=priority,
resource=resource)
self_contact.pep = conn.pep
return self_contact
def create_not_in_roster_contact(self, jid, account, resource='', name='',
keyID='', groupchat=False):
groupchat=False):
# Use Account object if available
account = self._accounts.get(account, account)
return self.create_contact(jid=jid, account=account, resource=resource,
name=name, groups=[_('Not in Roster')], show='not in roster',
status='', sub='none', keyID=keyID, groupchat=groupchat)
status='', sub='none', groupchat=groupchat)
def copy_contact(self, contact):
return self.create_contact(contact.jid, contact.account,
name=contact.name, groups=contact.groups, show=contact.show,
status=contact.status, sub=contact.sub, ask=contact.ask,
resource=contact.resource, priority=contact.priority,
keyID=contact.keyID, client_caps=contact.client_caps,
client_caps=contact.client_caps,
chatstate=contact.chatstate_enum,
idle_time=contact.idle_time, avatar_sha=contact.avatar_sha)
......
# Copyright (C) 2003-2014 Yann Leboulanger <asterix AT lagaule.org>
# Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
# Copyright (C) 2005-2006 Nikos Kouremenos <kourem AT gmail.com>
# Copyright (C) 2007 Stephan Erb <steve-e AT h3c.de>
# Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
# Jonathan Schleifer <js-gajim AT webkeks.org>
#
# This file is part of Gajim.
#
# Gajim 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.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
import os
from gajim.common import app
if app.is_installed('GPG'):
import gnupg
class GnuPG(gnupg.GPG):
def __init__(self):
use_agent = app.config.get('use_gpg_agent')
gnupg.GPG.__init__(self, gpgbinary=app.get_gpg_binary(), use_agent=use_agent)
encoding = app.config.get('pgp_encoding')
if encoding:
self.encoding = encoding
self.decode_errors = 'replace'
self.passphrase = None