117117class Session :
118118 """A connect to a domain"""
119119
120- key : bytes
121- counter : int
122- epoch : bytes
123- delta : int
124- hmac : bytes
125- publicKey : bytes | None = None
126- lock : Lock
127-
128120 def __init__ (self ):
121+ self .counter : int = 0
122+ self .epoch : bytes | None = None
123+ self .delta : int = 0
124+ self .hmac : bytes | None = None
125+ self .publicKey : bytes | None = None
129126 self .lock = Lock ()
130- self .counter = 0
131127
132128 def update (self , sessionInfo : SessionInfo , privateKey : ec .EllipticCurvePrivateKey ):
133129 """Update the session with new information"""
@@ -136,7 +132,7 @@ def update(self, sessionInfo: SessionInfo, privateKey: ec.EllipticCurvePrivateKe
136132 self .delta = int (time .time ()) - sessionInfo .clock_time
137133 if (self .publicKey != sessionInfo .publicKey ):
138134 self .publicKey = sessionInfo .publicKey
139- self . key = hashlib .sha1 (
135+ key = hashlib .sha1 (
140136 privateKey .exchange (
141137 ec .ECDH (),
142138 ec .EllipticCurvePublicKey .from_encoded_point (
@@ -145,18 +141,22 @@ def update(self, sessionInfo: SessionInfo, privateKey: ec.EllipticCurvePrivateKe
145141 ),
146142 ).digest ()[:16 ]
147143 self .hmac = hmac .new (
148- self . key , "authenticated command" .encode (), hashlib .sha256
144+ key , "authenticated command" .encode (), hashlib .sha256
149145 ).digest ()
150146
151147 def get (self ) -> HMAC_Personalized_Signature_Data :
152148 """Sign a command and return session metadata"""
149+ assert self .ready , "Session is not ready"
153150 self .counter = self .counter + 1
154151 return HMAC_Personalized_Signature_Data (
155152 epoch = self .epoch ,
156153 counter = self .counter ,
157154 expires_at = int (time .time ()) - self .delta + 10 ,
158155 )
159156
157+ @property
158+ def ready (self ) -> bool :
159+ return self .epoch is not None and self .hmac is not None and self .delta > 0
160160
161161class VehicleSigned (VehicleSpecific ):
162162 """Class describing the Tesla Fleet API vehicle endpoints and commands for a specific vehicle with command signing."""
@@ -181,7 +181,10 @@ def __init__(
181181 encoding = Encoding .X962 , format = PublicFormat .UncompressedPoint
182182 )
183183 self ._from_destination = randbytes (16 )
184- self ._sessions = {}
184+ self ._sessions = {
185+ Domain .DOMAIN_VEHICLE_SECURITY : Session (),
186+ Domain .DOMAIN_INFOTAINMENT : Session (),
187+ }
185188
186189 async def _send (self , msg : RoutableMessage ) -> RoutableMessage :
187190 """Serialize a message and send to the signed command endpoint."""
@@ -206,11 +209,8 @@ async def _send(self, msg: RoutableMessage) -> RoutableMessage:
206209
207210 return resp_msg
208211
209- async def _handshake (self , domain : Domain ) -> Session :
212+ async def _handshake (self , domain : Domain ) -> None :
210213 """Perform a handshake with the vehicle."""
211- if session := self ._sessions .get (domain ):
212- return session
213- self ._sessions [domain ] = Session ()
214214
215215 LOGGER .debug (f"Handshake with domain { Domain .Name (domain )} " )
216216 msg = RoutableMessage ()
@@ -222,8 +222,6 @@ async def _handshake(self, domain: Domain) -> Session:
222222 # Send handshake message
223223 await self ._send (msg )
224224
225- return self ._sessions [domain ]
226-
227225 async def _sendVehicleSecurity (self , command : UnsignedMessage ) -> dict [str , Any ]:
228226 """Sign and send a message to Infotainment computer."""
229227 return await self ._sign (DOMAIN_VEHICLE_SECURITY , command .SerializeToString ())
@@ -238,7 +236,10 @@ async def _sign(
238236 """Send a signed message to the vehicle."""
239237 LOGGER .debug (f"Sending to domain { Domain .Name (domain )} " )
240238
241- session = await self ._handshake (domain )
239+ session = self ._sessions [domain ]
240+ if not session .ready :
241+ await self ._handshake (domain )
242+
242243 hmac_personalized = session .get ()
243244
244245 msg = RoutableMessage ()
0 commit comments