diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py index 52bd98e41bb1e93fce19849fbafc9908800c76c5..50c84cdbf702a08bae984ae8402e215a2113c58a 100644 --- a/src/_zkapauthorizer/model.py +++ b/src/_zkapauthorizer/model.py @@ -27,7 +27,9 @@ from json import ( from datetime import ( datetime, ) - +from base64 import ( + b64decode, +) from zope.interface import ( Interface, implementer, @@ -606,6 +608,31 @@ class LeaseMaintenanceActivity(object): # x = store.get_latest_lease_maintenance_activity() # xs.started, xs.passes_required, xs.finished +def is_base64_encoded(b64decode=b64decode): + def validate_is_base64_encoded(inst, attr, value): + try: + b64decode(value.encode("ascii")) + except (TypeError, Error): + raise TypeError( + "{name!r} must be base64 encoded unicode, (got {value!r})".format( + name=attr.name, + value=value, + ), + ) + return validate_is_base64_encoded + +def has_length(expected): + def validate_has_length(inst, attr, value): + if len(value) != expected: + raise ValueError( + "{name!r} must have length {expected}, instead has length {actual}".format( + name=attr.name, + expected=expected, + actual=len(value), + ), + ) + return validate_has_length + @attr.s(frozen=True) class UnblindedToken(object):