summaryrefslogtreecommitdiffstats
path: root/app/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/util.py')
-rw-r--r--app/util.py36
1 files changed, 27 insertions, 9 deletions
diff --git a/app/util.py b/app/util.py
index 69b3ea7..69593ac 100644
--- a/app/util.py
+++ b/app/util.py
@@ -1,10 +1,15 @@
from base64 import b32encode, b32decode
import logging
-from hashlib import blake2b # because it is fast as fuck
+from hashlib import blake2b
+from binascii import Error as Base32DecodeError
log = logging.getLogger('blure')
+class URLDecodeError(ValueError):
+ pass
+
+
class URLCoder:
'''
URLCoder shuffles sequential ids into non-sequential strings,
@@ -16,17 +21,21 @@ class URLCoder:
_endian = 'big'
@classmethod
- def _humanify(self, data: bytes):
+ def _humanify(cls, data: bytes):
b32 = b32encode(data).decode('ascii')
- if self._pad > 0:
- return b32[:-self._pad]
+ if cls._pad > 0:
+ return b32[:-cls._pad]
else:
return b32
@classmethod
- def _dehumanify(self, data: str):
- binary = b32decode(data + '=' * self._pad)
- assert len(binary) == self._bs * 2
+ def _dehumanify(cls, data: str):
+ binary = b32decode(data + '=' * cls._pad)
+ if len(binary) != cls._bs * 2:
+ raise URLDecodeError(
+ f'Padded url len must be exactly {cls._bs * 2} bytes'
+ f'(binary="{binary}", len = {len(binary)})'
+ )
return binary
def __init__(self, secret: bytes):
@@ -39,13 +48,22 @@ class URLCoder:
self.reverse_keys = self.keys[::-1]
def to_url(self, id: int) -> str:
- assert 0 <= id and id <= self._bound
+ if 0 > id or id >= self._bound:
+ raise URLDecodeError(
+ 'id(={id}) is outside valid range [0, {self._bound})'
+ )
+
as_bytes = int.to_bytes(id, self._bs * 2, self._endian)
encoded = self._blake_enc(as_bytes, self.keys)
+
return self._humanify(encoded)
def to_id(self, url: str) -> int:
- binary = self._dehumanify(url.upper())
+ try:
+ binary = self._dehumanify(url.upper())
+ except Base32DecodeError as e:
+ raise URLDecodeError(e)
+
as_bytes = self._blake_enc(binary, self.reverse_keys)
return int.from_bytes(as_bytes, self._endian)