@@ -64,7 +64,7 @@ let defaultCreateOrReplaceCredOpts = {
6464
6565 userVerification : "discouraged" , // implicit register // "preferred", "required"
6666 } ,
67- challenge : challenge ,
67+ challenge : challenge , // for attestation
6868 // don't create for
6969 excludeCredentials : [ ] , // { id, transports, type }
7070 // https://caniuse.com/mdn-api_credentialscontainer_create_publickey_option_extensions
@@ -160,7 +160,7 @@ let defaultGetCredOpts = {
160160 // type: "public-key",
161161 // },
162162 ] ,
163- challenge : challenge ,
163+ challenge : challenge , // for signature
164164 // extensions: [],
165165 // hints: [],
166166 // can make Cross-Origin requests
@@ -205,6 +205,53 @@ Object.assign(window, {
205205 setAttachment,
206206} ) ;
207207
208+ /**
209+ * Converts a WebAuthn Public Key Credential response to plain JSON with base64 encoding for byte array fields.
210+ * @param {CredentialCreationOptions } pubkeyRegOpts
211+ * https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAttestationResponse
212+ * https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialCreationOptions
213+ */
214+ async function setPasskey ( pubkeyRegOpts ) {
215+ console . log ( "createOrReplacePublicKey() pubkeyRegOpts" , pubkeyRegOpts ) ;
216+
217+ abortController . abort ( currentAbort ) ;
218+ abortController = new AbortController ( ) ;
219+ pubkeyRegOpts . signal = abortController . signal ;
220+
221+ void globalThis . crypto . getRandomValues ( challenge ) ;
222+ if ( ! pubkeyRegOpts . publicKey ) {
223+ throw new Error ( ".publicKey must exist" ) ;
224+ }
225+ pubkeyRegOpts . publicKey . challenge = challenge ;
226+
227+ const pubkeyRegResp = await navigator . credentials
228+ . create ( pubkeyRegOpts )
229+ . catch ( function ( err ) {
230+ // this may never fire
231+ console . warn ( "Error: navigator.credentials.create():" ) ;
232+ console . log ( err ) ;
233+ return null ;
234+ } ) ;
235+
236+ if ( ! pubkeyRegResp ) {
237+ console . warn ( "WebAuthn was changed, restarted, failed, or canceled" ) ;
238+ if ( currentMediation === "conditional" ) {
239+ let authRequestOpts = globalThis . structuredClone ( defaultGetCredOpts ) ;
240+ authRequestOpts . mediation = currentMediation ;
241+ void ( await authorizePasskey ( authRequestOpts ) ) ;
242+ }
243+ return ;
244+ }
245+ /** @type {PublicKeyCredential } */ //@ts -ignore
246+ let pubkeyRegistration = pubkeyRegResp ;
247+
248+ console . log ( `createCredential response opaque:` ) ;
249+ console . log ( pubkeyRegistration ) ;
250+ let registerResult = pubkeyRegisterToJSON ( pubkeyRegistration ) ;
251+ console . log ( `createCredential response JSON:` ) ;
252+ console . log ( registerResult ) ;
253+ }
254+
208255/**
209256 * @param {Event } event
210257 */
@@ -215,19 +262,16 @@ async function createOrReplacePublicKey(event) {
215262 let pubkeyRegOpts = globalThis . structuredClone (
216263 defaultCreateOrReplaceCredOpts ,
217264 ) ;
265+ if ( ! pubkeyRegOpts . publicKey ) {
266+ throw new Error ( ".publicKey must exist" ) ;
267+ }
218268
219269 if ( currentAttachment ) {
220270 let attachment = currentAttachment ;
221271 //@ts -ignore
222272 pubkeyRegOpts . publicKey . authenticatorSelection . attachment = attachment ;
223273 }
224274
225- void globalThis . crypto . getRandomValues ( challenge ) ;
226- if ( ! pubkeyRegOpts . publicKey ) {
227- throw new Error ( ".publicKey must exist" ) ;
228- }
229- pubkeyRegOpts . publicKey . challenge = challenge ;
230-
231275 //@ts -ignore
232276 let username = $ ( "input[name=username]" ) . value ;
233277 if ( ! username ) {
@@ -254,38 +298,7 @@ async function createOrReplacePublicKey(event) {
254298 // excludeCredentials: [ { type: 'public-key', id: 'base64id' }]
255299 pubkeyRegOpts . publicKey . excludeCredentials = [ ] ;
256300
257- console . log ( "createOrReplacePublicKey() pubkeyRegOpts" , pubkeyRegOpts ) ;
258-
259- abortController . abort ( currentAbort ) ;
260- abortController = new AbortController ( ) ;
261- pubkeyRegOpts . signal = abortController . signal ;
262-
263- const pubkeyRegResp = await navigator . credentials
264- . create ( pubkeyRegOpts )
265- . catch ( function ( err ) {
266- // this may never fire
267- console . warn ( "Error: navigator.credentials.create():" ) ;
268- console . log ( err ) ;
269- return null ;
270- } ) ;
271-
272- if ( ! pubkeyRegResp ) {
273- console . warn ( "WebAuthn was changed, restarted, failed, or canceled" ) ;
274- if ( currentMediation === "conditional" ) {
275- let authRequestOpts = globalThis . structuredClone ( defaultGetCredOpts ) ;
276- authRequestOpts . mediation = currentMediation ;
277- void ( await authorizePasskey ( authRequestOpts ) . catch ( catchUiError ) ) ;
278- }
279- return ;
280- }
281- /** @type {PublicKeyCredential } */ //@ts -ignore
282- let pubkeyRegistration = pubkeyRegResp ;
283-
284- console . log ( `createCredential response opaque:` ) ;
285- console . log ( pubkeyRegistration ) ;
286- let registerResult = pubkeyRegisterToJSON ( pubkeyRegistration ) ;
287- console . log ( `createCredential response JSON:` ) ;
288- console . log ( registerResult ) ;
301+ await setPasskey ( pubkeyRegOpts ) . catch ( catchUiError ) ;
289302}
290303
291304/**
@@ -297,6 +310,12 @@ async function createOrReplacePublicKey(event) {
297310async function authorizePasskey ( authRequestOpts ) {
298311 console . log ( "getPublicKey() authRequestOpts" , authRequestOpts ) ;
299312
313+ void globalThis . crypto . getRandomValues ( challenge ) ;
314+ if ( ! authRequestOpts . publicKey ) {
315+ throw new Error ( ".publicKey must exist" ) ;
316+ }
317+ authRequestOpts . publicKey . challenge = challenge ;
318+
300319 abortController . abort ( currentAbort ) ;
301320 abortController = new AbortController ( ) ;
302321 authRequestOpts . signal = abortController . signal ;
@@ -337,13 +356,6 @@ async function getPublicKey(event) {
337356
338357 let authRequestOpts = globalThis . structuredClone ( defaultGetCredOpts ) ;
339358
340- if ( ! authRequestOpts . publicKey ) {
341- throw new Error ( ".publicKey must exist" ) ;
342- }
343-
344- authRequestOpts . publicKey . challenge = challenge ;
345- void globalThis . crypto . getRandomValues ( challenge ) ;
346-
347359 authRequestOpts . mediation = currentMediation ;
348360
349361 // to prevent overwriting the ID / public key when creating
0 commit comments