1"""Base implementation."""
2
3from __future__ import annotations
4
5import enum
6from typing import TYPE_CHECKING
7
8from rfc3161_client import _rust
9
10if TYPE_CHECKING:
11 from rfc3161_client.tsp import TimeStampRequest, TimeStampResponse
12
13
14class HashAlgorithm(enum.Enum):
15 """Hash algorithms."""
16
17 SHA256 = "SHA256"
18 SHA512 = "SHA512"
19
20
21_AllowedHashTypes = HashAlgorithm
22
23
24class TimestampRequestBuilder:
25 """Timestamp Request Builder class."""
26
27 def __init__(
28 self,
29 data: bytes | None = None,
30 hash_algorithm: _AllowedHashTypes | None = None,
31 nonce: bool = True,
32 cert_req: bool = True,
33 ) -> None:
34 """Init method."""
35 self._data: bytes | None = data
36 self._algorithm: _AllowedHashTypes | None = hash_algorithm
37 self._nonce: bool = nonce
38 self._cert_req: bool = cert_req
39
40 def data(self, data: bytes) -> TimestampRequestBuilder:
41 """Set the data to be timestamped."""
42 if not data:
43 msg = "The data to timestamp cannot be empty."
44 raise ValueError(msg)
45 if self._data is not None:
46 msg = "The data may only be set once."
47 raise ValueError(msg)
48 return TimestampRequestBuilder(data, self._algorithm, self._nonce, self._cert_req)
49
50 def hash_algorithm(self, hash_algorithm: _AllowedHashTypes) -> TimestampRequestBuilder:
51 """Set the Hash algorithm used."""
52 if not isinstance(hash_algorithm, HashAlgorithm):
53 msg = f"{hash_algorithm} is not a supported hash." # type: ignore[unreachable]
54 raise TypeError(msg)
55
56 return TimestampRequestBuilder(self._data, hash_algorithm, self._nonce, self._cert_req)
57
58 def cert_request(self, *, cert_request: bool = False) -> TimestampRequestBuilder:
59 """Set the cert request field."""
60 if not isinstance(cert_request, bool):
61 msg = "Cert request must be a boolean." # type: ignore[unreachable]
62 raise TypeError(msg)
63
64 return TimestampRequestBuilder(self._data, self._algorithm, self._nonce, cert_request)
65
66 def nonce(self, *, nonce: bool = True) -> TimestampRequestBuilder:
67 """Set the request policy field."""
68 if not isinstance(nonce, bool):
69 msg = "Request policy must be a boolean." # type: ignore[unreachable]
70 raise TypeError(msg)
71
72 return TimestampRequestBuilder(self._data, self._algorithm, nonce, self._cert_req)
73
74 def build(self) -> TimeStampRequest:
75 """Build a TimestampRequest."""
76 if self._data is None:
77 msg = "Data must be for a Timestamp Request."
78 raise ValueError(msg)
79
80 if self._algorithm is None:
81 self._algorithm = HashAlgorithm.SHA512
82
83 return _rust.create_timestamp_request(
84 data=self._data,
85 nonce=self._nonce,
86 cert=self._cert_req,
87 hash_algorithm=self._algorithm,
88 )
89
90
91def decode_timestamp_response(data: bytes) -> TimeStampResponse:
92 """Decode a Timestamp response."""
93 return _rust.parse_timestamp_response(data)