Skip to content

Commit

Permalink
Merge 61177c2 into 5353c4a
Browse files Browse the repository at this point in the history
  • Loading branch information
fizyk committed Feb 23, 2018
2 parents 5353c4a + 61177c2 commit d2090f3
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGES.rst
@@ -1,6 +1,11 @@
CHANGELOG
=========

unreleased
-------

* Remove padding characters from encoded string.

1.1.1
-------

Expand Down
13 changes: 9 additions & 4 deletions README.rst
Expand Up @@ -14,7 +14,7 @@ Encoding and decoding arbitrary strings into strings that are safe to put into a
The problem
-----------

`urlsafe_b64encode` and `urlsafe_b64decode` from base64 are not enough because they leave `=` chars unquoted:
`urlsafe_b64encode` and `urlsafe_b64decode` from base64 are not enough because they leave `=` used for padding chars unquoted:

.. code-block:: python
Expand Down Expand Up @@ -45,8 +45,10 @@ II. Some libraries tolerate the `=` in query string values:
but the RFC 3986 underspecifies the query string so we cannot rely on `=` chars being handled by all web applications as it is done by urlparse.

Therefore we consider chars: `['+', '/', '=']` unsafe and we replace them with `['-', '_', '.']`. Characters `+` and `/` are already handled by `urlsafe_*` functions from base64 so only `=` is left for us. The `.` character has been chosen because it often appears in real world query strings and it is not used
by base64.
Therefore we consider chars: `['+', '/', '=']` unsafe and we replace them with `['-', '_', '.']`.
Characters `+` and `/` are already handled by `urlsafe_*` functions from base64 so only `=` is left.
Since the `=` is used exclusively for padding, we simply remove it, and re-attach the padding during decoding.
Because of that, `querystringsafe_base64` is able to decode padded and unpadded string.

The solution
------------
Expand All @@ -56,7 +58,10 @@ The solution
import querystringsafe_base64
querystringsafe_base64.encode(b'foo-bar')
b'Zm9vLWJhcg..'
b'Zm9vLWJhcg'
querystringsafe_base64.decode(b'Zm9vLWJhcg..')
b'foo-bar'
querystringsafe_base64.decode(b'Zm9vLWJhcg')
b'foo-bar'
6 changes: 3 additions & 3 deletions src/querystringsafe_base64/__init__.py
Expand Up @@ -39,7 +39,7 @@ def fill_padding(padded_string):
length = len(padded_string)
reminder = len(padded_string) % 4
if reminder:
return padded_string.ljust(length + 4 - reminder, b'.')
return padded_string.ljust(length + 4 - reminder, b'=')
return padded_string


Expand All @@ -57,7 +57,7 @@ def encode(to_encode):
string - like base64, except characters ['+', '/', '='] are
replaced with ['-', '_', '.'] consequently
"""
return urlsafe_b64encode(to_encode).replace(b'=', b'.')
return urlsafe_b64encode(to_encode).strip(b'=')


def decode(encoded):
Expand All @@ -76,4 +76,4 @@ def decode(encoded):
:return: decoded string
"""
padded_string = fill_padding(encoded)
return urlsafe_b64decode(padded_string.replace(b'.', b'='))
return urlsafe_b64decode(padded_string)
2 changes: 1 addition & 1 deletion tests/test_encode_decode.py
Expand Up @@ -115,6 +115,6 @@ def test_encode_decode_unpad(string_num):
original = test_strings[string_num]

encoded = querystringsafe_base64.encode(original)
assert encoded.endswith(b'.') # make sure it ends with padding for this test
assert len(encoded) % 4 != 0 # make sure it would end with padding
decoded = querystringsafe_base64.decode(encoded.rstrip())
assert decoded == original

0 comments on commit d2090f3

Please sign in to comment.