← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-gpg into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-gpg into launchpad:master.

Commit message:
Fix various GPG-related tests on Python 3

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/398386

We generally just need to be a bit more careful about bytes vs. text types.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-gpg into launchpad:master.
diff --git a/lib/lp/registry/model/codeofconduct.py b/lib/lp/registry/model/codeofconduct.py
index cc484b9..421440e 100644
--- a/lib/lp/registry/model/codeofconduct.py
+++ b/lib/lp/registry/model/codeofconduct.py
@@ -321,7 +321,7 @@ class SignedCodeOfConductSet:
         current = coc.content
 
         # calculate text digest
-        if sig.plain_data.split() != current.split():
+        if sig.plain_data.split() != current.encode('UTF-8').split():
             return ('The signed text does not match the Code of Conduct. '
                     'Make sure that you signed the correct text (white '
                     'space differences are acceptable).')
diff --git a/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.txt b/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.txt
index d705ecd..e1ba1e0 100644
--- a/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.txt
+++ b/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.txt
@@ -508,9 +508,9 @@ Get the token from the body of the email sent.
     >>> msg = email.message_from_string(raw_msg)
     >>> cipher_body = msg.get_payload(decode=1)
     >>> body = decrypt_content(cipher_body, six.ensure_str('test'))
-    >>> link = re.findall(r'http.*/token/.*', body)[0]
+    >>> link = get_token_url_from_bytes(body)
     >>> token = re.sub(r'.*token/', '', link)
-    >>> token_url = 'http://launchpad.test/token/%s' % token.encode('ascii')
+    >>> token_url = 'http://launchpad.test/token/%s' % token
 
 
 Going to the token page will get us redirected to the page of that specific
diff --git a/lib/lp/registry/tests/test_codeofconduct.py b/lib/lp/registry/tests/test_codeofconduct.py
index e8b2bd3..baf64a2 100644
--- a/lib/lp/registry/tests/test_codeofconduct.py
+++ b/lib/lp/registry/tests/test_codeofconduct.py
@@ -156,9 +156,8 @@ class TestSignedCodeOfConductSet(TestCaseWithFactory):
     def test_verifyAndStore_good(self):
         user = self.factory.makePerson()
         gpgkey = self.factory.makeGPGKey(user)
-        signature = PymeSignature(
-            gpgkey.fingerprint,
-            getUtility(ICodeOfConductSet).current_code_of_conduct.content)
+        current = getUtility(ICodeOfConductSet).current_code_of_conduct.content
+        signature = PymeSignature(gpgkey.fingerprint, current.encode("UTF-8"))
         self.useFixture(ZopeUtilityFixture(
             FakeGPGHandlerGood(signature), IGPGHandler))
         self.assertIsNone(
diff --git a/lib/lp/services/gpg/handler.py b/lib/lp/services/gpg/handler.py
index d2ace9e..643246b 100644
--- a/lib/lp/services/gpg/handler.py
+++ b/lib/lp/services/gpg/handler.py
@@ -347,7 +347,7 @@ class GPGHandler:
         # http://pyme.sourceforge.net/doc/gpgme/Generating-Keys.html
         with gpgme_timeline("genkey", name):
             result = context.genkey(
-                signing_only_param % {'name': name.encode('utf-8')})
+                six.ensure_str(signing_only_param % {'name': name}))
 
         # Right, it might seem paranoid to have this many assertions,
         # but we have to take key generation very seriously.
@@ -432,7 +432,7 @@ class GPGHandler:
             del os.environ['GPG_AGENT_INFO']
 
         def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd):
-            os.write(fd, '%s\n' % password)
+            os.write(fd, six.ensure_binary('%s\n' % password))
         context.passphrase_cb = passphrase_cb
 
         # Sign the text.
@@ -469,7 +469,7 @@ class GPGHandler:
         # global one. It should basically consists of be
         # aware of a revoked flag coming from the global
         # key ring, but it needs "specing"
-        key = PymeKey(fingerprint.encode('ascii'))
+        key = PymeKey(fingerprint)
         if not key.exists_in_local_keyring:
             pubkey = self._getPubKey(fingerprint)
             key = self.importPublicKey(pubkey)
@@ -565,13 +565,13 @@ class GPGHandler:
             # We can extract the fact that the key is unknown by looking
             # into the response's content.
             if exc.response.status_code in (404, 500):
