← Back to team overview

launchpad-reviewers team mailing list archive

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

 

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

Commit message:
Use correct types for base64 encoding/decoding

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

On Python 3, base64.b64encode takes bytes and returns bytes.  base64.b64decode in fact takes either bytes or ASCII-only Unicode strings and returns bytes, but it's more symmetrical and thus clearer to treat it as if it only took bytes.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-base64-types into launchpad:master.
diff --git a/lib/lp/app/browser/stringformatter.py b/lib/lp/app/browser/stringformatter.py
index c791cf7..b816ae7 100644
--- a/lib/lp/app/browser/stringformatter.py
+++ b/lib/lp/app/browser/stringformatter.py
@@ -1084,7 +1084,8 @@ class FormattersAPI:
             # we also have to strip off any padding characters ("=") because
             # Python's URL-safe base 64 encoding includes those and they
             # aren't allowed in IDs either.
-            unique_suffix = urlsafe_b64encode(raw_text)
+            unique_suffix = (
+                urlsafe_b64encode(raw_text.encode('ASCII')).decode('ASCII'))
             # Ensure we put a '-' between the id and base 64 encoding.
             if id_[-1] != '-':
                 id_ += '-'
diff --git a/lib/lp/archivepublisher/htaccess.py b/lib/lp/archivepublisher/htaccess.py
index 1d29fb8..613cfde 100644
--- a/lib/lp/archivepublisher/htaccess.py
+++ b/lib/lp/archivepublisher/htaccess.py
@@ -76,7 +76,8 @@ def make_salt(s):
     """
     # As long as the input string is at least one character long, there will
     # be no padding within the first two characters.
-    return base64.b64encode((s or " ").encode("UTF-8"), altchars=b"./")[:2]
+    return base64.b64encode(
+        (s or " ").encode("UTF-8"), altchars=b"./")[:2].decode("ASCII")
 
 
 def htpasswd_credentials_for_archive(archive):
diff --git a/lib/lp/code/scripts/tests/test_request_daily_builds.py b/lib/lp/code/scripts/tests/test_request_daily_builds.py
index 1be9b9a..0f16bc8 100644
--- a/lib/lp/code/scripts/tests/test_request_daily_builds.py
+++ b/lib/lp/code/scripts/tests/test_request_daily_builds.py
@@ -142,7 +142,10 @@ class FakeTurnipApplication:
         if filename not in self.contents[repository_id]:
             return self._not_found(start_response)
         blob = self.contents[repository_id][filename]
-        response = {'size': len(blob), 'data': base64.b64encode(blob)}
+        response = {
+            'size': len(blob),
+            'data': base64.b64encode(blob).decode('ASCII'),
+            }
         start_response(
             '200 OK', [('Content-Type', 'application/octet-stream')])
         return [json.dumps(response).encode('UTF-8')]
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index ec5226d..624fab2 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -4096,8 +4096,8 @@ class SSHKey(SQLBase):
 
     def getFullKeyText(self):
         try:
-            ssh_keytype = getNS(base64.b64decode(self.keytext))[0].decode(
-                'ascii')
+            key_blob = base64.b64decode(self.keytext.encode('UTF-8'))
+            ssh_keytype = getNS(key_blob)[0].decode('ascii')
         except Exception:
             # We didn't always validate keys, so there might be some that
             # can't be loaded this way.
diff --git a/lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt b/lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt
index 27b6cb3..0b4628a 100644
--- a/lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt
+++ b/lib/lp/registry/stories/team-polls/xx-poll-confirm-vote.txt
@@ -2,7 +2,8 @@
   results of the director-2004 poll.
 
   >>> import base64
-  >>> jdub_auth = base64.b64encode('jeff.waugh@xxxxxxxxxxxxxxx:test')
+  >>> jdub_auth = base64.b64encode(
+  ...     b'jeff.waugh@xxxxxxxxxxxxxxx:test').decode('ASCII')
   >>> print(http(r"""
   ... GET /~ubuntu-team/+poll/director-2004 HTTP/1.1
   ... Authorization: Basic %s
diff --git a/lib/lp/services/gpg/tests/test_gpghandler.py b/lib/lp/services/gpg/tests/test_gpghandler.py
index 297db6c..e929187 100644
--- a/lib/lp/services/gpg/tests/test_gpghandler.py
+++ b/lib/lp/services/gpg/tests/test_gpghandler.py
@@ -1,7 +1,6 @@
 # Copyright 2009-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-import base64
 from datetime import datetime
 import os
 import shutil
@@ -507,8 +506,3 @@ class TestGPGHandler(TestCase):
                 line for line in status if line.startswith(validsig_prefix)]
             validsig_tokens = validsig_line[len(validsig_prefix):].split()
             self.assertEqual(gpgme.MD_SHA512, int(validsig_tokens[7]))
