11#!/usr/bin/env python3
22from contextlib import closing
3+ import functools
34import json
45import math
56import os
1819import gi
1920
2021gi .require_version ("Gtk" , "4.0" )
22+ gi .require_version ("GdkWayland" , "4.0" )
2123gi .require_version ("Adw" , "1" )
22- from gi .repository import Gio , GObject , Gtk , Adw # noqa: E402
24+ from gi .repository import GdkWayland , Gio , GObject , Gtk , Adw # noqa: E402
2325
2426import webauthn # noqa: E402
2527import util # noqa: E402
@@ -72,6 +74,9 @@ def on_register(self, *args):
7274 now = math .floor (time .time ())
7375 cur = DB .cursor ()
7476 username = self .username .get_text ()
77+ if not username :
78+ print ("Username is required" )
79+ return
7580 cur .execute (
7681 "select user_id, user_handle from users where username = ?" , (username ,)
7782 )
@@ -87,34 +92,40 @@ def on_register(self, *args):
8792 )
8893 options = self ._get_registration_options (user_handle , username )
8994 print (f"registration options: { options } " )
90- auth_data = create_passkey (INTERFACE , self .origin , self .origin , options )
91- if not user_id :
92- cur .execute (
93- "insert into users (username, user_handle, created_time) values (?, ?, ?)" ,
94- (username , user_handle , now ),
95- )
96- user_id = cur .lastrowid
97- params = {
98- "user_handle" : user_handle ,
99- "cred_id" : auth_data .cred_id ,
100- "aaguid" : str (uuid .UUID (bytes = bytes (auth_data .aaguid ))),
101- "sign_count" : None if auth_data .sign_count == 0 else auth_data .sign_count ,
102- "backup_eligible" : 1 if "BE" in auth_data .flags else 0 ,
103- "backup_state" : 1 if "BS" in auth_data .flags else 0 ,
104- "uv_initialized" : 1 if "UV" in auth_data .flags else 0 ,
105- "cose_pub_key" : auth_data .pub_key_bytes ,
106- "created_time" : now ,
107- }
108-
109- add_passkey_sql = """
110- insert into user_passkeys
111- (user_handle, cred_id, aaguid, sign_count, backup_eligible, backup_state, uv_initialized, cose_pub_key, created_time)
112- values
113- (:user_handle, :cred_id, :aaguid, :sign_count, :backup_eligible, :backup_state, :uv_initialized, :cose_pub_key, :created_time)
114- """
115- cur .execute (add_passkey_sql , params )
116- print ("Added passkey" )
117- DB .commit ()
95+ def cb (user_id , toplevel , handle ):
96+ cur = DB .cursor ()
97+ window_handle = "wayland:{handle}"
98+ auth_data = create_passkey (INTERFACE , window_handle , self .origin , self .origin , options )
99+ if not user_id :
100+ cur .execute (
101+ "insert into users (username, user_handle, created_time) values (?, ?, ?)" ,
102+ (username , user_handle , now ),
103+ )
104+ user_id = cur .lastrowid
105+ params = {
106+ "user_handle" : user_handle ,
107+ "cred_id" : auth_data .cred_id ,
108+ "aaguid" : str (uuid .UUID (bytes = bytes (auth_data .aaguid ))),
109+ "sign_count" : None if auth_data .sign_count == 0 else auth_data .sign_count ,
110+ "backup_eligible" : 1 if "BE" in auth_data .flags else 0 ,
111+ "backup_state" : 1 if "BS" in auth_data .flags else 0 ,
112+ "uv_initialized" : 1 if "UV" in auth_data .flags else 0 ,
113+ "cose_pub_key" : auth_data .pub_key_bytes ,
114+ "created_time" : now ,
115+ }
116+
117+ add_passkey_sql = """
118+ insert into user_passkeys
119+ (user_handle, cred_id, aaguid, sign_count, backup_eligible, backup_state, uv_initialized, cose_pub_key, created_time)
120+ values
121+ (:user_handle, :cred_id, :aaguid, :sign_count, :backup_eligible, :backup_state, :uv_initialized, :cose_pub_key, :created_time)
122+ """
123+ cur .execute (add_passkey_sql , params )
124+ print ("Added passkey" )
125+ DB .commit ()
126+ cur .close ()
127+ toplevel = self .get_surface ()
128+ toplevel .export_handle (functools .partial (cb , user_id ))
118129 cur .close ()
119130
120131 @Gtk .Template .Callback ()
@@ -202,17 +213,27 @@ def retrieve_user_cred(
202213 return user_cred
203214 else :
204215 return None
216+ def cb (toplevel , window_handle ):
217+ print (f"received window handle: { window_handle } " )
218+ window_handle = f"wayland:{ window_handle } "
219+
220+ auth_data = get_passkey (
221+ INTERFACE ,
222+ window_handle ,
223+ self .origin ,
224+ self .origin ,
225+ self .rp_id ,
226+ cred_ids ,
227+ retrieve_user_cred ,
228+ )
229+ print ("Received passkey:" )
230+ pprint (auth_data )
205231
206- auth_data = get_passkey (
207- INTERFACE ,
208- self .origin ,
209- self .origin ,
210- self .rp_id ,
211- cred_ids ,
212- retrieve_user_cred ,
213- )
214- print ("Received passkey:" )
215- pprint (auth_data )
232+ toplevel = self .get_surface ()
233+ print (type (toplevel ))
234+ toplevel .export_handle (cb )
235+ print ("Waiting for handle to complete" )
236+ # event.wait()
216237
217238 @GObject .Property (type = Gtk .StringList )
218239 def uv_pref (self ):
@@ -281,7 +302,7 @@ def on_activate(self, app):
281302
282303
283304def create_passkey (
284- interface : ProxyInterface , origin : str , top_origin : str , options : dict
305+ interface : ProxyInterface , window_handle : str , origin : str , top_origin : str , options : dict
285306) -> webauthn .AuthenticatorData :
286307 is_same_origin = origin == top_origin
287308 print (
@@ -298,7 +319,7 @@ def create_passkey(
298319 "publicKey" : Variant ("a{sv}" , {"request_json" : Variant ("s" , req_json )}),
299320 }
300321
301- rsp = interface .call_create_credential_sync (req )
322+ rsp = interface .call_create_credential_sync ([ req , window_handle ] )
302323
303324 # print("Received response")
304325 # pprint(rsp)
@@ -313,7 +334,7 @@ def create_passkey(
313334 return webauthn .verify_create_response (response_json , options , origin )
314335
315336
316- def get_passkey (interface , origin , top_origin , rp_id , cred_ids , cred_lookup_fn ):
337+ def get_passkey (interface , window_handle , origin , top_origin , rp_id , cred_ids , cred_lookup_fn ):
317338 is_same_origin = origin == top_origin
318339 options = {
319340 "challenge" : util .b64_encode (secrets .token_bytes (16 )),
@@ -337,7 +358,7 @@ def get_passkey(interface, origin, top_origin, rp_id, cred_ids, cred_lookup_fn):
337358 "publicKey" : Variant ("a{sv}" , {"request_json" : Variant ("s" , req_json )}),
338359 }
339360
340- rsp = interface .call_get_credential_sync (req )
361+ rsp = interface .call_get_credential_sync ([ req , window_handle ] )
341362 # print("Received response")
342363 # pprint(rsp)
343364 if rsp ["type" ].value != "public-key" :
0 commit comments