-                no_key_message = 'No results found: No keys found'
+                no_key_message = b'No results found: No keys found'
                 if exc.response.content.find(no_key_message) >= 0:
                     raise GPGKeyDoesNotExistOnServer(fingerprint)
                 errorlog.globalErrorUtility.raising(sys.exc_info(), request)
                 raise GPGKeyTemporarilyNotFoundError(fingerprint)
             raise
-        except (TimeoutError, requests.RequestException) as exc:
+        except (TimeoutError, requests.RequestException):
             errorlog.globalErrorUtility.raising(sys.exc_info(), request)
             raise GPGKeyTemporarilyNotFoundError(fingerprint)
         finally:
diff --git a/lib/lp/services/gpg/tests/test_gpghandler.py b/lib/lp/services/gpg/tests/test_gpghandler.py
index 5d8651e..297db6c 100644
--- a/lib/lp/services/gpg/tests/test_gpghandler.py
+++ b/lib/lp/services/gpg/tests/test_gpghandler.py
@@ -62,7 +62,7 @@ class FakeGenerateKey(Fixture):
 
     def __init__(self, keyfile):
         filepath = os.path.join(gpgkeysdir, keyfile)
-        with open(filepath) as f:
+        with open(filepath, "rb") as f:
             self.secret_key = f.read()
 
     def _setUp(self):
@@ -483,7 +483,7 @@ class TestGPGHandler(TestCase):
         for key_name, password in secret_keys:
             self.gpg_handler.resetLocalState()
             secret_key = import_secret_test_key(key_name)
-            content = "abc\n"
+            content = b"abc\n"
             signed_content = self.gpg_handler.signContent(
                 content, secret_key, password)
             signature = self.gpg_handler.getVerifiedSignature(signed_content)
@@ -499,8 +499,9 @@ class TestGPGHandler(TestCase):
                     [get_gpg_path(), "--quiet", "--status-fd", "1",
                      "--verify"],
                     stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                    stderr=devnull, universal_newlines=True)
-            status = gpg_proc.communicate(signed_content)[0].splitlines()
+                    stderr=devnull)
+            output = six.ensure_text(gpg_proc.communicate(signed_content)[0])
+            status = output.splitlines()
             validsig_prefix = "[GNUPG:] VALIDSIG "
             [validsig_line] = [
                 line for line in status if line.startswith(validsig_prefix)]
diff --git a/lib/lp/services/verification/browser/logintoken.py b/lib/lp/services/verification/browser/logintoken.py
index 47317aa..ea05877 100644
--- a/lib/lp/services/verification/browser/logintoken.py
+++ b/lib/lp/services/verification/browser/logintoken.py
@@ -300,9 +300,9 @@ class ValidateGPGKeyView(BaseTokenView, LaunchpadFormView):
             return
 
         # We compare the word-splitted content to avoid failures due
-        # to whitepace differences.
+        # to whitespace differences.
         if (signature.plain_data.split()
-            != self.context.validation_phrase.split()):
+                != self.context.validation_phrase.encode('UTF-8').split()):
             self.addError(_(
                 'The signed content does not match the message found '
                 'in the email.'))
