mirror of
https://github.com/certbot/certbot.git
synced 2026-07-27 16:19:11 +02:00
JOSE Base64: encode str only, decode str or ascii unicode
This commit is contained in:
@@ -74,39 +74,42 @@ def unique_file(default_name, mode=0777):
|
||||
# - padding stripped
|
||||
|
||||
|
||||
def jose_b64encode(data, encoding='utf-8'):
|
||||
def jose_b64encode(data):
|
||||
"""JOSE Base64 encode.
|
||||
|
||||
:param data: Data to be encoded.
|
||||
:type data: str or unicode
|
||||
:type data: str or bytearray
|
||||
|
||||
:param encoding: Name of the encoding to be performed before
|
||||
Base64 encoding. If not None, then `data`
|
||||
has to be unicode.
|
||||
:type encoding: str or None
|
||||
:raises: TypeError
|
||||
|
||||
:returns: JOSE Base64 string.
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
encoded = data if encoding is None else data.encode(encoding)
|
||||
return base64.urlsafe_b64encode(encoded).rstrip('=')
|
||||
if not isinstance(data, str):
|
||||
raise TypeError('argument should be str or bytearray')
|
||||
return base64.urlsafe_b64encode(data).rstrip('=')
|
||||
|
||||
|
||||
def jose_b64decode(arg, decoding='utf-8'):
|
||||
def jose_b64decode(data):
|
||||
"""JOSE Base64 decode.
|
||||
|
||||
:param arg: Base64 string to be decoded.
|
||||
:type arg: str or unicode
|
||||
:param data: Base64 string to be decoded. If it's unicode, then
|
||||
only ASCII characters are allowed.
|
||||
:type data: str or unicode
|
||||
|
||||
:param decoding: Name of the encoding to be performed after
|
||||
Base64 decoding.
|
||||
:type decoding: str or None
|
||||
:raises: ValueError, TypeError
|
||||
|
||||
:returns: Decoded data. Unicode if `decoding` is not None.
|
||||
:rtype: str or unicode
|
||||
:returns: Decoded data.
|
||||
|
||||
"""
|
||||
ascii = arg.encode('ascii') # equivalent to str(arg), for unicode input
|
||||
decoded = base64.urlsafe_b64decode(ascii + '=' * (4 - (len(ascii) % 4)))
|
||||
return decoded if decoding is None else decoded.decode(decoding)
|
||||
if isinstance(data, unicode):
|
||||
try:
|
||||
data = data.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
raise ValueError(
|
||||
'unicode argument should contain only ASCII characters')
|
||||
elif not isinstance(data, str):
|
||||
raise TypeError('argument should be a str or unicode')
|
||||
|
||||
return base64.urlsafe_b64decode(data + '=' * (4 - (len(data) % 4)))
|
||||
|
||||
@@ -88,46 +88,46 @@ B64_URL_UNSAFE_EXAMPLES = {
|
||||
class JOSEB64EncodeTest(unittest.TestCase):
|
||||
"""Tests for letsencrypt.client.le_util.jose_b64encode."""
|
||||
|
||||
def _call(self, data, encoding):
|
||||
def _call(self, data):
|
||||
from letsencrypt.client.le_util import jose_b64encode
|
||||
return jose_b64encode(data, encoding)
|
||||
return jose_b64encode(data)
|
||||
|
||||
def test_unsafe_url(self):
|
||||
for text, b64 in B64_URL_UNSAFE_EXAMPLES.iteritems():
|
||||
self.assertEqual(self._call(text, None), b64)
|
||||
self.assertEqual(self._call(text), b64)
|
||||
|
||||
def test_different_paddings(self):
|
||||
for text, (b64, _) in JOSE_B64_PADDING_EXAMPLES.iteritems():
|
||||
self.assertEqual(self._call(text, None), b64)
|
||||
self.assertEqual(self._call(text), b64)
|
||||
|
||||
def test_with_encoding(self):
|
||||
self.assertEqual(self._call(u'\u0105', 'utf-8'), 'xIU')
|
||||
def test_unicode_fails_with_type_error(self):
|
||||
self.assertRaises(TypeError, self._call, u'some unicode')
|
||||
|
||||
|
||||
class JOSEB64DecodeTest(unittest.TestCase):
|
||||
"""Tests for letsencrypt.client.le_util.jose_b64decode."""
|
||||
|
||||
def _call(self, jose_b64_string, decoding):
|
||||
def _call(self, data):
|
||||
from letsencrypt.client.le_util import jose_b64decode
|
||||
return jose_b64decode(jose_b64_string, decoding)
|
||||
return jose_b64decode(data)
|
||||
|
||||
def test_unsafe_url(self):
|
||||
for text, b64 in B64_URL_UNSAFE_EXAMPLES.iteritems():
|
||||
self.assertEqual(self._call(b64, None), text)
|
||||
self.assertEqual(self._call(b64), text)
|
||||
|
||||
def test_input_without_padding(self):
|
||||
for text, (b64, _) in JOSE_B64_PADDING_EXAMPLES.iteritems():
|
||||
self.assertEqual(self._call(b64, None), text)
|
||||
self.assertEqual(self._call(b64), text)
|
||||
|
||||
def test_input_with_padding(self):
|
||||
for text, (b64, pad) in JOSE_B64_PADDING_EXAMPLES.iteritems():
|
||||
self.assertEqual(self._call(b64 + pad, None), text)
|
||||
self.assertEqual(self._call(b64 + pad), text)
|
||||
|
||||
def test_with_encoding(self):
|
||||
self.assertEqual(self._call('xIU=', 'utf-8'), u'\u0105')
|
||||
def test_unicode_with_ascii(self):
|
||||
self.assertEqual(self._call(u'YQ'), 'a')
|
||||
|
||||
def test_unicode(self):
|
||||
self.assertEqual(self._call(u'YQ', None), 'a')
|
||||
def test_non_ascii_unicode_fails(self):
|
||||
self.assertRaises(ValueError, self._call, u'\u0105')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user