@@ -23,13 +23,13 @@ describe('WebAuthn Serialization/Deserialization', () => {
23
23
24
24
describe ( 'deserializeCredentialCreationOptions' , ( ) => {
25
25
const validServerOptions = {
26
- challenge : 'dGVzdC1jaGFsbGVuZ2U ' , // "test-challenge" in base64url
26
+ challenge : 'SGVsbG8gV2ViQXV0aG4h ' ,
27
27
rp : {
28
28
name : 'Test RP' ,
29
29
id : 'example.com' ,
30
30
} ,
31
31
user : {
32
- id : 'dXNlci1pZA ' , // "user-id" in base64url
32
+ id : 'dXNlci0xMjM0NTY ' ,
33
33
name : 'test@example.com' ,
34
34
displayName : 'Test User' ,
35
35
} ,
@@ -41,37 +41,40 @@ describe('WebAuthn Serialization/Deserialization', () => {
41
41
attestation : 'direct' as const ,
42
42
excludeCredentials : [
43
43
{
44
- id : 'Y3JlZC1pZA ' , // "cred-id" in base64url
44
+ id : 'Y3JlZGVudGlhbC1hYmMteHl6 ' ,
45
45
type : 'public-key' as const ,
46
46
transports : [ 'usb' , 'nfc' ] as AuthenticatorTransportFuture [ ] ,
47
47
} ,
48
48
] ,
49
49
}
50
50
51
51
it ( 'should convert base64url strings to ArrayBuffers using polyfill' , ( ) => {
52
- // Force polyfill path by removing PublicKeyCredential
52
+
53
53
delete ( global as any ) . PublicKeyCredential
54
54
55
55
const result = deserializeCredentialCreationOptions ( validServerOptions )
56
56
57
- // Verify challenge was converted to ArrayBuffer
57
+
58
58
expect ( result . challenge ) . toBeInstanceOf ( ArrayBuffer )
59
59
const challengeBytes = new Uint8Array ( result . challenge )
60
+
60
61
expect ( challengeBytes ) . toEqual (
61
- new Uint8Array ( [ 116 , 101 , 115 , 116 , 45 , 99 , 104 , 97 , 108 , 108 , 101 , 110 , 103 , 101 ] )
62
+ new Uint8Array ( [ 72 , 101 , 108 , 108 , 111 , 32 , 87 , 101 , 98 , 65 , 117 , 116 , 104 , 110 , 33 ] )
62
63
)
63
64
64
- // Verify user.id was converted to ArrayBuffer
65
+
65
66
expect ( result . user . id ) . toBeInstanceOf ( ArrayBuffer )
66
67
const userIdBytes = new Uint8Array ( result . user . id )
67
- expect ( userIdBytes ) . toEqual ( new Uint8Array ( [ 117 , 115 , 101 , 114 , 45 , 105 , 100 ] ) )
68
+
69
+ expect ( userIdBytes ) . toEqual ( new Uint8Array ( [ 117 , 115 , 101 , 114 , 45 , 49 , 50 , 51 , 52 , 53 , 54 ] ) )
68
70
69
- // Verify excludeCredentials[0].id was converted to ArrayBuffer
71
+
70
72
expect ( result . excludeCredentials ! [ 0 ] . id ) . toBeInstanceOf ( ArrayBuffer )
71
73
const credIdBytes = new Uint8Array ( result . excludeCredentials ! [ 0 ] . id as ArrayBuffer )
72
- expect ( credIdBytes ) . toEqual ( new Uint8Array ( [ 99 , 114 , 101 , 100 , 45 , 105 , 100 ] ) )
74
+
75
+ expect ( credIdBytes ) . toEqual ( new Uint8Array ( [ 99 , 114 , 101 , 100 , 101 , 110 , 116 , 105 , 97 , 108 , 45 , 97 , 98 , 99 , 45 , 120 , 121 , 122 ] ) )
73
76
74
- // Verify other fields are preserved
77
+
75
78
expect ( result . rp ) . toEqual ( validServerOptions . rp )
76
79
expect ( result . pubKeyCredParams ) . toEqual ( validServerOptions . pubKeyCredParams )
77
80
expect ( result . timeout ) . toBe ( 60000 )
@@ -99,10 +102,10 @@ describe('WebAuthn Serialization/Deserialization', () => {
99
102
100
103
it ( 'should handle missing optional fields correctly' , ( ) => {
101
104
const minimalOptions = {
102
- challenge : 'dGVzdC1jaGFsbGVuZ2U' ,
105
+ challenge : 'SGVsbG8gV2ViQXV0aG4h' ,
103
106
rp : { name : 'Test RP' } ,
104
107
user : {
105
- id : 'dXNlci1pZA' ,
108
+ id : 'dXNlci0xMjM0NTY' ,
106
109
name : 'test@example.com' ,
107
110
displayName : 'Test User' ,
108
111
} ,
@@ -130,13 +133,13 @@ describe('WebAuthn Serialization/Deserialization', () => {
130
133
131
134
describe ( 'deserializeCredentialRequestOptions' , ( ) => {
132
135
const validServerOptions = {
133
- challenge : 'dGVzdC1jaGFsbGVuZ2U' ,
136
+ challenge : 'QXV0aGVudGljYXRlTWU' ,
134
137
timeout : 60000 ,
135
138
rpId : 'example.com' ,
136
139
userVerification : 'preferred' as const ,
137
140
allowCredentials : [
138
141
{
139
- id : 'Y3JlZC1pZA' ,
142
+ id : 'YWxsb3dlZC1jcmVkLTEyMw' ,
140
143
type : 'public-key' as const ,
141
144
transports : [ 'usb' , 'nfc' ] as AuthenticatorTransportFuture [ ] ,
142
145
} ,
@@ -148,19 +151,21 @@ describe('WebAuthn Serialization/Deserialization', () => {
148
151
149
152
const result = deserializeCredentialRequestOptions ( validServerOptions )
150
153
151
- // Verify challenge was converted
154
+
152
155
expect ( result . challenge ) . toBeInstanceOf ( ArrayBuffer )
153
156
const challengeBytes = new Uint8Array ( result . challenge )
157
+
154
158
expect ( challengeBytes ) . toEqual (
155
- new Uint8Array ( [ 116 , 101 , 115 , 116 , 45 , 99 , 104 , 97 , 108 , 108 , 101 , 110 , 103 , 101 ] )
159
+ new Uint8Array ( [ 65 , 117 , 116 , 104 , 101 , 110 , 116 , 105 , 99 , 97 , 116 , 101 , 77 , 101 ] )
156
160
)
157
161
158
- // Verify allowCredentials[0].id was converted
162
+
159
163
expect ( result . allowCredentials ! [ 0 ] . id ) . toBeInstanceOf ( ArrayBuffer )
160
164
const credIdBytes = new Uint8Array ( result . allowCredentials ! [ 0 ] . id as ArrayBuffer )
161
- expect ( credIdBytes ) . toEqual ( new Uint8Array ( [ 99 , 114 , 101 , 100 , 45 , 105 , 100 ] ) )
165
+
166
+ expect ( credIdBytes ) . toEqual ( new Uint8Array ( [ 97 , 108 , 108 , 111 , 119 , 101 , 100 , 45 , 99 , 114 , 101 , 100 , 45 , 49 , 50 , 51 ] ) )
162
167
163
- // Verify other fields preserved
168
+
164
169
expect ( result . rpId ) . toBe ( 'example.com' )
165
170
expect ( result . userVerification ) . toBe ( 'preferred' )
166
171
expect ( result . timeout ) . toBe ( 60000 )
@@ -192,15 +197,15 @@ describe('WebAuthn Serialization/Deserialization', () => {
192
197
}
193
198
194
199
const result = deserializeCredentialRequestOptions ( optionsWithEmptyArray )
195
- // Empty array is not added to result per implementation
200
+
196
201
expect ( result . allowCredentials ) . toBeUndefined ( )
197
202
} )
198
203
199
204
it ( 'should handle missing allowCredentials' , ( ) => {
200
205
delete ( global as any ) . PublicKeyCredential
201
206
202
207
const optionsWithoutAllow = {
203
- challenge : 'dGVzdC1jaGFsbGVuZ2U' ,
208
+ challenge : 'QXV0aGVudGljYXRlTWU' ,
204
209
rpId : 'example.com' ,
205
210
}
206
211
@@ -233,10 +238,10 @@ describe('WebAuthn Serialization/Deserialization', () => {
233
238
234
239
const result = serializeCredentialCreationResponse ( mockCredential )
235
240
236
- // Verify ArrayBuffers were converted to base64url
237
- expect ( result . rawId ) . toBe ( mockCredential . id ) // Now correctly converts rawId ArrayBuffer to base64url
238
- expect ( result . response . attestationObject ) . toBe ( 'AQIDBAU' )
239
- expect ( result . response . clientDataJSON ) . toBe ( 'BgcICQo' )
241
+
242
+ expect ( result . rawId ) . toBe ( mockCredential . id )
243
+ expect ( result . response . attestationObject ) . toBe ( 'AQIDBAU' )
244
+ expect ( result . response . clientDataJSON ) . toBe ( 'BgcICQo' )
240
245
expect ( result . authenticatorAttachment ) . toBe ( 'platform' )
241
246
expect ( result . clientExtensionResults ) . toEqual ( { credProps : { rk : true } } )
242
247
} )
@@ -320,12 +325,12 @@ describe('WebAuthn Serialization/Deserialization', () => {
320
325
321
326
const result = serializeCredentialRequestResponse ( mockCredential )
322
327
323
- // Verify conversions
324
- expect ( result . rawId ) . toBe ( mockCredential . id ) // Now correctly converts rawId ArrayBuffer to base64url
325
- expect ( result . response . authenticatorData ) . toBe ( 'AQIDBAU' )
326
- expect ( result . response . clientDataJSON ) . toBe ( 'BgcICQo' )
327
- expect ( result . response . signature ) . toBe ( 'CwwNDg8' )
328
- expect ( result . response . userHandle ) . toBe ( 'EBESExQ' )
328
+
329
+ expect ( result . rawId ) . toBe ( mockCredential . id )
330
+ expect ( result . response . authenticatorData ) . toBe ( 'AQIDBAU' )
331
+ expect ( result . response . clientDataJSON ) . toBe ( 'BgcICQo' )
332
+ expect ( result . response . signature ) . toBe ( 'CwwNDg8' )
333
+ expect ( result . response . userHandle ) . toBe ( 'EBESExQ' )
329
334
} )
330
335
331
336
it ( 'should handle null userHandle correctly' , ( ) => {
@@ -386,10 +391,10 @@ describe('WebAuthn Serialization/Deserialization', () => {
386
391
387
392
describe ( 'mergeCredentialCreationOptions' , ( ) => {
388
393
const baseOptions : PublicKeyCredentialCreationOptionsFuture = {
389
- challenge : new Uint8Array ( [ 1 , 2 , 3 , 4 ] ) . buffer ,
394
+ challenge : new Uint8Array ( [ 67 , 104 , 97 , 108 , 108 , 101 , 110 , 103 , 101 , 49 , 50 , 51 ] ) . buffer ,
390
395
rp : { name : 'Test RP' , id : 'example.com' } ,
391
396
user : {
392
- id : new Uint8Array ( [ 5 , 6 , 7 , 8 ] ) . buffer ,
397
+ id : new Uint8Array ( [ 85 , 115 , 101 , 114 , 49 , 50 , 51 ] ) . buffer ,
393
398
name : 'user@example.com' ,
394
399
displayName : 'Test User' ,
395
400
} ,
@@ -399,7 +404,7 @@ describe('WebAuthn Serialization/Deserialization', () => {
399
404
it ( 'should apply DEFAULT_CREATION_OPTIONS correctly' , ( ) => {
400
405
const result = mergeCredentialCreationOptions ( baseOptions )
401
406
402
- // Verify defaults are applied
407
+
403
408
expect ( result . authenticatorSelection ) . toEqual ( {
404
409
authenticatorAttachment : 'cross-platform' ,
405
410
requireResidentKey : false ,
@@ -409,7 +414,7 @@ describe('WebAuthn Serialization/Deserialization', () => {
409
414
expect ( result . hints ) . toEqual ( [ 'security-key' ] )
410
415
expect ( result . attestation ) . toBe ( 'direct' )
411
416
412
- // Verify base options are preserved
417
+
413
418
expect ( result . challenge ) . toBe ( baseOptions . challenge )
414
419
expect ( result . rp ) . toEqual ( baseOptions . rp )
415
420
expect ( result . user ) . toEqual ( baseOptions . user )
@@ -422,12 +427,12 @@ describe('WebAuthn Serialization/Deserialization', () => {
422
427
} ,
423
428
} )
424
429
425
- // Should merge, not replace
430
+
426
431
expect ( result . authenticatorSelection ) . toEqual ( {
427
432
authenticatorAttachment : 'cross-platform' ,
428
433
requireResidentKey : false ,
429
434
residentKey : 'discouraged' ,
430
- userVerification : 'required' , // Override applied
435
+ userVerification : 'required' ,
431
436
} )
432
437
} )
433
438
@@ -454,7 +459,7 @@ describe('WebAuthn Serialization/Deserialization', () => {
454
459
} )
455
460
456
461
it ( 'should not modify ArrayBuffer fields during merge' , ( ) => {
457
- const customChallenge = new Uint8Array ( [ 9 , 10 , 11 , 12 ] ) . buffer
462
+ const customChallenge = new Uint8Array ( [ 78 , 101 , 119 , 67 , 104 , 97 , 108 , 108 ] ) . buffer
458
463
const result = mergeCredentialCreationOptions ( baseOptions , {
459
464
challenge : customChallenge ,
460
465
} )
@@ -466,11 +471,11 @@ describe('WebAuthn Serialization/Deserialization', () => {
466
471
467
472
describe ( 'mergeCredentialRequestOptions' , ( ) => {
468
473
const baseOptions : PublicKeyCredentialRequestOptionsFuture = {
469
- challenge : new Uint8Array ( [ 1 , 2 , 3 , 4 ] ) . buffer ,
474
+ challenge : new Uint8Array ( [ 82 , 101 , 113 , 117 , 101 , 115 , 116 ] ) . buffer ,
470
475
rpId : 'example.com' ,
471
476
allowCredentials : [
472
477
{
473
- id : new Uint8Array ( [ 5 , 6 , 7 , 8 ] ) . buffer ,
478
+ id : new Uint8Array ( [ 67 , 114 , 101 , 100 , 49 , 50 , 51 ] ) . buffer ,
474
479
type : 'public-key' ,
475
480
transports : [ 'usb' ] ,
476
481
} ,
@@ -483,7 +488,7 @@ describe('WebAuthn Serialization/Deserialization', () => {
483
488
expect ( result . userVerification ) . toBe ( 'preferred' )
484
489
expect ( result . hints ) . toEqual ( [ 'security-key' ] )
485
490
486
- // Base options preserved
491
+
487
492
expect ( result . challenge ) . toBe ( baseOptions . challenge )
488
493
expect ( result . allowCredentials ) . toBe ( baseOptions . allowCredentials )
489
494
} )
@@ -503,7 +508,7 @@ describe('WebAuthn Serialization/Deserialization', () => {
503
508
it ( 'should preserve allowCredentials ArrayBuffers' , ( ) => {
504
509
const newCreds = [
505
510
{
506
- id : new Uint8Array ( [ 9 , 10 , 11 , 12 ] ) . buffer ,
511
+ id : new Uint8Array ( [ 78 , 101 , 119 , 67 , 114 , 101 , 100 ] ) . buffer ,
507
512
type : 'public-key' as const ,
508
513
transports : [ 'nfc' ] as AuthenticatorTransportFuture [ ] ,
509
514
} ,
0 commit comments