first commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import re
|
||||
from typing import Any
|
||||
from ..util import (
|
||||
to_bytes,
|
||||
to_str,
|
||||
json_b64encode,
|
||||
urlsafe_b64encode,
|
||||
urlsafe_b64decode,
|
||||
)
|
||||
from .._rfc7515.model import JWSAlgModel, CompactSignature
|
||||
from .._rfc7515.compact import decode_header
|
||||
from .._rfc7515.registry import JWSRegistry, default_registry
|
||||
from ..errors import DecodeError
|
||||
from .util import is_rfc7797_enabled
|
||||
|
||||
|
||||
def sign_rfc7515_compact(obj: CompactSignature, alg: JWSAlgModel, key: Any) -> bytes:
|
||||
header_segment = json_b64encode(obj.headers())
|
||||
signing_input = header_segment + b"." + obj.payload
|
||||
signature = urlsafe_b64encode(alg.sign(signing_input, key))
|
||||
|
||||
# if need to detach payload
|
||||
if __is_urlsafe_characters(obj.payload):
|
||||
out = signing_input + b"." + signature
|
||||
else:
|
||||
out = header_segment + b".." + signature
|
||||
return out
|
||||
|
||||
|
||||
def extract_rfc7515_compact(
|
||||
value: bytes, payload: bytes | str | None = None, registry: JWSRegistry | None = None
|
||||
) -> CompactSignature:
|
||||
"""Extract the JWS Compact Serialization from bytes to object.
|
||||
|
||||
:param value: JWS in bytes
|
||||
:param payload: optional payload, required with detached content
|
||||
:param registry: optional JWSRegistry instance
|
||||
:raise DecodeError: when decoding fails
|
||||
"""
|
||||
parts = value.split(b".")
|
||||
if len(parts) != 3:
|
||||
raise DecodeError("Invalid JSON Web Signature")
|
||||
|
||||
if registry is None:
|
||||
registry = default_registry
|
||||
|
||||
header_segment, payload_segment, signature_segment = parts
|
||||
|
||||
registry.validate_header_size(header_segment)
|
||||
registry.validate_signature_size(signature_segment)
|
||||
if payload_segment:
|
||||
registry.validate_payload_size(payload_segment)
|
||||
|
||||
protected = decode_header(header_segment)
|
||||
|
||||
if is_rfc7797_enabled(protected):
|
||||
if not payload_segment and payload:
|
||||
payload_segment = to_bytes(payload)
|
||||
registry.validate_payload_size(payload_segment)
|
||||
payload = payload_segment
|
||||
else:
|
||||
if not payload_segment and payload:
|
||||
payload = to_bytes(payload)
|
||||
payload_segment = urlsafe_b64encode(payload)
|
||||
else:
|
||||
try:
|
||||
payload = urlsafe_b64decode(payload_segment)
|
||||
except (TypeError, ValueError):
|
||||
raise DecodeError("Invalid payload")
|
||||
|
||||
obj = CompactSignature(protected, payload)
|
||||
obj.segments.update(
|
||||
{
|
||||
"header": header_segment,
|
||||
"payload": payload_segment,
|
||||
"signature": signature_segment,
|
||||
}
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
# https://datatracker.ietf.org/doc/html/rfc7797#section-5.2
|
||||
# the application MUST ensure that the payload contains only the URL-safe
|
||||
# characters 'a'-'z', 'A'-'Z', '0'-'9', dash ('-'), underscore ('_'),
|
||||
# and tilde ('~')
|
||||
_re_urlsafe = re.compile("^[a-zA-Z0-9-_~]+$")
|
||||
|
||||
|
||||
def __is_urlsafe_characters(s: bytes | str) -> bool:
|
||||
return bool(_re_urlsafe.match(to_str(s)))
|
||||
Reference in New Issue
Block a user