ox 0.12.4 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/_cjs/core/P256.js +1 -1
  3. package/_cjs/core/P256.js.map +1 -1
  4. package/_cjs/core/WebAuthnP256.js +15 -256
  5. package/_cjs/core/WebAuthnP256.js.map +1 -1
  6. package/_cjs/core/WebCryptoP256.js +3 -1
  7. package/_cjs/core/WebCryptoP256.js.map +1 -1
  8. package/_cjs/core/internal/webauthn.js +5 -13
  9. package/_cjs/core/internal/webauthn.js.map +1 -1
  10. package/_cjs/index.docs.js +1 -0
  11. package/_cjs/index.docs.js.map +1 -1
  12. package/_cjs/tempo/KeyAuthorization.js +18 -3
  13. package/_cjs/tempo/KeyAuthorization.js.map +1 -1
  14. package/_cjs/tempo/SignatureEnvelope.js +26 -0
  15. package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
  16. package/_cjs/tempo/TxEnvelopeTempo.js +5 -10
  17. package/_cjs/tempo/TxEnvelopeTempo.js.map +1 -1
  18. package/_cjs/version.js +1 -1
  19. package/_cjs/webauthn/Authentication.js +246 -0
  20. package/_cjs/webauthn/Authentication.js.map +1 -0
  21. package/_cjs/webauthn/Authenticator.js +55 -0
  22. package/_cjs/webauthn/Authenticator.js.map +1 -0
  23. package/_cjs/webauthn/Credential.js +53 -0
  24. package/_cjs/webauthn/Credential.js.map +1 -0
  25. package/_cjs/webauthn/Registration.js +349 -0
  26. package/_cjs/webauthn/Registration.js.map +1 -0
  27. package/_cjs/webauthn/Types.js +3 -0
  28. package/_cjs/webauthn/Types.js.map +1 -0
  29. package/_cjs/webauthn/index.js +9 -0
  30. package/_cjs/webauthn/index.js.map +1 -0
  31. package/_cjs/webauthn/internal/utils.js +53 -0
  32. package/_cjs/webauthn/internal/utils.js.map +1 -0
  33. package/_esm/core/P256.js +1 -1
  34. package/_esm/core/P256.js.map +1 -1
  35. package/_esm/core/WebAuthnP256.js +13 -261
  36. package/_esm/core/WebAuthnP256.js.map +1 -1
  37. package/_esm/core/WebCryptoP256.js +4 -1
  38. package/_esm/core/WebCryptoP256.js.map +1 -1
  39. package/_esm/core/internal/webauthn.js +5 -13
  40. package/_esm/core/internal/webauthn.js.map +1 -1
  41. package/_esm/erc8021/index.js +2 -2
  42. package/_esm/index.docs.js +1 -0
  43. package/_esm/index.docs.js.map +1 -1
  44. package/_esm/tempo/KeyAuthorization.js +66 -3
  45. package/_esm/tempo/KeyAuthorization.js.map +1 -1
  46. package/_esm/tempo/SignatureEnvelope.js +74 -0
  47. package/_esm/tempo/SignatureEnvelope.js.map +1 -1
  48. package/_esm/tempo/TransactionReceipt.js +1 -1
  49. package/_esm/tempo/TransactionRequest.js +1 -1
  50. package/_esm/tempo/TxEnvelopeTempo.js +5 -10
  51. package/_esm/tempo/TxEnvelopeTempo.js.map +1 -1
  52. package/_esm/version.js +1 -1
  53. package/_esm/webauthn/Authentication.js +453 -0
  54. package/_esm/webauthn/Authentication.js.map +1 -0
  55. package/_esm/webauthn/Authenticator.js +176 -0
  56. package/_esm/webauthn/Authenticator.js.map +1 -0
  57. package/_esm/webauthn/Credential.js +95 -0
  58. package/_esm/webauthn/Credential.js.map +1 -0
  59. package/_esm/webauthn/Registration.js +512 -0
  60. package/_esm/webauthn/Registration.js.map +1 -0
  61. package/_esm/webauthn/Types.js +2 -0
  62. package/_esm/webauthn/Types.js.map +1 -0
  63. package/_esm/webauthn/index.js +31 -0
  64. package/_esm/webauthn/index.js.map +1 -0
  65. package/_esm/webauthn/internal/utils.js +52 -0
  66. package/_esm/webauthn/internal/utils.js.map +1 -0
  67. package/_types/core/WebAuthnP256.d.ts +33 -208
  68. package/_types/core/WebAuthnP256.d.ts.map +1 -1
  69. package/_types/core/WebCryptoP256.d.ts +2 -0
  70. package/_types/core/WebCryptoP256.d.ts.map +1 -1
  71. package/_types/core/internal/webauthn.d.ts +2 -110
  72. package/_types/core/internal/webauthn.d.ts.map +1 -1
  73. package/_types/erc8021/index.d.ts +2 -2
  74. package/_types/index.docs.d.ts +1 -0
  75. package/_types/index.docs.d.ts.map +1 -1
  76. package/_types/tempo/KeyAuthorization.d.ts +57 -0
  77. package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
  78. package/_types/tempo/SignatureEnvelope.d.ts +75 -0
  79. package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
  80. package/_types/tempo/Transaction.d.ts +2 -2
  81. package/_types/tempo/TransactionReceipt.d.ts +2 -2
  82. package/_types/tempo/TransactionRequest.d.ts +2 -2
  83. package/_types/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  84. package/_types/version.d.ts +1 -1
  85. package/_types/webauthn/Authentication.d.ts +324 -0
  86. package/_types/webauthn/Authentication.d.ts.map +1 -0
  87. package/_types/webauthn/Authenticator.d.ts +182 -0
  88. package/_types/webauthn/Authenticator.d.ts.map +1 -0
  89. package/_types/webauthn/Credential.d.ts +77 -0
  90. package/_types/webauthn/Credential.d.ts.map +1 -0
  91. package/_types/webauthn/Registration.d.ts +308 -0
  92. package/_types/webauthn/Registration.d.ts.map +1 -0
  93. package/_types/webauthn/Types.d.ts +106 -0
  94. package/_types/webauthn/Types.d.ts.map +1 -0
  95. package/_types/webauthn/index.d.ts +33 -0
  96. package/_types/webauthn/index.d.ts.map +1 -0
  97. package/_types/webauthn/internal/utils.d.ts +17 -0
  98. package/_types/webauthn/internal/utils.d.ts.map +1 -0
  99. package/core/P256.ts +1 -1
  100. package/core/WebAuthnP256.ts +37 -582
  101. package/core/WebCryptoP256.ts +6 -1
  102. package/core/internal/webauthn.ts +6 -165
  103. package/erc8021/index.ts +2 -2
  104. package/index.docs.ts +1 -0
  105. package/package.json +31 -1
  106. package/tempo/KeyAuthorization.test.ts +139 -0
  107. package/tempo/KeyAuthorization.ts +82 -3
  108. package/tempo/SignatureEnvelope.test.ts +147 -0
  109. package/tempo/SignatureEnvelope.ts +113 -0
  110. package/tempo/Transaction.ts +2 -2
  111. package/tempo/TransactionReceipt.ts +2 -2
  112. package/tempo/TransactionRequest.ts +2 -2
  113. package/tempo/TxEnvelopeTempo.ts +5 -12
  114. package/tempo/e2e.test.ts +265 -0
  115. package/version.ts +1 -1
  116. package/webauthn/Authentication/package.json +6 -0
  117. package/webauthn/Authentication.ts +673 -0
  118. package/webauthn/Authenticator/package.json +6 -0
  119. package/webauthn/Authenticator.ts +259 -0
  120. package/webauthn/Credential/package.json +6 -0
  121. package/webauthn/Credential.ts +146 -0
  122. package/webauthn/Registration/package.json +6 -0
  123. package/webauthn/Registration.ts +805 -0
  124. package/webauthn/Types/package.json +6 -0
  125. package/webauthn/Types.ts +158 -0
  126. package/webauthn/index.ts +38 -0
  127. package/webauthn/internal/utils.ts +63 -0
  128. package/webauthn/package.json +6 -0
