1- """Low-level TUF Envelope API.
1+ """Low-level TUF DSSE API. (experimental!)
22
33"""
44import json
5- from typing import Generic , Type , cast
5+ from typing import Dict , Generic , Type , cast
66
7- from securesystemslib .dsse import Envelope as BaseEnvelope
7+ from securesystemslib .dsse import Envelope as BaseSimpleEnvelope
88
9+ # Expose all payload classes to use API independently of ``tuf.api.metadata``.
910from tuf .api ._payload import ( # noqa: F401
1011 _ROOT ,
1112 _SNAPSHOT ,
3233from tuf .api .serialization import DeserializationError , SerializationError
3334
3435
35- class Envelope (Generic [T ], BaseEnvelope ):
36- """TODO: doc"""
36+ class SimpleEnvelope (Generic [T ], BaseSimpleEnvelope ):
37+ """Dead Simple Signing Envelope (DSSE) for TUF payloads.
38+
39+ * Sign with ``self.sign()`` (inherited).
40+ * Verify with ``verify_delegate`` on a ``Root`` or ``Targets``
41+ object::
42+
43+ delegator.verify_delegate(
44+ role_name,
45+ envelope.pae(), # Note, how we don't pass ``envelope.payload``!
46+ envelope.signatures_dict,
47+ )
48+
49+ Attributes:
50+ payload: Serialized payload bytes.
51+ payload_type: Payload string identifier.
52+ signatures: List of ``Signature`` objects.
53+ signatures_dict: Ordered dictionary of keyids to ``Signature`` objects.
54+
55+ """
3756
3857 _DEFAULT_PAYLOAD_TYPE = "application/vnd.tuf+json"
3958
59+ @property
60+ def signatures_dict (self ) -> Dict :
61+ """Convenience alias for ``self.signatures`` mapped to keyids."""
62+ # TODO: Propose changing ``signatures`` list to dict upstream
63+ return {sig .keyid : sig for sig in self .signatures }
64+
4065 @classmethod
41- def from_bytes (cls , data : bytes ) -> "Envelope[T]" :
42- """TODO: doc"""
66+ def from_bytes (cls , data : bytes ) -> "SimpleEnvelope[T]" :
67+ """Load envelope from JSON bytes.
68+
69+ NOTE: Unlike ``tuf.api.metadata.Metadata.from_bytes``, this method
70+ does not deserialize the contained payload. Use ``self.get_signed`` to
71+ deserialize the payload into a ``Signed`` object.
72+
73+ Args:
74+ data: envelope JSON bytes.
75+
76+ Raises:
77+ tuf.api.serialization.DeserializationError:
78+ data cannot be deserialized.
79+
80+ Returns:
81+ TUF ``SimpleEnvelope`` object.
82+ """
4383 try :
4484 envelope_dict = json .loads (data .decode ())
45- envelope = Envelope .from_dict (envelope_dict )
85+ envelope = SimpleEnvelope .from_dict (envelope_dict )
4686
4787 except Exception as e :
48- raise SerializationError from e
88+ raise DeserializationError from e
4989
5090 return envelope
5191
5292 def to_bytes (self ) -> bytes :
53- """TODO: doc"""
93+ """Return envelope as JSON bytes.
94+
95+ NOTE: Unlike ``tuf.api.metadata.Metadata.to_bytes``, this method does
96+ not serialize the payload. Use ``SimpleEnvelope.from_signed`` to
97+ serialize a ``Signed`` object and wrap it in an SimpleEnvelope.
98+
99+ Raises:
100+ tuf.api.serialization.SerializationError:
101+ self cannot be serialized.
102+ """
54103 try :
55104 envelope_dict = self .to_dict ()
56105 json_bytes = json .dumps (envelope_dict ).encode ()
@@ -61,8 +110,16 @@ def to_bytes(self) -> bytes:
61110 return json_bytes
62111
63112 @classmethod
64- def from_signed (cls , signed : T ) -> "Envelope[T]" :
65- """TODO: doc"""
113+ def from_signed (cls , signed : T ) -> "SimpleEnvelope[T]" :
114+ """Serialize payload as JSON bytes and wrap in envelope.
115+
116+ Args:
117+ signed: ``Signed`` object.
118+
119+ Raises:
120+ tuf.api.serialization.SerializationError:
121+ The signed object cannot be serialized.
122+ """
66123 try :
67124 signed_dict = signed .to_dict ()
68125 json_bytes = json .dumps (signed_dict ).encode ()
@@ -73,7 +130,13 @@ def from_signed(cls, signed: T) -> "Envelope[T]":
73130 return cls (json_bytes , cls ._DEFAULT_PAYLOAD_TYPE , [])
74131
75132 def get_signed (self ) -> T :
76- """TODO: doc"""
133+ """Extract and deserialize payload JSON bytes from envelope.
134+
135+ Raises:
136+ tuf.api.serialization.DeserializationError:
137+ The signed object cannot be deserialized.
138+ """
139+
77140 try :
78141 payload_dict = json .loads (self .payload .decode ())
79142
@@ -88,7 +151,7 @@ def get_signed(self) -> T:
88151 elif _type == _ROOT :
89152 inner_cls = Root
90153 else :
91- raise ValueError (f'unrecognized metadata type "{ _type } "' )
154+ raise ValueError (f'unrecognized role type "{ _type } "' )
92155
93156 except Exception as e :
94157 raise DeserializationError from e
0 commit comments