1414from dbus_next .aio import MessageBus
1515from dbus_next import Variant
1616
17- logging .basicConfig (filename = '/tmp/credential_manager_shim.log' , encoding = 'utf-8' , level = logging .DEBUG )
17+ logging .basicConfig (
18+ filename = "/tmp/credential_manager_shim.log" , encoding = "utf-8" , level = logging .DEBUG
19+ )
20+
1821
1922def getMessage ():
2023 logging .debug ("blocking on read" )
@@ -24,51 +27,55 @@ def getMessage():
2427 sys .exit (0 )
2528 try :
2629 logging .debug (f"unpacking struct: { rawLength } " )
27- messageLength = struct .unpack ('@I' , rawLength )[0 ]
30+ messageLength = struct .unpack ("@I" , rawLength )[0 ]
2831 logging .debug (f"reading { messageLength } bytes" )
2932 except Exception as e :
3033 logging .error ("Failed to convert rawLength to integer" , exc_info = e )
3134 try :
3235 raw_msg = sys .stdin .buffer .read (messageLength )
3336 logging .debug (f"received bytes: { raw_msg } " )
34- message = raw_msg .decode (' utf-8' )
37+ message = raw_msg .decode (" utf-8" )
3538 logging .debug ("received " + message )
3639 return json .loads (message )
3740 except Exception as e :
3841 logging .error ("Failed to read message" )
3942 raise e
4043
44+
4145# Encode a message for transmission,
4246# given its content.
4347def encodeMessage (messageContent ):
44- encodedContent = json .dumps (messageContent ).encode ('utf-8' )
45- encodedLength = struct .pack ('@I' , len (encodedContent ))
46- return {'length' : encodedLength , 'content' : encodedContent }
48+ encodedContent = json .dumps (messageContent ).encode ("utf-8" )
49+ encodedLength = struct .pack ("@I" , len (encodedContent ))
50+ return {"length" : encodedLength , "content" : encodedContent }
51+
4752
4853# Send an encoded message to stdout
4954def sendMessage (encodedMessage ):
50- sys .stdout .buffer .write (encodedMessage [' length' ])
51- sys .stdout .buffer .write (encodedMessage [' content' ])
55+ sys .stdout .buffer .write (encodedMessage [" length" ])
56+ sys .stdout .buffer .write (encodedMessage [" content" ])
5257 sys .stdout .buffer .flush ()
5358 logging .debug (f"sent message: { encodedMessage } " )
5459
5560
5661def b64_encode (data : bytes ) -> str :
57- return base64 .urlsafe_b64encode (data ).rstrip (b'=' ).decode ('ascii' )
62+ return base64 .urlsafe_b64encode (data ).rstrip (b"=" ).decode ("ascii" )
63+
5864
5965def b64_decode (s ) -> bytes :
60- padding = '=' * (len (s ) % 4 )
66+ padding = "=" * (len (s ) % 4 )
6167 return base64 .urlsafe_b64decode (s + padding )
6268
69+
6370class MajorType (Enum ):
64- PositiveInteger = 0 ,
65- NegativeInteger = 1 ,
66- ByteString = 2 ,
67- TextString = 3 ,
68- Array = 4 ,
69- Map = 5 ,
70- Tag = 6 ,
71- SimpleOrFloat = 7 ,
71+ PositiveInteger = ( 0 ,)
72+ NegativeInteger = ( 1 ,)
73+ ByteString = ( 2 ,)
74+ TextString = ( 3 ,)
75+ Array = ( 4 ,)
76+ Map = ( 5 ,)
77+ Tag = ( 6 ,)
78+ SimpleOrFloat = ( 7 ,)
7279
7380
7481class CborParser :
@@ -89,16 +96,16 @@ def _read_value(self, buf):
8996 argument_len = 0
9097 elif additional_info == 24 :
9198 argument_len = 1
92- argument = struct .unpack ('>B' , buf [1 : 1 + argument_len ])[0 ]
99+ argument = struct .unpack (">B" , buf [1 : 1 + argument_len ])[0 ]
93100 elif additional_info == 25 :
94101 argument_len = 2
95- argument = struct .unpack ('>H' , buf [1 : 1 + argument_len ])[0 ]
102+ argument = struct .unpack (">H" , buf [1 : 1 + argument_len ])[0 ]
96103 elif additional_info == 26 :
97104 argument_len = 4
98- argument = struct .unpack ('>I' , buf [1 : 1 + argument_len ])[0 ]
105+ argument = struct .unpack (">I" , buf [1 : 1 + argument_len ])[0 ]
99106 elif additional_info == 27 :
100107 argument_len = 8
101- argument = struct .unpack ('>Q' , buf [1 : 1 + argument_len ])[0 ]
108+ argument = struct .unpack (">Q" , buf [1 : 1 + argument_len ])[0 ]
102109 elif additional_info == 31 :
103110 # Indefinite length for types 2-5
104111 argument = None
@@ -138,55 +145,57 @@ def _read_value(self, buf):
138145 string_len = 0
139146 # indefinite length
140147 value = ""
141- while self .data [self .pos ] != 0xff :
142- val = self ._read_value (self .data [self .pos :])[0 ]
148+ while self .data [self .pos ] != 0xFF :
149+ val = self ._read_value (self .data [self .pos :])[0 ]
143150 value += val
144151 string_len = 1
145152 else :
146- value = self .data [self .pos : self .pos + string_len ]
153+ value = self .data [self .pos : self .pos + string_len ]
147154 bytes_consumed = string_len
148155
149156 case MajorType .TextString :
150157 string_len = argument
151158 if string_len is None :
152159 # indefinite length
153160 value = ""
154- while self .data [self .pos ] != 0xff :
155- val = self ._read_value (self .data [self .pos :])
161+ while self .data [self .pos ] != 0xFF :
162+ val = self ._read_value (self .data [self .pos :])
156163 value += val
157164 bytes_consumed = 1
158165 else :
159- value = codecs .utf_8_decode (self .data [self .pos :self .pos + string_len ])[0 ]
166+ value = codecs .utf_8_decode (
167+ self .data [self .pos : self .pos + string_len ]
168+ )[0 ]
160169 bytes_consumed = string_len
161170
162171 case MajorType .Map :
163172 value = {}
164173 if argument is None :
165174 argument = 0
166175 value = {}
167- while self .data [self .pos ] != 0xff :
168- inner_key = self ._read_value (self .data [self .pos :])
169- inner_value = self ._read_value (self .data [self .pos :])
176+ while self .data [self .pos ] != 0xFF :
177+ inner_key = self ._read_value (self .data [self .pos :])
178+ inner_value = self ._read_value (self .data [self .pos :])
170179 value [inner_key ] = inner_value
171180 bytes_consumed = 1
172181 else :
173182 for _ in range (argument ):
174- inner_key = self ._read_value (self .data [self .pos :])
175- inner_value = self ._read_value (self .data [self .pos :])
183+ inner_key = self ._read_value (self .data [self .pos :])
184+ inner_value = self ._read_value (self .data [self .pos :])
176185 value [inner_key ] = inner_value
177186
178187 case MajorType .Array :
179188 value = []
180189 if argument is None :
181190 argument = 0
182191 value = []
183- while self .data [self .pos ] != 0xff :
184- inner_value = self ._read_value (self .data [self .pos :])
192+ while self .data [self .pos ] != 0xFF :
193+ inner_value = self ._read_value (self .data [self .pos :])
185194 value .append (inner_value )
186195 bytes_consumed = 1
187196 else :
188197 for _ in range (argument ):
189- inner_value = self ._read_value (self .data [self .pos :])
198+ inner_value = self ._read_value (self .data [self .pos :])
190199 value .append (inner_value )
191200
192201 case MajorType .Tag :
@@ -207,10 +216,12 @@ def _read_value(self, buf):
207216 self .pos += bytes_consumed
208217 return value
209218
219+
210220def cbor_loads (data ):
211221 parser = CborParser (data )
212222 return parser .parse ()
213223
224+
214225def _parse_authenticator_data (auth_data ):
215226 client_rp_id_hash = auth_data [:32 ]
216227
@@ -223,17 +234,17 @@ def _parse_authenticator_data(auth_data):
223234 flags .add (bits [i ])
224235 flag_byte = flag_byte >> 1
225236
226- sign_count = struct .unpack ('>I' , auth_data [33 :37 ])[0 ]
237+ sign_count = struct .unpack (">I" , auth_data [33 :37 ])[0 ]
227238
228- if 'AT' in flags :
229- aaguid = auth_data [37 : 37 + 16 ]
230- cred_id_length = struct .unpack ('>H' , auth_data [53 :55 ])[0 ]
231- cred_id = auth_data [55 : 55 + cred_id_length ]
232- parser = CborParser (auth_data [55 + cred_id_length :])
239+ if "AT" in flags :
240+ aaguid = auth_data [37 : 37 + 16 ]
241+ cred_id_length = struct .unpack (">H" , auth_data [53 :55 ])[0 ]
242+ cred_id = auth_data [55 : 55 + cred_id_length ]
243+ parser = CborParser (auth_data [55 + cred_id_length :])
233244 _ = parser .parse ()
234- cose_key_bytes = parser .data [:parser .pos ]
245+ cose_key_bytes = parser .data [: parser .pos ]
235246 cose_key_bytes_len = len (cose_key_bytes )
236- assert ( len (cose_key_bytes ) == parser .pos )
247+ assert len (cose_key_bytes ) == parser .pos
237248 attested_cred_data_len = 55 + cred_id_length + cose_key_bytes_len
238249
239250 else :
@@ -242,8 +253,8 @@ def _parse_authenticator_data(auth_data):
242253 cred_id = None
243254 cose_key_bytes = None
244255
245- if 'ED' in flags :
246- extensions = cbor_loads (auth_data [37 + attested_cred_data_len :])
256+ if "ED" in flags :
257+ extensions = cbor_loads (auth_data [37 + attested_cred_data_len :])
247258 else :
248259 extensions = None
249260 return AuthenticatorData (
@@ -253,9 +264,10 @@ def _parse_authenticator_data(auth_data):
253264 aaguid = aaguid ,
254265 cred_id = cred_id ,
255266 pub_key_bytes = cose_key_bytes ,
256- extensions = extensions
267+ extensions = extensions ,
257268 )
258269
270+
259271@dataclass
260272class AuthenticatorData :
261273 rp_id_hash : bytes
@@ -280,27 +292,31 @@ async def create_passkey(interface, options, origin, top_origin):
280292 req_json = json .dumps (options )
281293 logging .debug (req_json )
282294 req = {
283- "type" : Variant ('s' , "publicKey" ),
284- "origin" : Variant ('s' , origin ),
285- "is_same_origin" : Variant ('b' , is_same_origin ),
286- "publicKey" : Variant ('a{sv}' , {
287- "request_json" : Variant ('s' , req_json )
288- })
295+ "type" : Variant ("s" , "publicKey" ),
296+ "origin" : Variant ("s" , origin ),
297+ "is_same_origin" : Variant ("b" , is_same_origin ),
298+ "publicKey" : Variant ("a{sv}" , {"request_json" : Variant ("s" , req_json )}),
289299 }
290300 logging .debug ("Sending request to D-Bus API" )
291301 rsp = await interface .call_create_credential (req )
292- if rsp ['type' ].value != 'public-key' :
293- raise Exception (f"Invalid credential type received: expected 'public-key', received { rsp ['type' .value ]} " )
294- response_json = json .loads (rsp ['public_key' ].value ['registration_response_json' ].value )
295- attestation = cbor_loads (b64_decode (response_json ['response' ]['attestationObject' ]))
302+ if rsp ["type" ].value != "public-key" :
303+ raise Exception (
304+ f"Invalid credential type received: expected 'public-key', received { rsp ['type' .value ]} "
305+ )
306+ response_json = json .loads (
307+ rsp ["public_key" ].value ["registration_response_json" ].value
308+ )
309+ attestation = cbor_loads (b64_decode (response_json ["response" ]["attestationObject" ]))
296310 auth_data_view = attestation ["authData" ]
297- response_json [' response' ][ ' authenticatorData' ] = b64_encode (auth_data_view )
311+ response_json [" response" ][ " authenticatorData" ] = b64_encode (auth_data_view )
298312 auth_data = _parse_authenticator_data (auth_data_view )
299313 if auth_data .pub_key_bytes :
300314 # TODO: format this as SubjectPublicKeyInfo -_-
301- response_json [' response' ][ ' publicKey' ] = b64_encode (auth_data .pub_key_bytes )
315+ response_json [" response" ][ " publicKey" ] = b64_encode (auth_data .pub_key_bytes )
302316 COSE_ALG = 3
303- response_json ['response' ]['publicKeyAlgorithm' ] = auth_data .get_pub_key ()[COSE_ALG ]
317+ response_json ["response" ]["publicKeyAlgorithm" ] = auth_data .get_pub_key ()[
318+ COSE_ALG
319+ ]
304320 return response_json
305321
306322
@@ -310,20 +326,22 @@ async def get_passkey(interface, options, origin, top_origin):
310326 req_json = json .dumps (options )
311327 logging .debug (req_json )
312328 req = {
313- "type" : Variant ('s' , "publicKey" ),
314- "origin" : Variant ('s' , origin ),
315- "is_same_origin" : Variant ('b' , is_same_origin ),
316- "publicKey" : Variant ('a{sv}' , {
317- "request_json" : Variant ('s' , req_json )
318- })
329+ "type" : Variant ("s" , "publicKey" ),
330+ "origin" : Variant ("s" , origin ),
331+ "is_same_origin" : Variant ("b" , is_same_origin ),
332+ "publicKey" : Variant ("a{sv}" , {"request_json" : Variant ("s" , req_json )}),
319333 }
320334
321335 logging .debug ("Sending request to D-Bus API" )
322336 rsp = await interface .call_get_credential (req )
323- if rsp ['type' ].value != 'public-key' :
324- raise Exception (f"Invalid credential type received: expected 'public-key', received { rsp ['type' .value ]} " )
337+ if rsp ["type" ].value != "public-key" :
338+ raise Exception (
339+ f"Invalid credential type received: expected 'public-key', received { rsp ['type' .value ]} "
340+ )
325341
326- response_json = json .loads (rsp ['public_key' ].value ['authentication_response_json' ].value )
342+ response_json = json .loads (
343+ rsp ["public_key" ].value ["authentication_response_json" ].value
344+ )
327345 return response_json
328346
329347
@@ -332,6 +350,7 @@ async def run(cmd, options, origin, top_origin):
332350 bus = await MessageBus ().connect ()
333351 logging .debug ("Connected to bus" )
334352 import os
353+
335354 logging .info (os .getcwd ())
336355
337356 with open ("../../contrib/xyz.iinuwa.credentialsd.Credentials.xml" , "r" ) as f :
@@ -346,17 +365,25 @@ async def run(cmd, options, origin, top_origin):
346365 interface = proxy_object .get_interface ("xyz.iinuwa.credentialsd.Credentials1" )
347366 logging .debug (f"Connected to interface at { interface .path } " )
348367
349- if cmd == 'create' :
350- if 'publicKey' in options :
351- return await create_passkey (interface , options ['publicKey' ], origin , top_origin )
368+ if cmd == "create" :
369+ if "publicKey" in options :
370+ return await create_passkey (
371+ interface , options ["publicKey" ], origin , top_origin
372+ )
352373 else :
353- raise Exception (f"Could not create unknown credential type: { options .keys ()[0 ]} " )
354- elif cmd == 'get' :
355- if 'publicKey' in options :
356- return await get_passkey (interface , options ['publicKey' ], origin , top_origin )
374+ raise Exception (
375+ f"Could not create unknown credential type: { options .keys ()[0 ]} "
376+ )
377+ elif cmd == "get" :
378+ if "publicKey" in options :
379+ return await get_passkey (
380+ interface , options ["publicKey" ], origin , top_origin
381+ )
357382 else :
358- raise Exception (f"Could not get unknown credential type: { options .keys ()[0 ]} " )
359- elif cmd == 'getClientCapabilities' :
383+ raise Exception (
384+ f"Could not get unknown credential type: { options .keys ()[0 ]} "
385+ )
386+ elif cmd == "getClientCapabilities" :
360387 rsp = await interface .call_get_client_capabilities ()
361388 response = {}
362389 for name , val in rsp .items ():
@@ -370,19 +397,19 @@ async def run(cmd, options, origin, top_origin):
370397while True :
371398 logging .debug ("starting event loop message" )
372399 receivedMessage = getMessage ()
373- request_id = receivedMessage [' requestId' ]
400+ request_id = receivedMessage [" requestId" ]
374401 try :
375- cmd = receivedMessage [' cmd' ]
402+ cmd = receivedMessage [" cmd" ]
376403
377404 options = None
378- if ' options' in receivedMessage :
379- options = receivedMessage [' options' ]
380- origin = receivedMessage [' origin' ]
381- top_origin = receivedMessage [' topOrigin' ]
405+ if " options" in receivedMessage :
406+ options = receivedMessage [" options" ]
407+ origin = receivedMessage [" origin" ]
408+ top_origin = receivedMessage [" topOrigin" ]
382409 loop = asyncio .get_event_loop ()
383410 auth_data = loop .run_until_complete (run (cmd , options , origin , top_origin ))
384- sendMessage (encodeMessage ({ "requestId" : request_id , "data" : auth_data }))
411+ sendMessage (encodeMessage ({"requestId" : request_id , "data" : auth_data }))
385412 except Exception as e :
386413 logging .error ("Failed to send message" , exc_info = e )
387- sendMessage (encodeMessage ({ "requestId" : request_id , "error" : str (e ) }))
414+ sendMessage (encodeMessage ({"requestId" : request_id , "error" : str (e )}))
388415 logging .debug ("Sent error message" )
0 commit comments