@@ -0,0 +1,453 @@
1
+ import * as Base64 from '../core/Base64.js';
2
+ import * as Bytes from '../core/Bytes.js';
3
+ import * as Errors from '../core/Errors.js';
4
+ import * as Hash from '../core/Hash.js';
5
+ import * as Hex from '../core/Hex.js';
6
+ import * as internal from '../core/internal/webauthn.js';
7
+ import * as P256 from '../core/P256.js';
8
+ import * as Signature from '../core/Signature.js';
9
+ import { getAuthenticatorData, getClientDataJSON } from './Authenticator.js';
10
+ import { base64UrlOptions, bufferSourceToBytes, bytesToArrayBuffer, deserializeExtensions, responseKeys, serializeExtensions, } from './internal/utils.js';
11
+ /**
12
+ * Deserializes credential request options that can be passed to
13
+ * `navigator.credentials.get()`.
14
+ *
15
+ * @example
16
+ * ```ts twoslash
17
+ * import { Authentication } from 'ox/webauthn'
18
+ *
19
+ * const options = Authentication.getOptions({
20
+ * challenge: '0xdeadbeef',
21
+ * })
22
+ * const serialized = Authentication.serializeOptions(options)
23
+ *
24
+ * // ... send to server and back ...
25
+ *
26
+ * const deserialized = Authentication.deserializeOptions(serialized) // [!code focus]
27
+ * const credential = await window.navigator.credentials.get(deserialized)
28
+ * ```
29
+ *
30
+ * @param options - The serialized credential request options.
31
+ * @returns The deserialized credential request options.
32
+ */
33
+ export function deserializeOptions(options) {
34
+ const { publicKey, ...rest } = options;
35
+ if (!publicKey)
36
+ return { ...rest };
37
+ const { allowCredentials, challenge, extensions, ...publicKeyRest } = publicKey;
38
+ return {
39
+ ...rest,
40
+ publicKey: {
41
+ ...publicKeyRest,
42
+ challenge: Bytes.fromHex(challenge),
43
+ ...(allowCredentials && {
44
+ allowCredentials: allowCredentials.map(({ id, ...rest }) => ({
45
+ ...rest,
46
+ id: Base64.toBytes(id),
47
+ })),
48
+ }),
49
+ ...(extensions && {
50
+ extensions: deserializeExtensions(extensions),
51
+ }),
52
+ },
53
+ };
54
+ }
55
+ /**
56
+ * Deserializes a serialized authentication response.
57
+ *
58
+ * @example
59
+ * ```ts twoslash
60
+ * import { Authentication } from 'ox/webauthn'
61
+ *
62
+ * const response = Authentication.deserializeResponse({ // [!code focus]
63
+ * id: 'm1-bMPuAqpWhCxHZQZTT6e-lSPntQbh3opIoGe7g4Qs', // [!code focus]
64
+ * metadata: { // [!code focus]
65
+ * authenticatorData: '0x49960de5...', // [!code focus]
66
+ * clientDataJSON: '{"type":"webauthn.get",...}', // [!code focus]
67
+ * challengeIndex: 23, // [!code focus]
68
+ * typeIndex: 1, // [!code focus]
69
+ * userVerificationRequired: true, // [!code focus]
70
+ * }, // [!code focus]
71
+ * raw: { // [!code focus]
72
+ * id: 'm1-bMPuAqpWhCxHZQZTT6e-lSPntQbh3opIoGe7g4Qs', // [!code focus]
73
+ * type: 'public-key', // [!code focus]
74
+ * authenticatorAttachment: 'platform', // [!code focus]
75
+ * rawId: 'm1-bMPuAqpWhCxHZQZTT6e-lSPntQbh3opIoGe7g4Qs', // [!code focus]
76
+ * response: { clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0In0' }, // [!code focus]
77
+ * }, // [!code focus]
78
+ * signature: '0x...', // [!code focus]
79
+ * }) // [!code focus]
80
+ * ```
81
+ *
82
+ * @param response - The serialized authentication response.
83
+ * @returns The deserialized authentication response.
84
+ */
85
+ export function deserializeResponse(response) {
86
+ const { id, metadata, raw, signature } = response;
87
+ const rawResponse = {};
88
+ for (const [key, value] of Object.entries(raw.response))
89
+ rawResponse[key] = bytesToArrayBuffer(Base64.toBytes(value));
90
+ return {
91
+ id,
92
+ metadata,
93
+ raw: {
94
+ id: raw.id,
95
+ type: raw.type,
96
+ authenticatorAttachment: raw.authenticatorAttachment,
97
+ rawId: bytesToArrayBuffer(Base64.toBytes(raw.rawId)),
98
+ response: rawResponse,
99
+ getClientExtensionResults: () => ({}),
100
+ },
101
+ signature: Signature.from(signature),
102
+ };
103
+ }
104
+ /**
105
+ * Returns the request options to sign a challenge with the Web Authentication API.
106
+ *
107
+ * @example
108
+ * ```ts twoslash
109
+ * import { Authentication } from 'ox/webauthn'
110
+ *
111
+ * const options = Authentication.getOptions({
112
+ * challenge: '0xdeadbeef',
113
+ * })
114
+ *
115
+ * const credential = await window.navigator.credentials.get(options)
116
+ * ```
117
+ *
118
+ * @param options - Options.
119
+ * @returns The credential request options.
120
+ */
121
+ export function getOptions(options) {
122
+ const { credentialId, challenge, extensions, rpId = window.location.hostname, userVerification = 'required', } = options;
123
+ return {
124
+ publicKey: {
125
+ ...(credentialId
126
+ ? {
127
+ allowCredentials: Array.isArray(credentialId)
128
+ ? credentialId.map((id) => ({
129
+ id: Base64.toBytes(id),
130
+ type: 'public-key',
131
+ }))
132
+ : [
133
+ {
134
+ id: Base64.toBytes(credentialId),
135
+ type: 'public-key',
136
+ },
137
+ ],
138
+ }
139
+ : {}),
140
+ challenge: Bytes.fromHex(challenge),
141
+ ...(extensions && { extensions }),
142
+ rpId,
143
+ userVerification,
144
+ },
145
+ };
146
+ }
147
+ /**
148
+ * Constructs the final digest that was signed and computed by the authenticator. This payload includes
149
+ * the cryptographic `challenge`, as well as authenticator metadata (`authenticatorData` + `clientDataJSON`).
150
+ * This value can be also used with raw P256 verification (such as `P256.verify` or
151
+ * `WebCryptoP256.verify`).
152
+ *
153
+ * :::warning
154
+ *
155
+ * This function is mainly for testing purposes or for manually constructing
156
+ * signing payloads. In most cases you will not need this function and
157
+ * instead use `Authentication.sign`.
158
+ *
159
+ * :::
160
+ *
161
+ * @example
162
+ * ```ts twoslash
163
+ * import { Authentication } from 'ox/webauthn'
164
+ * import { WebCryptoP256 } from 'ox'
165
+ *
166
+ * const { metadata, payload } = Authentication.getSignPayload({ // [!code focus]
167
+ * challenge: '0xdeadbeef', // [!code focus]
168
+ * }) // [!code focus]
169
+ *
170
+ * const { publicKey, privateKey } = await WebCryptoP256.createKeyPair()
171
+ *
172
+ * const signature = await WebCryptoP256.sign({
173
+ * payload,
174
+ * privateKey,
175
+ * })
176
+ * ```
177
+ *
178
+ * @param options - Options to construct the signing payload.
179
+ * @returns The signing payload.
180
+ */
181
+ export function getSignPayload(options) {
182
+ const { challenge, crossOrigin, extraClientData, flag, origin, rpId, signCount, userVerification = 'required', } = options;
183
+ const authenticatorData = getAuthenticatorData({
184
+ flag,
185
+ rpId,
186
+ signCount,
187
+ });
188
+ const clientDataJSON = getClientDataJSON({
189
+ challenge,
190
+ crossOrigin,
191
+ extraClientData,
192
+ origin,
193
+ });
194
+ const clientDataJSONHash = Hash.sha256(Hex.fromString(clientDataJSON));
195
+ const challengeIndex = clientDataJSON.indexOf('"challenge"');
196
+ const typeIndex = clientDataJSON.indexOf('"type"');
197
+ const metadata = {
198
+ authenticatorData,
199
+ clientDataJSON,
200
+ challengeIndex,
201
+ typeIndex,
202
+ userVerificationRequired: userVerification === 'required',
203
+ };
204
+ const payload = Hex.concat(authenticatorData, clientDataJSONHash);
205
+ return { metadata, payload };
206
+ }
207
+ /**
208
+ * Serializes credential request options into a JSON-serializable
209
+ * format, converting `BufferSource` fields to base64url strings.
210
+ *
211
+ * @example
212
+ * ```ts twoslash
213
+ * import { Authentication } from 'ox/webauthn'
214
+ *
215
+ * const options = Authentication.getOptions({
216
+ * challenge: '0xdeadbeef',
217
+ * })
218
+ *
219
+ * const serialized = Authentication.serializeOptions(options) // [!code focus]
220
+ *
221
+ * // `serialized` is JSON-serializable — send it to a server, store it, etc.
222
+ * const json = JSON.stringify(serialized)
223
+ * ```
224
+ *
225
+ * @param options - The credential request options to serialize.
226
+ * @returns The serialized credential request options.
227
+ */
228
+ export function serializeOptions(options) {
229
+ const { publicKey, signal: _, ...rest } = options;
230
+ if (!publicKey)
231
+ return { ...rest };
232
+ const { allowCredentials, challenge, extensions, ...publicKeyRest } = publicKey;
233
+ return {
234
+ ...rest,
235
+ publicKey: {
236
+ ...publicKeyRest,
237
+ challenge: Hex.fromBytes(bufferSourceToBytes(challenge)),
238
+ ...(allowCredentials && {
239
+ allowCredentials: allowCredentials.map(({ id, ...rest }) => ({
240
+ ...rest,
241
+ id: Base64.fromBytes(bufferSourceToBytes(id), base64UrlOptions),
242
+ })),
243
+ }),
244
+ ...(extensions && {
245
+ extensions: serializeExtensions(extensions),
246
+ }),
247
+ },
248
+ };
249
+ }
250
+ /**
251
+ * Serializes an authentication response into a JSON-serializable
252
+ * format, converting `BufferSource` fields to base64url strings
253
+ * and the signature to a hex string.
254
+ *
255
+ * @example
256
+ * ```ts twoslash
257
+ * import { Authentication } from 'ox/webauthn'
258
+ *
259
+ * const response = await Authentication.sign({
260
+ * challenge: '0xdeadbeef',
261
+ * })
262
+ *
263
+ * const serialized = Authentication.serializeResponse(response) // [!code focus]
264
+ *
265
+ * // `serialized` is JSON-serializable — send it to a server, store it, etc.
266
+ * const json = JSON.stringify(serialized)
267
+ * ```
268
+ *
269
+ * @param response - The authentication response to serialize.
270
+ * @returns The serialized authentication response.
271
+ */
272
+ export function serializeResponse(response) {
273
+ const { id, metadata, raw, signature } = response;
274
+ const rawResponse = {};
275
+ for (const key of responseKeys) {
276
+ const value = raw.response[key];
277
+ if (value instanceof ArrayBuffer)
278
+ rawResponse[key] = Base64.fromBytes(new Uint8Array(value), base64UrlOptions);
279
+ }
280
+ return {
281
+ id,
282
+ metadata,
283
+ raw: {
284
+ id: raw.id,
285
+ type: raw.type,
286
+ authenticatorAttachment: raw.authenticatorAttachment,
287
+ rawId: Base64.fromBytes(bufferSourceToBytes(raw.rawId), base64UrlOptions),
288
+ response: rawResponse,
289
+ },
290
+ signature: Signature.toHex(signature),
291
+ };
292
+ }
293
+ /**
294
+ * Signs a challenge using a stored WebAuthn P256 Credential. If no Credential is provided,
295
+ * a prompt will be displayed for the user to select an existing Credential
296
+ * that was previously registered.
297
+ *
298
+ * @example
299
+ * ```ts twoslash
300
+ * import { Registration, Authentication } from 'ox/webauthn'
301
+ *
302
+ * const credential = await Registration.create({
303
+ * name: 'Example',
304
+ * })
305
+ *
306
+ * const { metadata, signature } = await Authentication.sign({ // [!code focus]
307
+ * credentialId: credential.id, // [!code focus]
308
+ * challenge: '0xdeadbeef', // [!code focus]
309
+ * }) // [!code focus]
310
+ * // @log: {
311
+ * // @log: metadata: {
312
+ * // @log: authenticatorData: '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
313
+ * // @log: clientDataJSON: '{"type":"webauthn.get","challenge":"9jEFijuhEWrM4SOW-tChJbUEHEP44VcjcJ-Bqo1fTM8","origin":"http://localhost:5173","crossOrigin":false}',
314
+ * // @log: challengeIndex: 23,
315
+ * // @log: typeIndex: 1,
316
+ * // @log: userVerificationRequired: true,
317
+ * // @log: },
318
+ * // @log: signature: { r: 51231...4215n, s: 12345...6789n },
319
+ * // @log: }
320
+ * ```
321
+ *
322
+ * @param options - Options.
323
+ * @returns The signature.
324
+ */
325
+ export async function sign(options) {
326
+ const { getFn = window.navigator.credentials.get.bind(window.navigator.credentials), ...rest } = options;
327
+ const requestOptions = 'publicKey' in rest
328
+ ? rest
329
+ : getOptions(rest);
330
+ try {
331
+ const credential = (await getFn(requestOptions));
332
+ if (!credential)
333
+ throw new SignFailedError();
334
+ const response = credential.response;
335
+ const clientDataJSON = String.fromCharCode(...new Uint8Array(response.clientDataJSON));
336
+ const challengeIndex = clientDataJSON.indexOf('"challenge"');
337
+ const typeIndex = clientDataJSON.indexOf('"type"');
338
+ const signature = internal.parseAsn1Signature(new Uint8Array(response.signature));
339
+ return {
340
+ id: credential.id,
341
+ metadata: {
342
+ authenticatorData: Hex.fromBytes(new Uint8Array(response.authenticatorData)),
343
+ clientDataJSON,
344
+ challengeIndex,
345
+ typeIndex,
346
+ userVerificationRequired: requestOptions.publicKey.userVerification === 'required',
347
+ },
348
+ signature,
349
+ raw: credential,
350
+ };
351
+ }
352
+ catch (error) {
353
+ throw new SignFailedError({
354
+ cause: error,
355
+ });
356
+ }
357
+ }
358
+ /** Thrown when a WebAuthn P256 credential request fails. */
359
+ export class SignFailedError extends Errors.BaseError {
360
+ constructor({ cause } = {}) {
361
+ super('Failed to request credential.', {
362
+ cause,
363
+ });
364
+ Object.defineProperty(this, "name", {
365
+ enumerable: true,
366
+ configurable: true,
367
+ writable: true,
368
+ value: 'Authentication.SignFailedError'
369
+ });
370
+ }
371
+ }
372
+ /**
373
+ * Verifies a signature using the Credential's public key and the challenge which was signed.
374
+ *
375
+ * @example
376
+ * ```ts twoslash
377
+ * import { Registration, Authentication } from 'ox/webauthn'
378
+ *
379
+ * const credential = await Registration.create({
380
+ * name: 'Example',
381
+ * })
382
+ *
383
+ * const { metadata, signature } = await Authentication.sign({
384
+ * credentialId: credential.id,
385
+ * challenge: '0xdeadbeef',
386
+ * })
387
+ *
388
+ * const result = Authentication.verify({ // [!code focus]
389
+ * metadata, // [!code focus]
390
+ * challenge: '0xdeadbeef', // [!code focus]
391
+ * publicKey: credential.publicKey, // [!code focus]
392
+ * signature, // [!code focus]
393
+ * }) // [!code focus]
394
+ * // @log: true
395
+ * ```
396
+ *
397
+ * @param options - Options.
398
+ * @returns Whether the signature is valid.
399
+ */
400
+ export function verify(options) {
401
+ const { challenge, metadata, origin, publicKey, rpId, signature } = options;
402
+ const { authenticatorData, clientDataJSON, userVerificationRequired } = metadata;
403
+ const authenticatorDataBytes = Bytes.fromHex(authenticatorData);
404
+ // Check length of `authenticatorData`.
405
+ if (authenticatorDataBytes.length < 37)
406
+ return false;
407
+ // If rpId is provided, validate the rpIdHash in authenticatorData.
408
+ if (rpId !== undefined) {
409
+ const rpIdHash = authenticatorDataBytes.slice(0, 32);
410
+ const expectedRpIdHash = Hash.sha256(Hex.fromString(rpId), { as: 'Bytes' });
411
+ if (!Bytes.isEqual(rpIdHash, expectedRpIdHash))
412
+ return false;
413
+ }
414
+ const flag = authenticatorDataBytes[32];
415
+ // Verify that the UP bit of the flags in authData is set.
416
+ if ((flag & 0x01) !== 0x01)
417
+ return false;
418
+ // If user verification was determined to be required, verify that
419
+ // the UV bit of the flags in authData is set. Otherwise, ignore the
420
+ // value of the UV flag.
421
+ if (userVerificationRequired && (flag & 0x04) !== 0x04)
422
+ return false;
423
+ // If the BE bit of the flags in authData is not set, verify that
424
+ // the BS bit is not set.
425
+ if ((flag & 0x08) !== 0x08 && (flag & 0x10) === 0x10)
426
+ return false;
427
+ // Parse clientDataJSON for validation.
428
+ const clientData = JSON.parse(clientDataJSON);
429
+ // Verify that response is for an authentication assertion.
430
+ if (clientData.type !== 'webauthn.get')
431
+ return false;
432
+ // Validate the challenge in the clientDataJSON.
433
+ if (!clientData.challenge ||
434
+ Hex.fromBytes(Base64.toBytes(clientData.challenge)) !== challenge)
435
+ return false;
436
+ // If origin is provided, validate origin.
437
+ if (origin !== undefined) {
438
+ const origins = Array.isArray(origin) ? origin : [origin];
439
+ if (!origins.includes(clientData.origin))
440
+ return false;
441
+ }
442
+ const clientDataJSONHash = Hash.sha256(Bytes.fromString(clientDataJSON), {
443
+ as: 'Bytes',
444
+ });
445
+ const payload = Bytes.concat(authenticatorDataBytes, clientDataJSONHash);
446
+ return P256.verify({
447
+ hash: true,
448
+ payload,
449
+ publicKey,
450
+ signature,
451
+ });
452
+ }
453
+ //# sourceMappingURL=Authentication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Authentication.js","sourceRoot":"","sources":["../../webauthn/Authentication.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAC3C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAC3C,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AACvC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAA;AAErC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAA;AACxD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AAEvC,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE5E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,mBAAmB,GACpB,MAAM,qBAAqB,CAAA;AAW5B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA6C;IAE7C,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACtC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAA;IAElC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,GACjE,SAAS,CAAA;IAEX,OAAO;QACL,GAAG,IAAI;QACP,SAAS,EAAE;YACT,GAAG,aAAa;YAChB,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACnC,GAAG,CAAC,gBAAgB,IAAI;gBACtB,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;oBAC3D,GAAG,IAAI;oBACP,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;iBACvB,CAAC,CAAC;aACJ,CAAC;YACF,GAAG,CAAC,UAAU,IAAI;gBAChB,UAAU,EAAE,qBAAqB,CAAC,UAAU,CAAC;aAC9C,CAAC;SACH;KACF,CAAA;AACH,CAAC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAwB;IAC1D,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAA;IAEjD,MAAM,WAAW,GAAgC,EAAE,CAAA;IACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QACrD,WAAW,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAE9D,OAAO;QACL,EAAE;QACF,QAAQ;QACR,GAAG,EAAE;YACH,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,uBAAuB,EAAE,GAAG,CAAC,uBAAuB;YACpD,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpD,QAAQ,EAAE,WAAqD;YAC/D,yBAAyB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;SACtC;QACD,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;KACrC,CAAA;AACH,CAAC;AASD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,UAAU,CACxB,OAA2B;IAE3B,MAAM,EACJ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAC/B,gBAAgB,GAAG,UAAU,GAC9B,GAAG,OAAO,CAAA;IACX,OAAO;QACL,SAAS,EAAE;YACT,GAAG,CAAC,YAAY;gBACd,CAAC,CAAC;oBACE,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;wBAC3C,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;4BACxB,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;4BACtB,IAAI,EAAE,YAAY;yBACnB,CAAC,CAAC;wBACL,CAAC,CAAC;4BACE;gCACE,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;gCAChC,IAAI,EAAE,YAAY;6BACnB;yBACF;iBACN;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACnC,GAAG,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC;YACjC,IAAI;YACJ,gBAAgB;SACjB;KACF,CAAA;AACH,CAAC;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,cAAc,CAC5B,OAA+B;IAE/B,MAAM,EACJ,SAAS,EACT,WAAW,EACX,eAAe,EACf,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,SAAS,EACT,gBAAgB,GAAG,UAAU,GAC9B,GAAG,OAAO,CAAA;IAEX,MAAM,iBAAiB,GAAG,oBAAoB,CAAC;QAC7C,IAAI;QACJ,IAAI;QACJ,SAAS;KACV,CAAC,CAAA;IACF,MAAM,cAAc,GAAG,iBAAiB,CAAC;QACvC,SAAS;QACT,WAAW;QACX,eAAe;QACf,MAAM;KACP,CAAC,CAAA;IACF,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAA;IAEtE,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;IAC5D,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAElD,MAAM,QAAQ,GAAG;QACf,iBAAiB;QACjB,cAAc;QACd,cAAc;QACd,SAAS;QACT,wBAAwB,EAAE,gBAAgB,KAAK,UAAU;KAC1D,CAAA;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAA;IAEjE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;AAC9B,CAAC;AAsCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAuC;IAEvC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACjD,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAA;IAElC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,GACjE,SAAS,CAAA;IAEX,OAAO;QACL,GAAG,IAAI;QACP,SAAS,EAAE;YACT,GAAG,aAAa;YAChB,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;YACxD,GAAG,CAAC,gBAAgB,IAAI;gBACtB,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;oBAC3D,GAAG,IAAI;oBACP,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC;iBAChE,CAAC,CAAC;aACJ,CAAC;YACF,GAAG,CAAC,UAAU,IAAI;gBAChB,UAAU,EAAE,mBAAmB,CAAC,UAAU,CAAC;aAC5C,CAAC;SACH;KACF,CAAA;AACH,CAAC;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAA;IAEjD,MAAM,WAAW,GAAG,EAA4B,CAAA;IAChD,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAI,GAAG,CAAC,QAA+C,CAAC,GAAG,CAAC,CAAA;QACvE,IAAI,KAAK,YAAY,WAAW;YAC9B,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,SAAS,CACjC,IAAI,UAAU,CAAC,KAAK,CAAC,EACrB,gBAAgB,CACjB,CAAA;IACL,CAAC;IAED,OAAO;QACL,EAAE;QACF,QAAQ;QACR,GAAG,EAAE;YACH,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,uBAAuB,EAAE,GAAG,CAAC,uBAAuB;YACpD,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;YACzE,QAAQ,EAAE,WAA2D;SACtE;QACD,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC;KACtC,CAAA;AACH,CAAC;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAqB;IAC9C,MAAM,EACJ,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAC3E,GAAG,IAAI,EACR,GAAG,OAAO,CAAA;IACX,MAAM,cAAc,GAClB,WAAW,IAAI,IAAI;QACjB,CAAC,CAAE,IAAuC;QAC1C,CAAC,CAAC,UAAU,CAAC,IAAa,CAAC,CAAA;IAC/B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,CAAC,MAAM,KAAK,CAC7B,cAAuB,CACxB,CAA8B,CAAA;QAC/B,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,eAAe,EAAE,CAAA;QAC5C,MAAM,QAAQ,GAAG,UAAU,CAAC,QAA0C,CAAA;QAEtE,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CACxC,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,CAC3C,CAAA;QACD,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;QAC5D,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAElD,MAAM,SAAS,GAAG,QAAQ,CAAC,kBAAkB,CAC3C,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CACnC,CAAA;QAED,OAAO;YACL,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,QAAQ,EAAE;gBACR,iBAAiB,EAAE,GAAG,CAAC,SAAS,CAC9B,IAAI,UAAU,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAC3C;gBACD,cAAc;gBACd,cAAc;gBACd,SAAS;gBACT,wBAAwB,EACtB,cAAc,CAAC,SAAU,CAAC,gBAAgB,KAAK,UAAU;aAC5D;YACD,SAAS;YACT,GAAG,EAAE,UAAU;SAChB,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC;YACxB,KAAK,EAAE,KAAc;SACtB,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AA4BD,4DAA4D;AAC5D,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,SAAgB;IAG1D,YAAY,EAAE,KAAK,KAAoC,EAAE;QACvD,KAAK,CAAC,+BAA+B,EAAE;YACrC,KAAK;SACN,CAAC,CAAA;QALc;;;;mBAAO,gCAAgC;WAAA;IAMzD,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,MAAM,CAAC,OAAuB;IAC5C,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAC3E,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,wBAAwB,EAAE,GACnE,QAAQ,CAAA;IAEV,MAAM,sBAAsB,GAAG,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAE/D,uCAAuC;IACvC,IAAI,sBAAsB,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,KAAK,CAAA;IAEpD,mEAAmE;IACnE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;QAC3E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,gBAAgB,CAAC;YAAE,OAAO,KAAK,CAAA;IAC9D,CAAC;IAED,MAAM,IAAI,GAAG,sBAAsB,CAAC,EAAE,CAAE,CAAA;IAExC,0DAA0D;IAC1D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAExC,kEAAkE;IAClE,oEAAoE;IACpE,wBAAwB;IACxB,IAAI,wBAAwB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAEpE,iEAAiE;IACjE,yBAAyB;IACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAElE,uCAAuC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;IAE7C,2DAA2D;IAC3D,IAAI,UAAU,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,KAAK,CAAA;IAEpD,gDAAgD;IAChD,IACE,CAAC,UAAU,CAAC,SAAS;QACrB,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,SAAS;QAEjE,OAAO,KAAK,CAAA;IAEd,0CAA0C;IAC1C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QACzD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;IACxD,CAAC;IAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;QACvE,EAAE,EAAE,OAAO;KACZ,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,CAAA;IAExE,OAAO,IAAI,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,IAAI;QACV,OAAO;QACP,SAAS;QACT,SAAS;KACV,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,176 @@
1
+ import * as Base64 from '../core/Base64.js';
2
+ import * as Bytes from '../core/Bytes.js';
3
+ import * as Cbor from '../core/Cbor.js';
4
+ import * as CoseKey from '../core/CoseKey.js';
5
+ import * as Hash from '../core/Hash.js';
6
+ import * as Hex from '../core/Hex.js';
7
+ /**
8
+ * Gets the authenticator data which contains information about the
9
+ * processing of an authenticator request (ie. from `Authentication.sign`).
10
+ *
11
+ * :::warning
12
+ *
13
+ * This function is mainly for testing purposes or for manually constructing
14
+ * autenticator data. In most cases you will not need this function.
15
+ * `authenticatorData` is typically returned as part of the
16
+ * authenticator response.
17
+ *
18
+ * :::
19
+ *
20
+ * @example
21
+ * ```ts twoslash
22
+ * import { Authenticator } from 'ox/webauthn'
23
+ *
24
+ * const authenticatorData = Authenticator.getAuthenticatorData({
25
+ * rpId: 'example.com',
26
+ * signCount: 420,
27
+ * })
28
+ * // @log: "0xa379a6f6eeafb9a55e378c118034e2751e682fab9f2d30ab13d2125586ce194705000001a4"
29
+ * ```
30
+ *
31
+ * @example
32
+ * ### With Attested Credential Data
33
+ *
34
+ * Include a credential ID and public key in the authenticator data (for registration responses):
35
+ *
36
+ * ```ts twoslash
37
+ * import { P256 } from 'ox'
38
+ * import { Authenticator } from 'ox/webauthn'
39
+ *
40
+ * const { publicKey } = P256.createKeyPair()
41
+ *
42
+ * const authenticatorData = Authenticator.getAuthenticatorData({
43
+ * rpId: 'example.com',
44
+ * flag: 0x41, // UP + AT
45
+ * credential: {
46
+ * id: new Uint8Array(32),
47
+ * publicKey,
48
+ * },
49
+ * })
50
+ * ```
51
+ *
52
+ * @param options - Options to construct the authenticator data.
53
+ * @returns The authenticator data.
54
+ */
55
+ export function getAuthenticatorData(options = {}) {
56
+ const { credential, flag = 5, rpId = window.location.hostname, signCount = 0, } = options;
57
+ const rpIdHash = Hash.sha256(Hex.fromString(rpId));
58
+ const flag_bytes = Hex.fromNumber(flag, { size: 1 });
59
+ const signCount_bytes = Hex.fromNumber(signCount, { size: 4 });
60
+ const base = Hex.concat(rpIdHash, flag_bytes, signCount_bytes);
61
+ if (!credential)
62
+ return base;
63
+ // AAGUID (16 bytes of zeros)
64
+ const aaguid = Hex.fromBytes(new Uint8Array(16));
65
+ // Credential ID
66
+ const credentialId = Hex.fromBytes(credential.id);
67
+ const credIdLen = Hex.fromNumber(credential.id.length, { size: 2 });
68
+ // COSE public key
69
+ const coseKey = CoseKey.fromPublicKey(credential.publicKey);
70
+ return Hex.concat(base, aaguid, credIdLen, credentialId, coseKey);
71
+ }
72
+ /**
73
+ * Extracts the signature counter from the authenticator data.
74
+ * The counter is a 4-byte big-endian unsigned integer at bytes 33–36.
75
+ *
76
+ * Useful for detecting cloned authenticators: if the counter is non-zero and
77
+ * does not monotonically increase between assertions, it may indicate a cloned key.
78
+ *
79
+ * @example
80
+ * ```ts twoslash
81
+ * import { Authenticator } from 'ox/webauthn'
82
+ *
83
+ * const signCount = Authenticator.getSignCount(
84
+ * '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000001',
85
+ * )
86
+ * // @log: 1
87
+ * ```
88
+ *
89
+ * @param authenticatorData - The authenticator data hex string.
90
+ * @returns The signature counter.
91
+ */
92
+ export function getSignCount(authenticatorData) {
93
+ const bytes = Bytes.fromHex(authenticatorData);
94
+ if (bytes.length < 37)
95
+ return 0;
96
+ return (((bytes[33] << 24) |
97
+ (bytes[34] << 16) |
98
+ (bytes[35] << 8) |
99
+ bytes[36]) >>>
100
+ 0);
101
+ }
102
+ /**
103
+ * Constructs the Client Data in stringified JSON format which represents client data that
104
+ * was passed to `credentials.get()` or `credentials.create()`.
105
+ *
106
+ * :::warning
107
+ *
108
+ * This function is mainly for testing purposes or for manually constructing
109
+ * client data. In most cases you will not need this function.
110
+ * `clientDataJSON` is typically returned as part of the authenticator response.
111
+ *
112
+ * :::
113
+ *
114
+ * @example
115
+ * ```ts twoslash
116
+ * import { Authenticator } from 'ox/webauthn'
117
+ *
118
+ * const clientDataJSON = Authenticator.getClientDataJSON({
119
+ * challenge: '0xdeadbeef',
120
+ * origin: 'https://example.com',
121
+ * })
122
+ * // @log: "{"type":"webauthn.get","challenge":"3q2-7w","origin":"https://example.com","crossOrigin":false}"
123
+ * ```
124
+ *
125
+ * @param options - Options to construct the client data.
126
+ * @returns The client data.
127
+ */
128
+ export function getClientDataJSON(options) {
129
+ const { challenge, crossOrigin = false, extraClientData, origin = window.location.origin, type = 'webauthn.get', } = options;
130
+ return JSON.stringify({
131
+ type,
132
+ challenge: Base64.fromHex(challenge, { url: true, pad: false }),
133
+ origin,
134
+ crossOrigin,
135
+ ...extraClientData,
136
+ });
137
+ }
138
+ /**
139
+ * Constructs a CBOR-encoded attestation object for testing WebAuthn registration
140
+ * verification. Combines the authenticator data with an attestation statement.
141
+ *
142
+ * :::warning
143
+ *
144
+ * This function is mainly for testing purposes. In production, the attestation
145
+ * object is returned by the authenticator during `navigator.credentials.create()`.
146
+ *
147
+ * :::
148
+ *
149
+ * @example
150
+ * ```ts twoslash
151
+ * import { P256 } from 'ox'
152
+ * import { Authenticator } from 'ox/webauthn'
153
+ *
154
+ * const { publicKey } = P256.createKeyPair()
155
+ *
156
+ * const attestationObject = Authenticator.getAttestationObject({
157
+ * authData: Authenticator.getAuthenticatorData({
158
+ * rpId: 'example.com',
159
+ * flag: 0x41,
160
+ * credential: { id: new Uint8Array(32), publicKey },
161
+ * }),
162
+ * })
163
+ * ```
164
+ *
165
+ * @param options - Options to construct the attestation object.
166
+ * @returns The CBOR-encoded attestation object as a Hex string.
167
+ */
168
+ export function getAttestationObject(options) {
169
+ const { attStmt = {}, authData, fmt = 'none' } = options;
170
+ return Cbor.encode({
171
+ fmt,
172
+ attStmt,
173
+ authData: Hex.toBytes(authData),
174
+ });
175
+ }
176
+ //# sourceMappingURL=Authenticator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Authenticator.js","sourceRoot":"","sources":["../../webauthn/Authenticator.ts"],"names":[],"mappings":"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"}