-
-
-def construct_url(template, owner_id='', fingerprint=''):
-    owner_id = base64.b64encode(owner_id, altchars='-_')
-    return template.format(owner_id=owner_id, fingerprint=fingerprint)
diff --git a/lib/lp/services/signing/tests/test_proxy.py b/lib/lp/services/signing/tests/test_proxy.py
index f50aa8c..4405fe7 100644
--- a/lib/lp/services/signing/tests/test_proxy.py
+++ b/lib/lp/services/signing/tests/test_proxy.py
@@ -72,7 +72,6 @@ class SigningServiceResponseFactory:
             bytes(self.generated_public_key))
         self.generated_fingerprint = (
             u'338D218488DFD597D8FCB9C328C3E9D9ADA16CEE')
-        self.b64_signed_msg = base64.b64encode(b"the-signed-msg")
 
         self.signed_msg_template = "%s::signed!"
 
@@ -169,8 +168,8 @@ class SigningServiceResponseFactory:
 
         def sign_callback(request):
             call_counts['/sign'] += 1
-            signed = base64.b64encode(
-                self.signed_msg_template % call_counts['/sign'])
+            signed_msg = self.signed_msg_template % call_counts['/sign']
+            signed = base64.b64encode(signed_msg.encode('utf8'))
             data = {'signed-message': signed.decode('utf8'),
                     'public-key': self.b64_generated_public_key.decode('utf8')}
             return 201, {}, self._encryptPayload(data, self.response_nonce)
diff --git a/lib/lp/services/webapp/doc/webapp-publication.txt b/lib/lp/services/webapp/doc/webapp-publication.txt
index 8af06ab..d1f0ff3 100644
--- a/lib/lp/services/webapp/doc/webapp-publication.txt
+++ b/lib/lp/services/webapp/doc/webapp-publication.txt
@@ -1103,7 +1103,7 @@ utility to setup the request.
     >>> import base64
     >>> login(ANONYMOUS) # Get rid of the marker object in the interaction.
     >>> foo_bar_auth = 'Basic %s' % (
-    ...     base64.b64encode('foo.bar@xxxxxxxxxxxxx:test'))
+    ...     base64.b64encode(b'foo.bar@xxxxxxxxxxxxx:test').decode('ASCII'))
     >>> request, publication = get_request_and_publication(
     ...     extra_environment=dict(HTTP_AUTHORIZATION=foo_bar_auth))
     >>> principal = publication.getPrincipal(request)
diff --git a/lib/lp/services/webapp/tests/test_authutility.py b/lib/lp/services/webapp/tests/test_authutility.py
index 279dd3d..6d7000b 100644
--- a/lib/lp/services/webapp/tests/test_authutility.py
+++ b/lib/lp/services/webapp/tests/test_authutility.py
@@ -79,9 +79,9 @@ class TestPlacelessAuth(ContainerPlacelessSetup, testtools.TestCase):
         testtools.TestCase.tearDown(self)
 
     def _make(self, login, pwd):
-        dict = {
-            'HTTP_AUTHORIZATION':
-            'Basic %s' % base64.b64encode('%s:%s' % (login, pwd))}
+        auth = base64.b64encode(
+            ('%s:%s' % (login, pwd)).encode('ASCII')).decode('ASCII')
+        dict = {'HTTP_AUTHORIZATION': 'Basic %s' % auth}
         request = TestRequest(**dict)
         return getUtility(IPlacelessAuthUtility), request
 
diff --git a/lib/lp/services/webservice/stories/xx-service.txt b/lib/lp/services/webservice/stories/xx-service.txt
index f3a5d3f..c07704b 100644
--- a/lib/lp/services/webservice/stories/xx-service.txt
+++ b/lib/lp/services/webservice/stories/xx-service.txt
@@ -166,7 +166,9 @@ scheme (and don't require OAuth).
     ...     LaunchpadWebServiceCaller)
     >>> noauth_webservice = LaunchpadWebServiceCaller(
     ...     domain='bugs.launchpad.test')
-    >>> sample_auth = 'Basic %s' % base64.b64encode('test@xxxxxxxxxxxxx:test')
+    >>> sample_auth = (
+    ...     'Basic %s' %
+    ...     base64.b64encode(b'test@xxxxxxxxxxxxx:test').decode('ASCII'))
     >>> print(noauth_webservice.get(
     ...     'http://bugs.launchpad.test/api/devel/people/+me',
     ...     headers={'Authorization': sample_auth}))
diff --git a/lib/lp/snappy/model/snapbuildbehaviour.py b/lib/lp/snappy/model/snapbuildbehaviour.py
index cdb374f..4dd89f0 100644
--- a/lib/lp/snappy/model/snapbuildbehaviour.py
+++ b/lib/lp/snappy/model/snapbuildbehaviour.py
@@ -94,7 +94,7 @@ class SnapProxyMixin:
             build_id=self.build.build_cookie,
             timestamp=timestamp)
         auth_string = '{}:{}'.format(admin_username, secret).strip()
