diff --git a/.gitignore b/.gitignore index 2e2c6b7..7201aa6 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ dist/ .err .vscode /run.sh +ROADMAP.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca4b52..f2f1f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ 👀 +## 0.3.7 + +- Fixed a bug in `b64decode()` padding handling which made the function inconsistent and non injective. Now, leading `'A'` is NEVER stripped. + ## 0.3.6 - Fixed `ConfigValue` behavior with multiple sources. It used to iterate through all the sources, possibly overwriting; now, iteration stops at first non-missing value. diff --git a/src/suou/__init__.py b/src/suou/__init__.py index 4fad4a2..2a06368 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -27,7 +27,7 @@ from .itertools import makelist, kwargs_prefix, ltuple, rtuple, additem from .i18n import I18n, JsonI18n, TomlI18n from .snowflake import Snowflake, SnowflakeGen -__version__ = "0.3.6" +__version__ = "0.3.7" __all__ = ( 'Siq', 'SiqCache', 'SiqType', 'SiqGen', 'StringCase', diff --git a/src/suou/codecs.py b/src/suou/codecs.py index 3efe53f..9c77424 100644 --- a/src/suou/codecs.py +++ b/src/suou/codecs.py @@ -178,10 +178,10 @@ def b32ldecode(val: bytes | str) -> bytes: def b64encode(val: bytes, *, strip: bool = True) -> str: ''' - Wrapper around base64.urlsafe_b64encode() which also strips trailing '=' and leading 'A'. + Wrapper around base64.urlsafe_b64encode() which also strips trailing '='. ''' b = want_str(base64.urlsafe_b64encode(val)) - return b.lstrip('A').rstrip('=') if strip else b + return b.rstrip('=') if strip else b def b64decode(val: bytes | str) -> bytes: ''' diff --git a/src/suou/configparse.py b/src/suou/configparse.py index b30c83f..f91a2b2 100644 --- a/src/suou/configparse.py +++ b/src/suou/configparse.py @@ -23,7 +23,7 @@ import os from typing import Any, Callable, Iterator from collections import OrderedDict -from .functools import deprecated_alias +from .functools import deprecated MISSING = object() @@ -226,7 +226,7 @@ class ConfigOptions: if first: self._srcs.move_to_end(key, False) - add_config_source = deprecated_alias(add_source) + add_config_source = deprecated('use add_source() instead')(add_source) def expose(self, public_name: str, attr_name: str | None = None) -> None: ''' diff --git a/src/suou/flask_sqlalchemy.py b/src/suou/flask_sqlalchemy.py index 963b34d..f114d91 100644 --- a/src/suou/flask_sqlalchemy.py +++ b/src/suou/flask_sqlalchemy.py @@ -40,12 +40,12 @@ class FlaskAuthSrc(AuthSrc): def get_signature(self) -> bytes: sig = request.headers.get('authorization-signature', None) return want_bytes(sig) if sig else None - def invalid_exc(self, msg: str = 'Validation failed') -> Never: + def invalid_exc(self, msg: str = 'validation failed') -> Never: abort(400, msg) def required_exc(self): abort(401, 'Login required') -def require_auth(cls: type[DeclarativeBase], db: SQLAlchemy) -> Callable: +def require_auth(cls: type[DeclarativeBase], db: SQLAlchemy) -> Callable[Any, Callable]: """ Make an auth_required() decorator for Flask views.