changeset b14e72db6e7a in /home/hg/repos/gajim
details:http://hg.gajim.org/gajim?cmd=changeset;node=b14e72db6e7a description: switch from GnuPGInterface to python-gnupg, so gpg is available under windows. Fixes #5096, #3615, #1890, #996
diffstat:
debian/rules | 1 - src/common/GnuPG.py | 200 ++------- src/common/GnuPGInterface.py | 673 ------------------------------- src/common/connection.py | 19 +- src/common/gajim.py | 2 +- src/common/gnupg.py | 921 +++++++++++++++++++++++++++++++++++++++++++ src/features_window.py | 6 +- 7 files changed, 977 insertions(+), 845 deletions(-)
diffs (truncated from 1938 to 300 lines):
diff -r c3f1f5f7d238 -r b14e72db6e7a debian/rules --- a/debian/rules Mon Nov 29 18:44:16 2010 +0300 +++ b/debian/rules Mon Nov 29 18:44:22 2010 +0100 @@ -12,6 +12,5 @@ DEB_MAKE_INSTALL_TARGET = install DESTDIR=$(DEB_DESTDIR)
binary-install/gajim:: - rm $(DEB_DESTDIR)/usr/share/gajim/src/common/GnuPGInterface.py* dh_pysupport -pgajim convert $(DEB_DESTDIR)/usr/share/icons/hicolor/64x64/apps/gajim.png -resize 32x32 $(DEB_DESTDIR)/usr/share/pixmaps/gajim.xpm diff -r c3f1f5f7d238 -r b14e72db6e7a src/common/GnuPG.py --- a/src/common/GnuPG.py Mon Nov 29 18:44:16 2010 +0300 +++ b/src/common/GnuPG.py Mon Nov 29 18:44:22 2010 +0100 @@ -23,17 +23,17 @@ ##
import gajim +import os from os import tmpfile -from common import helpers
if gajim.HAVE_GPG: - import GnuPGInterface + import gnupg
- class GnuPG(GnuPGInterface.GnuPG): - def __init__(self, use_agent = False): - GnuPGInterface.GnuPG.__init__(self) + class GnuPG(gnupg.GPG): + def __init__(self, use_agent=False): + gnupg.GPG.__init__(self) + self.passphrase = None self.use_agent = use_agent - self._setup_my_options() self.always_trust = False
def _setup_my_options(self): @@ -46,166 +46,56 @@ if self.use_agent: self.options.extra_args.append('--use-agent')
- def _read_response(self, child_stdout): - # Internal method: reads all the output from GPG, taking notice - # only of lines that begin with the magic [GNUPG:] prefix. - # (See doc/DETAILS in the GPG distribution for info on GPG's - # output when --status-fd is specified.) - # - # Returns a dictionary, mapping GPG's keywords to the arguments - # for that keyword. + def encrypt(self, str_, recipients, always_trust=False): + result = super(GnuPG, self).encrypt(str_, recipients, + always_trust=always_trust, passphrase=self.passphrase)
- resp = {} - while True: - line = helpers.temp_failure_retry(child_stdout.readline) - if line == "": break - line = line.rstrip() - if line[0:9] == '[GNUPG:] ': - # Chop off the prefix - line = line[9:] - L = line.split(None, 1) - keyword = L[0] - if len(L) > 1: - resp[ keyword ] = L[1] - else: - resp[ keyword ] = "" - return resp + if result.status == 'invalid recipient': + return '', 'NOT_TRUSTED'
- def encrypt(self, str_, recipients, always_trust=False): - self.options.recipients = recipients # a list! + if result.ok: + error = '' + else: + error = result.status
- opt = ['--encrypt'] - if always_trust or self.always_trust: - opt.append('--always-trust') - proc = self.run(opt, create_fhs=['stdin', 'stdout', 'status', - 'stderr']) - proc.handles['stdin'].write(str_) - try: - proc.handles['stdin'].close() - except IOError: - pass - - output = proc.handles['stdout'].read() - try: - proc.handles['stdout'].close() - except IOError: - pass - - stat = proc.handles['status'] - resp = self._read_response(stat) - try: - proc.handles['status'].close() - except IOError: - pass - - error = proc.handles['stderr'].read() - proc.handles['stderr'].close() - - try: proc.wait() - except IOError: pass - if 'INV_RECP' in resp and resp['INV_RECP'].split()[0] == '10': - # unusable recipient "Key not trusted" - return '', 'NOT_TRUSTED' - if 'BEGIN_ENCRYPTION' in resp and 'END_ENCRYPTION' in resp: - # Encryption succeeded, even if there is output on stderr. Maybe - # verbose is on - error = '' - return self._stripHeaderFooter(output), helpers.decode_string(error) + return self._stripHeaderFooter(str(result)), error
def decrypt(self, str_, keyID): - proc = self.run(['--decrypt', '-q', '-u %s'%keyID], create_fhs=['stdin', 'stdout']) - enc = self._addHeaderFooter(str_, 'MESSAGE') - proc.handles['stdin'].write(enc) - proc.handles['stdin'].close() + data = self._addHeaderFooter(str_, 'MESSAGE') + result = super(GnuPG, self).decrypt(data, + passphrase=self.passphrase)
- output = proc.handles['stdout'].read() - proc.handles['stdout'].close() - - try: proc.wait() - except IOError: pass - return output + return str(result)
def sign(self, str_, keyID): - proc = self.run(['-b', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status', 'stderr']) - proc.handles['stdin'].write(str_) - try: - proc.handles['stdin'].close() - except IOError: - pass + result = super(GnuPG, self).sign(str_, keyid=keyID, detach=True, + passphrase=self.passphrase)
- output = proc.handles['stdout'].read() - try: - proc.handles['stdout'].close() - proc.handles['stderr'].close() - except IOError: - pass - - stat = proc.handles['status'] - resp = self._read_response(stat) - try: - proc.handles['status'].close() - except IOError: - pass - - try: proc.wait() - except IOError: pass - if 'GOOD_PASSPHRASE' in resp or 'SIG_CREATED' in resp: - return self._stripHeaderFooter(output) - if 'KEYEXPIRED' in resp: - return 'KEYEXPIRED' + if result.fingerprint: + return self._stripHeaderFooter(str(result)) +# if 'KEYEXPIRED' in resp: +# return 'KEYEXPIRED' return 'BAD_PASSPHRASE'
def verify(self, str_, sign): if str_ is None: return '' - f = tmpfile() - fd = f.fileno() - f.write(str_) - f.seek(0) + data = '-----BEGIN PGP SIGNED MESSAGE-----' + os.linesep + data = data + 'Hash: SHA1' + os.linesep + os.linesep + data = data + str_ + os.linesep + data = data + self._addHeaderFooter(sign, 'SIGNATURE') + result = super(GnuPG, self).verify(data)
- proc = self.run(['--verify', '--enable-special-filenames', '-', '-&%s'%fd], create_fhs=['stdin', 'status', 'stderr']) + if result.valid: + return result.key_id + return ''
- f.close() - sign = self._addHeaderFooter(sign, 'SIGNATURE') - proc.handles['stdin'].write(sign) - proc.handles['stdin'].close() - proc.handles['stderr'].close() - - stat = proc.handles['status'] - resp = self._read_response(stat) - proc.handles['status'].close() - - try: proc.wait() - except IOError: pass - - keyid = '' - if 'GOODSIG' in resp: - keyid = resp['GOODSIG'].split()[0] - return keyid - - def get_keys(self, secret = False): - if secret: - opt = '--list-secret-keys' - else: - opt = '--list-keys' - proc = self.run(['--with-colons', opt], - create_fhs=['stdout']) - output = proc.handles['stdout'].read() - proc.handles['stdout'].close() - - try: proc.wait() - except IOError: pass - + def get_keys(self, secret=False): keys = {} - lines = output.split('\n') - for line in lines: - sline = line.split(':') - if (sline[0] == 'sec' and secret) or \ - (sline[0] == 'pub' and not secret): - # decode escaped chars - name = eval('"' + sline[9].replace('"', '\"') + '"') - # make it unicode instance - keys[sline[4][8:]] = helpers.decode_string(name) + result = super(GnuPG, self).list_keys(secret=secret) + for key in result: + # Take first not empty uid + keys[key['keyid'][8:]] = [uid for uid in key['uids'] if uid][0] return keys
def get_secret_keys(self): @@ -216,7 +106,7 @@ Remove header and footer from data """ if not data: return '' - lines = data.split('\n') + lines = data.splitlines() while lines[0] != '': lines.remove(lines[0]) while lines[0] == '': @@ -233,9 +123,9 @@ """ Add header and footer from data """ - out = "-----BEGIN PGP %s-----\n" % type_ - out = out + "Version: PGP\n" - out = out + "\n" - out = out + data + "\n" - out = out + "-----END PGP %s-----\n" % type_ + out = "-----BEGIN PGP %s-----" % type_ + os.linesep + out = out + "Version: PGP" + os.linesep + out = out + os.linesep + out = out + data + os.linesep + out = out + "-----END PGP %s-----" % type_ + os.linesep return out diff -r c3f1f5f7d238 -r b14e72db6e7a src/common/GnuPGInterface.py --- a/src/common/GnuPGInterface.py Mon Nov 29 18:44:16 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,673 +0,0 @@ -# -*- coding:utf-8 -*- -## src/common/GnuPGInterface.py -## -## Copyright (C) 2001 Frank J. Tobin <ftobin AT neverending.org> -## Copyright (C) 2005 Nikos Kouremenos <kourem AT gmail.com> -## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org> -## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.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/. -## - -""" -Interface to GNU Privacy Guard (GnuPG) - -GnuPGInterface is a Python module to interface with GnuPG. -It concentrates on interacting with GnuPG via filehandles, -providing access to control GnuPG via versatile and extensible means. - -This module is based on GnuPG::Interface, a Perl module by the same author. - -Normally, using this module will involve creating a -GnuPG object, setting some options in it's 'options' data member -(which is of type Options), creating some pipes