-        auth_header = b'Basic ' + base64.b64encode(auth_string)
+        auth_header = b'Basic ' + base64.b64encode(auth_string.encode('ASCII'))
 
         token = yield self._slave.process_pool.doWork(
             RequestProxyTokenCommand,
diff --git a/lib/lp/snappy/model/snapstoreclient.py b/lib/lp/snappy/model/snapstoreclient.py
index 917559d..8055438 100644
--- a/lib/lp/snappy/model/snapstoreclient.py
+++ b/lib/lp/snappy/model/snapstoreclient.py
@@ -98,8 +98,8 @@ class MacaroonAuth(requests.auth.AuthBase):
             try:
                 _, key, value = caveat.caveat_id.split("|")
                 if key == "account":
-                    account = json.loads(
-                        base64.b64decode(value).decode("UTF-8"))
+                    account = json.loads(base64.b64decode(
+                        value.encode("UTF-8")).decode("UTF-8"))
                     if "openid" in account:
                         self.logger.debug(
                             "%s macaroon: OpenID identifier: %s" %
diff --git a/lib/lp/soyuz/adapters/archivedependencies.py b/lib/lp/soyuz/adapters/archivedependencies.py
index d3cbff3..12e5ff2 100644
--- a/lib/lp/soyuz/adapters/archivedependencies.py
+++ b/lib/lp/soyuz/adapters/archivedependencies.py
@@ -405,7 +405,8 @@ def _get_sources_list_for_dependencies(dependencies, logger=None):
 
             key = yield deferToThread(get_key)
             if key is not None:
-                trusted_keys[fingerprint] = base64.b64encode(key.export())
+                trusted_keys[fingerprint] = (
+                    base64.b64encode(key.export()).decode("ASCII"))
 
     defer.returnValue(
         (sources_list_lines, [v for k, v in sorted(trusted_keys.items())]))
diff --git a/lib/lp/soyuz/tests/soyuz.py b/lib/lp/soyuz/tests/soyuz.py
index 52c9fb7..5e0b9fe 100644
--- a/lib/lp/soyuz/tests/soyuz.py
+++ b/lib/lp/soyuz/tests/soyuz.py
@@ -29,7 +29,7 @@ class Base64KeyMatches(Matcher):
         self.fingerprint = fingerprint
 
     def match(self, encoded_key):
-        key = base64.b64decode(encoded_key)
+        key = base64.b64decode(encoded_key.encode("ASCII"))
         return Equals(self.fingerprint).match(
             getUtility(IGPGHandler).importPublicKey(key).fingerprint)
 
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 9661a8f..2717264 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -4392,7 +4392,8 @@ class BareLaunchpadObjectFactory(ObjectFactory):
             raise AssertionError(
                 "key_type must be a member of SSH_TEXT_TO_KEY_TYPE, not %r" %
                 key_type)
-        key_text = base64.b64encode(NS(key_type) + b"".join(parameters))
+        key_text = base64.b64encode(
+            NS(key_type) + b"".join(parameters)).decode("ASCII")
         if comment is None:
             comment = self.getUniqueString()
         return "%s %s %s" % (key_type, key_text, comment)
diff --git a/utilities/massage-bug-import-xml b/utilities/massage-bug-import-xml
index 7d92f84..5a304be 100755
--- a/utilities/massage-bug-import-xml
+++ b/utilities/massage-bug-import-xml
@@ -178,7 +178,8 @@ def massage(root, project_name, fix_nickname, tag_nickname):
                     u"text/plain")
                 etree.SubElement(attachment, '{%s}contents' % NS).text = (
                     standard_b64encode(
-                        first_comment_text.text.encode('utf-8')))
+                        first_comment_text.text.encode('utf-8')
+                        ).decode('ascii'))
                 # Trim the comment text.
                 problem_resolution('Trimming comment text.')
                 first_comment_text.text = truncate(
diff --git a/utilities/roundup-sniffer.py b/utilities/roundup-sniffer.py
index 224da01..3035d0e 100755
--- a/utilities/roundup-sniffer.py
+++ b/utilities/roundup-sniffer.py
@@ -66,7 +66,9 @@ class RoundupSniffer:
 
     def fetch(self, url):
         """Fetch the URL, consulting the cache first."""
-        filename = join(self.cache_dir, urlsafe_b64encode(url))
+        filename = join(
+            self.cache_dir,
+            urlsafe_b64encode(url.encode('UTF-8')).decode('ASCII'))
         if not exists(filename):
             open(filename, 'wb').write(urlopen(url).read())
         return open(filename, 'rb')