diff --git a/lib/lp/services/verification/model/logintoken.py b/lib/lp/services/verification/model/logintoken.py
index 4190340..4e00b8e 100644
--- a/lib/lp/services/verification/model/logintoken.py
+++ b/lib/lp/services/verification/model/logintoken.py
@@ -10,6 +10,7 @@ __all__ = [
 import hashlib
 
 import pytz
+import six
 from sqlobject import (
     ForeignKey,
     SQLObjectNotFound,
@@ -169,8 +170,8 @@ class LoginToken(SQLBase):
         # Encrypt this part's content if requested.
         if key.can_encrypt:
             gpghandler = getUtility(IGPGHandler)
-            token_text = gpghandler.encryptContent(
-                token_text.encode('utf-8'), key)
+            token_text = six.ensure_text(gpghandler.encryptContent(
+                token_text.encode('utf-8'), key))
             # In this case, we need to include some clear text instructions
             # for people who do not have an MUA that can decrypt the ASCII
             # armored text.
diff --git a/lib/lp/testing/gpgkeys/__init__.py b/lib/lp/testing/gpgkeys/__init__.py
index b2d4dca..a1d0378 100644
--- a/lib/lp/testing/gpgkeys/__init__.py
+++ b/lib/lp/testing/gpgkeys/__init__.py
@@ -24,6 +24,7 @@ import os
 
 import gpgme
 import scandir
+import six
 from zope.component import getUtility
 
 from lp.registry.interfaces.gpg import IGPGKeySet
@@ -139,7 +140,7 @@ def decrypt_content(content, password):
     plain = BytesIO()
 
     def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd):
-        os.write(fd, '%s\n' % password)
+        os.write(fd, six.ensure_binary('%s\n' % password))
 
     ctx.passphrase_cb = passphrase_cb
 
diff --git a/lib/lp/testing/keyserver/web.py b/lib/lp/testing/keyserver/web.py
index 98f204d..179155d 100644
--- a/lib/lp/testing/keyserver/web.py
+++ b/lib/lp/testing/keyserver/web.py
@@ -48,7 +48,7 @@ from lp.services.gpg.interfaces import (
     )
 
 
-GREETING = 'Copyright 2004-2009 Canonical Ltd.\n'
+GREETING = b'Copyright 2004-2009 Canonical Ltd.\n'
 
 
 def locate_key(root, suffix):
@@ -107,13 +107,13 @@ class PksResource(_BaseResource):
         self.putChild(b'add', SubmitKey(root))
 
     def render_GET(self, request):
-        return 'Welcome To Fake SKS service.\n'
+        return b'Welcome To Fake SKS service.\n'
 
 
 KEY_NOT_FOUND_BODY = (
-    "<html><head><title>Error handling request</title></head>\n"
-    "<body><h1>Error handling request</h1>No results found: "
-    "No keys found</body></html>")
+    b"<html><head><title>Error handling request</title></head>\n"
+    b"<body><h1>Error handling request</h1>No results found: "
+    b"No keys found</body></html>")
 
 
 class LookUp(Resource):
@@ -127,10 +127,10 @@ class LookUp(Resource):
 
     def render_GET(self, request):
         try:
-            action = request.args['op'][0]
-            keyid = request.args['search'][0]
+            action = request.args[b'op'][0].decode('ISO-8859-1')
+            keyid = request.args[b'search'][0].decode('ISO-8859-1')
         except KeyError:
-            return 'Invalid Arguments %s' % request.args
+            return ('Invalid Arguments %s' % request.args).encode('UTF-8')
 
         return self.processRequest(action, keyid, request)
 
@@ -139,7 +139,8 @@ class LookUp(Resource):
         # are properly handled by setting an even shorter timeout.
         sleep(0.02)
         if (action not in self.permitted_actions) or not keyid:
-            return 'Forbidden: "%s" on ID "%s"' % (action, keyid)
+            message = 'Forbidden: "%s" on ID "%s"' % (action, keyid)
+            return message.encode('UTF-8')
 
         filename = '%s.%s' % (keyid, action)
 
@@ -152,7 +153,7 @@ class LookUp(Resource):
                     '</head>\n<body>'
                     '<h1>Results for Key %s</h1>\n'
                     '<pre>\n%s\n</pre>\n</html>') % (keyid, keyid, content)
-            return page
+            return page.encode('UTF-8')
         else:
             request.setResponseCode(404)
             return KEY_NOT_FOUND_BODY
@@ -183,13 +184,13 @@ class SubmitKey(Resource):
         self.root = root
 
     def render_GET(self, request):
-        return SUBMIT_KEY_PAGE % {'banner': ''}
+        return (SUBMIT_KEY_PAGE % {'banner': ''}).encode('UTF-8')
 
     def render_POST(self, request):
         try:
-            keytext = request.args['keytext'][0]
+            keytext = request.args[b'keytext'][0]
         except KeyError:
-            return 'Invalid Arguments %s' % request.args
+            return ('Invalid Arguments %s' % request.args).encode('UTF-8')
         return self.storeKey(keytext)
 
     def storeKey(self, keytext):
@@ -198,13 +199,12 @@ class SubmitKey(Resource):
             key = gpghandler.importPublicKey(keytext)
         except (GPGKeyNotFoundError, SecretGPGKeyImportDetected,
                 MoreThanOneGPGKeyFound) as err:
-            return SUBMIT_KEY_PAGE % {'banner': str(err)}
+            return (SUBMIT_KEY_PAGE % {'banner': str(err)}).encode('UTF-8')
 
         filename = '0x%s.get' % key.fingerprint
         path = os.path.join(self.root, filename)
 
-        fp = open(path, 'w')
-        fp.write(keytext)
-        fp.close()
+        with open(path, 'wb') as fp:
+            fp.write(keytext)
 
-        return SUBMIT_KEY_PAGE % {'banner': 'Key added'}
+        return (SUBMIT_KEY_PAGE % {'banner': 'Key added'}).encode('UTF-8')