nid-webauthn-emulator 0.2.13 → 0.2.14

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.
package/README.ja.md CHANGED
@@ -94,6 +94,12 @@ const authenticatorResponse = unpackMakeCredentialResponse(this.authenticator.co
94
94
 
95
95
  WebAuthn の著名なデモサイトである [webauthn.io](https://webauthn.io/) での使用例を示します。[統合テスト](spec/integration/integration.spec.ts) に実際にうごくテストコード例があります。
96
96
 
97
+ webauthn.io の統合テストは外部サイトに依存するため、通常の `pnpm test` ではスキップされます。このテストだけを実行する場合は、下記のコマンドを利用してください。
98
+
99
+ ```sh
100
+ pnpm test:webauthn-io
101
+ ```
102
+
97
103
  ```TypeScript
98
104
  // Origin および WebAuthn API エミュレータを初期化します
99
105
  // ここでは、https://webauthn.io を Origin として利用します
@@ -203,7 +209,7 @@ await page.evaluate(BrowserInjection.HookWebAuthnApis);
203
209
 
204
210
  ## ユニットテストでの WebAuthn API フック
205
211
 
206
- Vitest/Jest などで WebAuthn API を差し替えたい場合は、`src/test-utils/unit-test.ts` の `createPasskeysEmulator` を使うと `PublicKeyCredential` / `navigator.credentials` を簡単にモックできます。
212
+ ユニットテストで WebAuthn API を差し替えたい場合は、`src/test-utils/unit-test.ts` の `createPasskeysEmulator` を使うと `PublicKeyCredential` / `navigator.credentials` を簡単にモックできます。
207
213
 
208
214
  ```TypeScript
209
215
  import { createPasskeysEmulator } from "nid-webauthn-emulator";
package/README.md CHANGED
@@ -95,6 +95,12 @@ const authenticatorResponse = unpackMakeCredentialResponse(this.authenticator.co
95
95
 
96
96
  Here's an example of usage with [webauthn.io](https://webauthn.io/), a well-known WebAuthn demo site. You can find working test code examples in the [integration tests](spec/integration/integration.spec.ts).
97
97
 
98
+ The webauthn.io integration test is skipped by the default `pnpm test` command because it depends on an external site. To run only that test, use:
99
+
100
+ ```sh
101
+ pnpm test:webauthn-io
102
+ ```
103
+
98
104
  ```TypeScript
99
105
  // Initialize the Origin and WebAuthn API emulator
100
106
  // Here we use https://webauthn.io as the Origin
@@ -212,7 +218,7 @@ This ensures that the `WebAuthnEmulator` methods defined earlier with `exposeFun
212
218
 
213
219
  ## Hooking WebAuthn APIs in Unit Tests
214
220
 
215
- If you want to swap out WebAuthn APIs in Vitest/Jest, you can mock `PublicKeyCredential` / `navigator.credentials` using `createPasskeysEmulator` from `src/test-utils/unit-test.ts`.
221
+ If you want to swap out WebAuthn APIs in unit tests, you can mock `PublicKeyCredential` / `navigator.credentials` using `createPasskeysEmulator` from `src/test-utils/unit-test.ts`.
216
222
 
217
223
  ```TypeScript
218
224
  import { createPasskeysEmulator } from "nid-webauthn-emulator";
@@ -3,24 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const globals_1 = require("@jest/globals");
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
7
8
  const src_1 = require("../../src");
8
9
  const ctap_model_1 = require("../../src/authenticator/ctap-model");
9
10
  const encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
10
11
  const credentials_memory_repository_1 = require("../../src/repository/credentials-memory-repository");
11
- (0, globals_1.describe)("Authenticator Emulator Exceptional Test", () => {
12
+ (0, node_test_1.describe)("Authenticator Emulator Exceptional Test", () => {
12
13
  // Success case has been tested in the webauthn-emulator.spec.ts
13
- (0, globals_1.test)("Unknown command _ CTAP Error", async () => {
14
+ (0, node_test_1.test)("Unknown command _ CTAP Error", async () => {
14
15
  const testRequest = {
15
16
  command: ctap_model_1.CTAP_COMMAND.authenticatorReset,
16
17
  };
17
18
  const authenticator = new src_1.AuthenticatorEmulator();
18
- (0, globals_1.expect)(() => {
19
+ strict_1.default.throws(() => {
19
20
  authenticator.command(testRequest);
20
- }).toThrow("CTAP error: CTAP1_ERR_INVALID_COMMAND (1)");
21
+ }, { message: "CTAP error: CTAP1_ERR_INVALID_COMMAND (1)" });
21
22
  });
22
23
  });
23
- (0, globals_1.describe)("Authenticator Credential Management Tests", () => {
24
+ (0, node_test_1.describe)("Authenticator Credential Management Tests", () => {
24
25
  let authenticator;
25
26
  let repository;
26
27
  // Test data
@@ -41,7 +42,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
41
42
  name: "user3",
42
43
  displayName: "User Three",
43
44
  };
44
- (0, globals_1.beforeEach)(() => {
45
+ (0, node_test_1.beforeEach)(() => {
45
46
  // Create a new repository for each test
46
47
  repository = new credentials_memory_repository_1.PasskeysCredentialsMemoryRepository();
47
48
  // Create authenticator with the repository
@@ -64,8 +65,8 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
64
65
  };
65
66
  authenticator.authenticatorMakeCredential(makeCredentialRequest);
66
67
  }
67
- (0, globals_1.describe)("enumerateCredentialsBegin", () => {
68
- (0, globals_1.test)("should return the total number of credentials for a specific RP", () => {
68
+ (0, node_test_1.describe)("enumerateCredentialsBegin", () => {
69
+ (0, node_test_1.test)("should return the total number of credentials for a specific RP", () => {
69
70
  // Create request for enumerateCredentialsBegin
70
71
  const request = {
71
72
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
@@ -76,19 +77,19 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
76
77
  // Execute the command
77
78
  const response = authenticator.authenticatorCredentialManagement(request);
78
79
  // Verify the response
79
- (0, globals_1.expect)(response.totalCredentials).toBe(2); // We created 2 credentials for rpId1
80
+ strict_1.default.equal(response.totalCredentials, 2); // We created 2 credentials for rpId1
80
81
  });
81
- (0, globals_1.test)("should throw an error if rpId is not provided", () => {
82
+ (0, node_test_1.test)("should throw an error if rpId is not provided", () => {
82
83
  // Create request without rpId
83
84
  const request = {
84
85
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
85
86
  };
86
87
  // Execute the command and expect an error
87
- (0, globals_1.expect)(() => {
88
+ strict_1.default.throws(() => {
88
89
  authenticator.authenticatorCredentialManagement(request);
89
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
90
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
90
91
  });
91
- (0, globals_1.test)("should return 0 credentials for an RP with no credentials", () => {
92
+ (0, node_test_1.test)("should return 0 credentials for an RP with no credentials", () => {
92
93
  // Create request for a non-existent RP
93
94
  const request = {
94
95
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
@@ -99,11 +100,11 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
99
100
  // Execute the command
100
101
  const response = authenticator.authenticatorCredentialManagement(request);
101
102
  // Verify the response
102
- (0, globals_1.expect)(response.totalCredentials).toBe(0);
103
+ strict_1.default.equal(response.totalCredentials, 0);
103
104
  });
104
105
  });
105
- (0, globals_1.describe)("enumerateCredentialsGetNextCredential", () => {
106
- (0, globals_1.test)("should return credentials one by one", () => {
106
+ (0, node_test_1.describe)("enumerateCredentialsGetNextCredential", () => {
107
+ (0, node_test_1.test)("should return credentials one by one", () => {
107
108
  // First, call enumerateCredentialsBegin
108
109
  const beginRequest = {
109
110
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
@@ -118,34 +119,34 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
118
119
  };
119
120
  // Get first credential
120
121
  const response1 = authenticator.authenticatorCredentialManagement(getNextRequest);
121
- (0, globals_1.expect)(response1.user).toBeDefined();
122
- (0, globals_1.expect)(response1.credentialID).toBeDefined();
123
- (0, globals_1.expect)(response1.publicKey).toBeDefined();
122
+ strict_1.default.notEqual(response1.user, undefined);
123
+ strict_1.default.notEqual(response1.credentialID, undefined);
124
+ strict_1.default.notEqual(response1.publicKey, undefined);
124
125
  // Get second credential
125
126
  const response2 = authenticator.authenticatorCredentialManagement(getNextRequest);
126
- (0, globals_1.expect)(response2.user).toBeDefined();
127
- (0, globals_1.expect)(response2.credentialID).toBeDefined();
128
- (0, globals_1.expect)(response2.publicKey).toBeDefined();
127
+ strict_1.default.notEqual(response2.user, undefined);
128
+ strict_1.default.notEqual(response2.credentialID, undefined);
129
+ strict_1.default.notEqual(response2.publicKey, undefined);
129
130
  // Verify we got different credentials
130
131
  if (response1.credentialID && response2.credentialID) {
131
- (0, globals_1.expect)(encode_utils_1.default.encodeBase64Url(response1.credentialID)).not.toBe(encode_utils_1.default.encodeBase64Url(response2.credentialID));
132
+ strict_1.default.notEqual(encode_utils_1.default.encodeBase64Url(response1.credentialID), encode_utils_1.default.encodeBase64Url(response2.credentialID));
132
133
  }
133
134
  // Verify we can't get more credentials
134
- (0, globals_1.expect)(() => {
135
+ strict_1.default.throws(() => {
135
136
  authenticator.authenticatorCredentialManagement(getNextRequest);
136
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
137
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
137
138
  });
138
- (0, globals_1.test)("should throw an error if called without calling enumerateCredentialsBegin first", () => {
139
+ (0, node_test_1.test)("should throw an error if called without calling enumerateCredentialsBegin first", () => {
139
140
  const getNextRequest = {
140
141
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
141
142
  };
142
- (0, globals_1.expect)(() => {
143
+ strict_1.default.throws(() => {
143
144
  authenticator.authenticatorCredentialManagement(getNextRequest);
144
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
145
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
145
146
  });
146
147
  });
147
- (0, globals_1.describe)("updateUserInformation", () => {
148
- (0, globals_1.test)("should update user information for all credentials of a user", () => {
148
+ (0, node_test_1.describe)("updateUserInformation", () => {
149
+ (0, node_test_1.test)("should update user information for all credentials of a user", () => {
149
150
  // Create updated user information
150
151
  const updatedUser = {
151
152
  id: user1.id, // Same ID
@@ -178,33 +179,33 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
178
179
  // Find the credential for user1
179
180
  if (nextResponse.user &&
180
181
  encode_utils_1.default.encodeBase64Url(nextResponse.user.id) === encode_utils_1.default.encodeBase64Url(user1.id)) {
181
- (0, globals_1.expect)(nextResponse.user.name).toBe(updatedUser.name);
182
- (0, globals_1.expect)(nextResponse.user.displayName).toBe(updatedUser.displayName);
182
+ strict_1.default.equal(nextResponse.user.name, updatedUser.name);
183
+ strict_1.default.equal(nextResponse.user.displayName, updatedUser.displayName);
183
184
  }
184
185
  });
185
- (0, globals_1.test)("should throw an error if rpId is not provided", () => {
186
+ (0, node_test_1.test)("should throw an error if rpId is not provided", () => {
186
187
  const request = {
187
188
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
188
189
  subCommandParams: {
189
190
  user: user1,
190
191
  },
191
192
  };
192
- (0, globals_1.expect)(() => {
193
+ strict_1.default.throws(() => {
193
194
  authenticator.authenticatorCredentialManagement(request);
194
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
195
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
195
196
  });
196
- (0, globals_1.test)("should throw an error if user is not provided", () => {
197
+ (0, node_test_1.test)("should throw an error if user is not provided", () => {
197
198
  const request = {
198
199
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
199
200
  subCommandParams: {
200
201
  rpId: rpId1,
201
202
  },
202
203
  };
203
- (0, globals_1.expect)(() => {
204
+ strict_1.default.throws(() => {
204
205
  authenticator.authenticatorCredentialManagement(request);
205
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
206
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
206
207
  });
207
- (0, globals_1.test)("should throw an error if no credentials exist for the user", () => {
208
+ (0, node_test_1.test)("should throw an error if no credentials exist for the user", () => {
208
209
  const nonExistentUser = {
209
210
  id: encode_utils_1.default.strToUint8Array("nonexistent-id"),
210
211
  name: "nonexistent",
@@ -217,13 +218,13 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
217
218
  user: nonExistentUser,
218
219
  },
219
220
  };
220
- (0, globals_1.expect)(() => {
221
+ strict_1.default.throws(() => {
221
222
  authenticator.authenticatorCredentialManagement(request);
222
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
223
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
223
224
  });
224
225
  });
225
- (0, globals_1.describe)("authenticatorCredentialManagement with stateless authenticator", () => {
226
- (0, globals_1.test)("should throw an error if authenticator is stateless", () => {
226
+ (0, node_test_1.describe)("authenticatorCredentialManagement with stateless authenticator", () => {
227
+ (0, node_test_1.test)("should throw an error if authenticator is stateless", () => {
227
228
  // Create a stateless authenticator
228
229
  const statelessAuthenticator = new src_1.AuthenticatorEmulator({
229
230
  stateless: true,
@@ -236,76 +237,76 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
236
237
  },
237
238
  };
238
239
  // Execute the command and expect an error
239
- (0, globals_1.expect)(() => {
240
+ strict_1.default.throws(() => {
240
241
  statelessAuthenticator.authenticatorCredentialManagement(request);
241
- }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
242
+ }, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
242
243
  });
243
244
  });
244
- (0, globals_1.describe)("Authenticator Credential Management additional error coverage", () => {
245
- (0, globals_1.test)("dispatch default branch throws invalid command", () => {
245
+ (0, node_test_1.describe)("Authenticator Credential Management additional error coverage", () => {
246
+ (0, node_test_1.test)("dispatch default branch throws invalid command", () => {
246
247
  const authenticator = new src_1.AuthenticatorEmulator();
247
248
  // Build a CTAP request with an unknown subCommand to hit default branch
248
249
  const data = encode_utils_1.default.encodeCbor({ "1": -1 });
249
- (0, globals_1.expect)(() => authenticator.command({ command: ctap_model_1.CTAP_COMMAND.authenticatorCredentialManagement, data })).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_COMMAND));
250
+ strict_1.default.throws(() => authenticator.command({ command: ctap_model_1.CTAP_COMMAND.authenticatorCredentialManagement, data }), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_COMMAND));
250
251
  });
251
- (0, globals_1.test)("enumerateCredentialsBegin without repository throws not allowed", () => {
252
+ (0, node_test_1.test)("enumerateCredentialsBegin without repository throws not allowed", () => {
252
253
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
253
254
  const req = (0, ctap_model_1.packCredentialManagementRequest)({
254
255
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
255
256
  subCommandParams: { rpId: "example.com" },
256
257
  });
257
- (0, globals_1.expect)(() => authenticator.command(req)).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
258
+ strict_1.default.throws(() => authenticator.command(req), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
258
259
  });
259
- (0, globals_1.test)("updateUserInformation without repository throws not allowed", () => {
260
+ (0, node_test_1.test)("updateUserInformation without repository throws not allowed", () => {
260
261
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
261
262
  const req = (0, ctap_model_1.packCredentialManagementRequest)({
262
263
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
263
264
  subCommandParams: { rpId: "example.com", user: { id: new Uint8Array([1]), name: "n", displayName: "d" } },
264
265
  });
265
- (0, globals_1.expect)(() => authenticator.command(req)).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
266
+ strict_1.default.throws(() => authenticator.command(req), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
266
267
  });
267
- (0, globals_1.test)("deleteCredential without repository throws not allowed", () => {
268
+ (0, node_test_1.test)("deleteCredential without repository throws not allowed", () => {
268
269
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
269
270
  const req = (0, ctap_model_1.packCredentialManagementRequest)({ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.deleteCredential });
270
- (0, globals_1.expect)(() => authenticator.command(req)).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
271
+ strict_1.default.throws(() => authenticator.command(req), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
271
272
  });
272
- (0, globals_1.test)("deleteCredential without credentialId throws invalid parameter", () => {
273
+ (0, node_test_1.test)("deleteCredential without credentialId throws invalid parameter", () => {
273
274
  const authenticator = new src_1.AuthenticatorEmulator();
274
275
  const req = (0, ctap_model_1.packCredentialManagementRequest)({ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.deleteCredential });
275
- (0, globals_1.expect)(() => authenticator.command(req)).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
276
+ strict_1.default.throws(() => authenticator.command(req), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
276
277
  });
277
- (0, globals_1.test)("deleteCredential for non-existent id throws no credentials", () => {
278
+ (0, node_test_1.test)("deleteCredential for non-existent id throws no credentials", () => {
278
279
  const authenticator = new src_1.AuthenticatorEmulator();
279
280
  const credentialId = encode_utils_1.default.strToUint8Array("non-existent-id");
280
281
  const req = (0, ctap_model_1.packCredentialManagementRequest)({
281
282
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.deleteCredential,
282
283
  subCommandParams: { credentialId },
283
284
  });
284
- (0, globals_1.expect)(() => authenticator.command(req)).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
285
+ strict_1.default.throws(() => authenticator.command(req), new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
285
286
  });
286
- (0, globals_1.test)("private enumerateCredentialsBegin guard throws not allowed when repository missing", () => {
287
+ (0, node_test_1.test)("private enumerateCredentialsBegin guard throws not allowed when repository missing", () => {
287
288
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
288
289
  const target = authenticator.authenticatorEnumerateCredentialsBegin.bind(authenticator);
289
290
  const call = () => target({
290
291
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
291
292
  subCommandParams: { rpId: "x" },
292
293
  });
293
- (0, globals_1.expect)(call).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
294
+ strict_1.default.throws(call, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
294
295
  });
295
- (0, globals_1.test)("private updateUserInformation guard throws not allowed when repository missing", () => {
296
+ (0, node_test_1.test)("private updateUserInformation guard throws not allowed when repository missing", () => {
296
297
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
297
298
  const target = authenticator.authenticatorUpdateUserInformation.bind(authenticator);
298
299
  const call = () => target({
299
300
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
300
301
  subCommandParams: { rpId: "x", user: { id: new Uint8Array([1]), name: "n", displayName: "d" } },
301
302
  });
302
- (0, globals_1.expect)(call).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
303
+ strict_1.default.throws(call, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
303
304
  });
304
- (0, globals_1.test)("private deleteCredential guard throws not allowed when repository missing", () => {
305
+ (0, node_test_1.test)("private deleteCredential guard throws not allowed when repository missing", () => {
305
306
  const authenticator = new src_1.AuthenticatorEmulator({ stateless: true });
306
307
  const target = authenticator.authenticatorDeleteCredential.bind(authenticator);
307
308
  const call = () => target({ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.deleteCredential });
308
- (0, globals_1.expect)(call).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
309
+ strict_1.default.throws(call, new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
309
310
  });
310
311
  });
311
312
  });
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const globals_1 = require("@jest/globals");
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
4
8
  const ctap_model_1 = require("../../src/authenticator/ctap-model");
5
- (0, globals_1.describe)("CTAP Model Test", () => {
6
- (0, globals_1.test)("MakeCredentialRequest CTAP Object pack and unpack", async () => {
9
+ (0, node_test_1.describe)("CTAP Model Test", () => {
10
+ (0, node_test_1.test)("MakeCredentialRequest CTAP Object pack and unpack", async () => {
7
11
  const testRequest = {
8
12
  clientDataHash: new Uint8Array([99, 104, 97, 108, 108, 101, 110, 103, 101]),
9
13
  rp: { name: "webauthn.io", id: "webauthn.io" },
@@ -18,10 +22,10 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
18
22
  const packed = (0, ctap_model_1.packMakeCredentialRequest)(testRequest);
19
23
  const unpacked = (0, ctap_model_1.unpackRequest)(packed);
20
24
  const rePacked = (0, ctap_model_1.packMakeCredentialRequest)(unpacked.request);
21
- (0, globals_1.expect)(packed).toEqual(rePacked);
22
- (0, globals_1.expect)(unpacked.request).toEqual(testRequest);
25
+ strict_1.default.deepEqual(packed, rePacked);
26
+ strict_1.default.deepEqual(unpacked.request, testRequest);
23
27
  });
24
- (0, globals_1.test)("GetAssertionRequest CTAP Object pack and unpack", async () => {
28
+ (0, node_test_1.test)("GetAssertionRequest CTAP Object pack and unpack", async () => {
25
29
  const testRequest = {
26
30
  rpId: "webauthn.io",
27
31
  clientDataHash: new Uint8Array([99, 104, 97, 108, 108, 101, 110, 103, 101]),
@@ -34,10 +38,10 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
34
38
  const packed = (0, ctap_model_1.packGetAssertionRequest)(testRequest);
35
39
  const unpacked = (0, ctap_model_1.unpackRequest)(packed);
36
40
  const rePacked = (0, ctap_model_1.packGetAssertionRequest)(unpacked.request);
37
- (0, globals_1.expect)(packed).toEqual(rePacked);
38
- (0, globals_1.expect)(unpacked.request).toEqual(testRequest);
41
+ strict_1.default.deepEqual(packed, rePacked);
42
+ strict_1.default.deepEqual(unpacked.request, testRequest);
39
43
  });
40
- (0, globals_1.test)("MakeCredentialResponse CTAP Object pack and unpack", async () => {
44
+ (0, node_test_1.test)("MakeCredentialResponse CTAP Object pack and unpack", async () => {
41
45
  const testResponse = {
42
46
  fmt: "none",
43
47
  attStmt: {},
@@ -46,11 +50,12 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
46
50
  const packed = (0, ctap_model_1.packMakeCredentialResponse)(testResponse);
47
51
  const unpacked = (0, ctap_model_1.unpackMakeCredentialResponse)(packed);
48
52
  const rePacked = (0, ctap_model_1.packMakeCredentialResponse)(unpacked);
49
- (0, globals_1.expect)(packed).toEqual(rePacked);
50
- (0, globals_1.expect)(unpacked).toEqual(testResponse);
53
+ strict_1.default.deepEqual(packed, rePacked);
54
+ strict_1.default.deepEqual(unpacked, testResponse);
51
55
  });
52
- (0, globals_1.test)("GetAssertionResponse CTAP Object pack and unpack", async () => {
56
+ (0, node_test_1.test)("GetAssertionResponse CTAP Object pack and unpack", async () => {
53
57
  const testResponse = {
58
+ credential: undefined,
54
59
  authData: new Uint8Array([97, 117, 116, 104, 68, 97, 116, 97]),
55
60
  signature: new Uint8Array([115, 105, 103]),
56
61
  user: { id: new Uint8Array([116, 101, 115, 116, 45, 117, 115, 101, 114]), name: "user", displayName: "user" },
@@ -59,10 +64,10 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
59
64
  const packed = (0, ctap_model_1.packGetAssertionResponse)(testResponse);
60
65
  const unpacked = (0, ctap_model_1.unpackGetAssertionResponse)(packed);
61
66
  const rePacked = (0, ctap_model_1.packGetAssertionResponse)(unpacked);
62
- (0, globals_1.expect)(packed).toEqual(rePacked);
63
- (0, globals_1.expect)(unpacked).toEqual(testResponse);
67
+ strict_1.default.deepEqual(packed, rePacked);
68
+ strict_1.default.deepEqual(unpacked, testResponse);
64
69
  });
65
- (0, globals_1.test)("GetInfoResponse CTAP Object pack and unpack", async () => {
70
+ (0, node_test_1.test)("GetInfoResponse CTAP Object pack and unpack", async () => {
66
71
  const testResponse = {
67
72
  versions: ["U2F_V2"],
68
73
  extensions: ["credProtect"],
@@ -74,48 +79,48 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
74
79
  const packed = (0, ctap_model_1.packGetInfoResponse)(testResponse);
75
80
  const unpacked = (0, ctap_model_1.unpackGetInfoResponse)(packed);
76
81
  const rePacked = (0, ctap_model_1.packGetInfoResponse)(unpacked);
77
- (0, globals_1.expect)(packed).toEqual(rePacked);
78
- (0, globals_1.expect)(unpacked).toEqual(testResponse);
82
+ strict_1.default.deepEqual(packed, rePacked);
83
+ strict_1.default.deepEqual(unpacked, testResponse);
79
84
  });
80
- (0, globals_1.test)("Illegal data parse test _ failed to unpack", async () => {
85
+ (0, node_test_1.test)("Illegal data parse test _ failed to unpack", async () => {
81
86
  const response = {};
82
87
  const expected = "CTAP error: CTAP2_ERR_INVALID_CBOR (18)";
83
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackMakeCredentialResponse)(response)).toThrow(expected);
84
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackGetAssertionResponse)(response)).toThrow(expected);
85
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackGetInfoResponse)(response)).toThrow(expected);
88
+ strict_1.default.throws(() => (0, ctap_model_1.unpackMakeCredentialResponse)(response), { message: expected });
89
+ strict_1.default.throws(() => (0, ctap_model_1.unpackGetAssertionResponse)(response), { message: expected });
90
+ strict_1.default.throws(() => (0, ctap_model_1.unpackGetInfoResponse)(response), { message: expected });
86
91
  });
87
- (0, globals_1.test)("Illegal cbor data parse test _ failed to unpack", async () => {
92
+ (0, node_test_1.test)("Illegal cbor data parse test _ failed to unpack", async () => {
88
93
  const request = {
89
94
  command: ctap_model_1.CTAP_COMMAND.authenticatorMakeCredential,
90
95
  data: new Uint8Array([1, 2, 3, 4, 5]),
91
96
  };
92
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackRequest)(request)).toThrow("CTAP error: CTAP2_ERR_INVALID_CBOR (18)");
97
+ strict_1.default.throws(() => (0, ctap_model_1.unpackRequest)(request), { message: "CTAP error: CTAP2_ERR_INVALID_CBOR (18)" });
93
98
  });
94
- (0, globals_1.test)("unpackRequest default branch returns undefined request for unhandled command", () => {
99
+ (0, node_test_1.test)("unpackRequest default branch returns undefined request for unhandled command", () => {
95
100
  const req = { command: ctap_model_1.CTAP_COMMAND.authenticatorClientPIN }; // not explicitly handled in switch
96
101
  const unpacked = (0, ctap_model_1.unpackRequest)(req);
97
- (0, globals_1.expect)(unpacked.command).toBe(ctap_model_1.CTAP_COMMAND.authenticatorClientPIN);
98
- (0, globals_1.expect)(unpacked.request).toBeUndefined();
102
+ strict_1.default.equal(unpacked.command, ctap_model_1.CTAP_COMMAND.authenticatorClientPIN);
103
+ strict_1.default.equal(unpacked.request, undefined);
99
104
  });
100
- (0, globals_1.test)("credential management request with undefined optional params round-trips", () => {
105
+ (0, node_test_1.test)("credential management request with undefined optional params round-trips", () => {
101
106
  const packed = (0, ctap_model_1.packCredentialManagementRequest)({
102
107
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
103
108
  // subCommandParams and pinUvAuth* omitted intentionally
104
109
  });
105
110
  const unpacked = (0, ctap_model_1.unpackCredentialManagementRequest)(packed);
106
- (0, globals_1.expect)(unpacked.subCommand).toBe(ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin);
107
- (0, globals_1.expect)(unpacked.subCommandParams).toBeUndefined();
108
- (0, globals_1.expect)(unpacked.pinUvAuthParam).toBeUndefined();
109
- (0, globals_1.expect)(unpacked.pinUvAuthProtocol).toBeUndefined();
111
+ strict_1.default.equal(unpacked.subCommand, ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin);
112
+ strict_1.default.equal(unpacked.subCommandParams, undefined);
113
+ strict_1.default.equal(unpacked.pinUvAuthParam, undefined);
114
+ strict_1.default.equal(unpacked.pinUvAuthProtocol, undefined);
110
115
  });
111
- (0, globals_1.test)("credential management response optional binary fields handled when absent/present", () => {
116
+ (0, node_test_1.test)("credential management response optional binary fields handled when absent/present", () => {
112
117
  // Absent case
113
118
  const packedAbsent = (0, ctap_model_1.packCredentialManagementResponse)({});
114
119
  const absent = (0, ctap_model_1.unpackCredentialManagementResponse)(packedAbsent);
115
- (0, globals_1.expect)(absent.credentialID).toBeUndefined();
116
- (0, globals_1.expect)(absent.publicKey).toBeUndefined();
117
- (0, globals_1.expect)(absent.rpIDHash).toBeUndefined();
118
- (0, globals_1.expect)(absent.largeBlobKey).toBeUndefined();
120
+ strict_1.default.equal(absent.credentialID, undefined);
121
+ strict_1.default.equal(absent.publicKey, undefined);
122
+ strict_1.default.equal(absent.rpIDHash, undefined);
123
+ strict_1.default.equal(absent.largeBlobKey, undefined);
119
124
  // Present case
120
125
  const bin = new Uint8Array([1, 2, 3]);
121
126
  const packedPresent = (0, ctap_model_1.packCredentialManagementResponse)({
@@ -125,32 +130,32 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
125
130
  largeBlobKey: bin,
126
131
  });
127
132
  const present = (0, ctap_model_1.unpackCredentialManagementResponse)(packedPresent);
128
- (0, globals_1.expect)(present.credentialID).toBeDefined();
129
- (0, globals_1.expect)(present.publicKey).toBeDefined();
130
- (0, globals_1.expect)(present.rpIDHash).toBeDefined();
131
- (0, globals_1.expect)(present.largeBlobKey).toBeDefined();
133
+ strict_1.default.notEqual(present.credentialID, undefined);
134
+ strict_1.default.notEqual(present.publicKey, undefined);
135
+ strict_1.default.notEqual(present.rpIDHash, undefined);
136
+ strict_1.default.notEqual(present.largeBlobKey, undefined);
132
137
  if (present.credentialID && present.publicKey && present.rpIDHash && present.largeBlobKey) {
133
- (0, globals_1.expect)(Array.from(present.credentialID)).toEqual([1, 2, 3]);
134
- (0, globals_1.expect)(Array.from(present.publicKey)).toEqual([1, 2, 3]);
135
- (0, globals_1.expect)(Array.from(present.rpIDHash)).toEqual([1, 2, 3]);
136
- (0, globals_1.expect)(Array.from(present.largeBlobKey)).toEqual([1, 2, 3]);
138
+ strict_1.default.deepEqual(Array.from(present.credentialID), [1, 2, 3]);
139
+ strict_1.default.deepEqual(Array.from(present.publicKey), [1, 2, 3]);
140
+ strict_1.default.deepEqual(Array.from(present.rpIDHash), [1, 2, 3]);
141
+ strict_1.default.deepEqual(Array.from(present.largeBlobKey), [1, 2, 3]);
137
142
  }
138
143
  });
139
- (0, globals_1.test)("unpackCredentialManagementRequest throws on invalid CBOR", () => {
144
+ (0, node_test_1.test)("unpackCredentialManagementRequest throws on invalid CBOR", () => {
140
145
  const bad = {
141
146
  command: ctap_model_1.CTAP_COMMAND.authenticatorCredentialManagement,
142
147
  data: new Uint8Array([1, 2, 3]),
143
148
  };
144
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackCredentialManagementRequest)(bad)).toThrow(/CTAP2_ERR_INVALID_CBOR/);
149
+ strict_1.default.throws(() => (0, ctap_model_1.unpackCredentialManagementRequest)(bad), /CTAP2_ERR_INVALID_CBOR/);
145
150
  });
146
- (0, globals_1.test)("unpackCredentialManagementResponse throws on invalid CBOR", () => {
151
+ (0, node_test_1.test)("unpackCredentialManagementResponse throws on invalid CBOR", () => {
147
152
  const bad = {
148
153
  status: ctap_model_1.CTAP_STATUS_CODE.CTAP2_OK,
149
154
  data: new Uint8Array([1, 2, 3]),
150
155
  };
151
- (0, globals_1.expect)(() => (0, ctap_model_1.unpackCredentialManagementResponse)(bad)).toThrow(/CTAP2_ERR_INVALID_CBOR/);
156
+ strict_1.default.throws(() => (0, ctap_model_1.unpackCredentialManagementResponse)(bad), /CTAP2_ERR_INVALID_CBOR/);
152
157
  });
153
- (0, globals_1.test)("unpackRequest CM includes pinUvAuthParam when present", () => {
158
+ (0, node_test_1.test)("unpackRequest CM includes pinUvAuthParam when present", () => {
154
159
  const pin = new Uint8Array([7, 7]);
155
160
  const packed = (0, ctap_model_1.packCredentialManagementRequest)({
156
161
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
@@ -160,12 +165,12 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
160
165
  const unpacked = (0, ctap_model_1.unpackRequest)(packed);
161
166
  const req = unpacked.request;
162
167
  const isMgmt = (x) => typeof x === "object" && x !== null && "subCommand" in x;
163
- (0, globals_1.expect)(isMgmt(req)).toBe(true);
168
+ strict_1.default.equal(isMgmt(req), true);
164
169
  if (isMgmt(req)) {
165
- (0, globals_1.expect)(Array.from(req.pinUvAuthParam ?? new Uint8Array())).toEqual([7, 7]);
170
+ strict_1.default.deepEqual(Array.from(req.pinUvAuthParam ?? new Uint8Array()), [7, 7]);
166
171
  }
167
172
  });
168
- (0, globals_1.test)("unpackCredentialManagementRequest includes pinUvAuthParam when present", () => {
173
+ (0, node_test_1.test)("unpackCredentialManagementRequest includes pinUvAuthParam when present", () => {
169
174
  const pin = new Uint8Array([9, 9]);
170
175
  const packed = (0, ctap_model_1.packCredentialManagementRequest)({
171
176
  subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
@@ -173,6 +178,6 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
173
178
  pinUvAuthParam: pin,
174
179
  });
175
180
  const req = (0, ctap_model_1.unpackCredentialManagementRequest)(packed);
176
- (0, globals_1.expect)(Array.from(req.pinUvAuthParam ?? new Uint8Array())).toEqual([9, 9]);
181
+ strict_1.default.deepEqual(Array.from(req.pinUvAuthParam ?? new Uint8Array()), [9, 9]);
177
182
  });
178
183
  });
@@ -3,11 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const globals_1 = require("@jest/globals");
6
+ const node_test_1 = require("node:test");
7
7
  const index_1 = __importDefault(require("../../src/index"));
8
8
  const webauthn_io_1 = require("./webauthn-io");
9
- (0, globals_1.describe)("Passkeys Integration Test by webauthn.io", () => {
10
- globals_1.test.skip("Registration Ceremony and Authentication Ceremony", async () => {
9
+ (0, node_test_1.describe)("Passkeys Integration Test by webauthn.io", () => {
10
+ (0, node_test_1.test)("Registration Ceremony and Authentication Ceremony", {
11
+ timeout: 60_000,
12
+ skip: process.env.RUN_WEBAUTHN_IO !== "1",
13
+ }, async () => {
11
14
  const origin = "https://webauthn.io";
12
15
  const emulator = new index_1.default();
13
16
  const webauthnIO = await webauthn_io_1.WebAuthnIO.create();
@@ -28,5 +31,5 @@ const webauthn_io_1 = require("./webauthn-io");
28
31
  console.log("Authentication credential", requestCredential);
29
32
  await webauthnIO.getAuthenticationVerification(requestCredential);
30
33
  console.log("Authentication verification completed");
31
- }, 60000);
34
+ });
32
35
  });
@@ -1,4 +1,3 @@
1
- import type { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from "../../src/webauthn/webauthn-model-json";
2
1
  export interface PasskeysUser {
3
2
  username: string;
4
3
  id: string;
@@ -1,4 +1,3 @@
1
- import type { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from "../../src/webauthn/webauthn-model-json";
2
1
  import type { PasskeysApiClient, PasskeysUser } from "./passkeys-api-client";
3
2
  /**
4
3
  * Passkeys Api Client implementation for webauthn.io