nid-webauthn-emulator 0.2.3 → 0.2.5

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 ADDED
@@ -0,0 +1,216 @@
1
+ # NID WebAuthn Emulator
2
+
3
+ [![CI Status](https://github.com/Nikkei/nid-webauthn-emulator/actions/workflows/ci.yml/badge.svg)](https://github.com/Nikkei/nid-webauthn-emulator/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ [English](README.md) | [日本語](README.ja.md)
7
+
8
+ `NID WebAuthn Emulator` は、[FIDO2/CTAP Authenticator のエミュレータ](src/authenticator/authenticator-emulator.ts) およびそれを利用した [WebAuthn API のエミュレータ](src/webauthn/webauthn-emulator.ts) ライブラリです。それぞれ WebAuthn API および CTAP の仕様に基づいて実装されています。このモジュールは Node.js 上で動作し、ローカルでの Passkeys の統合テストを目的として設計されています。
9
+
10
+ それぞれのエミュレータの詳細な仕様は下記を参照してください。
11
+
12
+ - [FIDO2/CTAP Authenticator Emulator 開発者向け詳細仕様](docs/authenticator-emulator.ja.md)
13
+ - [WebAuthn API Emulator 開発者向け詳細仕様](docs/webauthn-emulator.ja.md)
14
+
15
+ ## 使用方法
16
+
17
+ ```bash
18
+ npm install nid-webauthn-emulator
19
+ ```
20
+
21
+ 基本的な使い方は `WebAuthnEmulator` クラスを作成し、`create` および `get` メソッドを利用することで、WebAuthn API における `navigator.credentials.create` および `navigator.credentials.get` をエミュレーションすることができます。
22
+
23
+ ```TypeScript
24
+ import WebAuthnEmulator from "nid-webauthn-emulator";
25
+
26
+ const emulator = new WebAuthnEmulator();
27
+ const origin = "https://example.com";
28
+
29
+ emulator.create(origin, creationOptions);
30
+ emulator.get(origin, requestOptions);
31
+ ```
32
+
33
+ また、`createJSON` および `getJSON` メソッドを利用することで、WebAuthn API で WebAuthn API 仕様に基づいた JSON データでのエミュレーションを行うこともできます。
34
+
35
+ ```TypeScript
36
+ emulator.createJSON(origin, creationOptionsJSON);
37
+ emulator.getJSON(origin, requestOptionsJSON);
38
+ ```
39
+
40
+ これらの JSON の仕様は、標準仕様の下記に定義されたデータです。
41
+
42
+ - <https://www.w3.org/TR/webauthn-3/#dictdef-authenticationresponsejson>
43
+ - <https://www.w3.org/TR/webauthn-3/#dictdef-registrationresponsejson>
44
+
45
+ `WebAuthnEmulator` クラスは標準で下記の FIDO2/CTAP Authenticator をエミュレートします。
46
+
47
+ - 自動で User Verification を行います (`uv` フラグを立てます)
48
+ - ES256, RS256, EdDSA のアルゴリズムをサポートします
49
+ - USB 接続の CTAP2 デバイスをエミュレートします
50
+ - AAGUID は `NID-AUTH-3141592` です
51
+ - 認証時には Sign Counter を `1` インクリメントさせます
52
+
53
+ これらの設定は下記のように `AuthenticatorEmulator` クラスを作成し、`WebAuthnEmulator` クラスに渡すことで、Authenticator の挙動を変更することができます。
54
+
55
+ ```TypeScript
56
+ import WebAuthnEmulator, { AuthenticatorEmulator } from "nid-webauthn-emulator";
57
+
58
+ const authenticator = new AuthenticatorEmulator({
59
+ algorithmIdentifiers: ["ES256"],
60
+ verifications: {
61
+ userVerified: false,
62
+ userPresent: false,
63
+ },
64
+ signCounterIncrement: 0,
65
+ });
66
+
67
+ const webAuthnEmulator = new WebAuthnEmulator(authenticator);
68
+ ```
69
+
70
+ `AuthenticatorEmulator` は FIDO2/CTAP の仕様のうち下記のコマンドを実装しています。
71
+
72
+ - `authenticatorMakeCredential` (CTAP2) : 認証情報の作成
73
+ - `authenticatorGetAssertion` (CTAP2) : 認証情報の取得
74
+ - `authenticatorGetInfo` (CTAP2) : 認証情報の取得
75
+
76
+ これらは通常は直接利用することはありませんが、`WebAuthnEmulator` クラスの内部で CTAP のプロトコルに従って下記の通り呼び出されています。
77
+
78
+ ```TypeScript
79
+ const authenticatorRequest = packMakeCredentialRequest({
80
+ clientDataHash: createHash("sha256").update(clientDataJSON).digest(),
81
+ rp: options.publicKey.rp,
82
+ user: options.publicKey.user,
83
+ pubKeyCredParams: options.publicKey.pubKeyCredParams,
84
+ excludeList: options.publicKey.excludeCredentials,
85
+ options: {
86
+ rk: options.publicKey.authenticatorSelection?.requireResidentKey,
87
+ uv: options.publicKey.authenticatorSelection?.userVerification !== "discouraged",
88
+ },
89
+ });
90
+ const authenticatorResponse = unpackMakeCredentialResponse(this.authenticator.command(authenticatorRequest));
91
+ ```
92
+
93
+ ## [WebAuthn.io](https://webauthn.io/) での実行例
94
+
95
+ WebAuthn の著名なデモサイトである [webauthn.io](https://webauthn.io/) での使用例を示します。[統合テスト](spec/integration/integration.spec.ts) に実際にうごくテストコード例があります。
96
+
97
+ ```TypeScript
98
+ // Origin および WebAuthn API エミュレータを初期化します
99
+ // ここでは、https://webauthn.io を Origin として利用します
100
+ const origin = "https://webauthn.io";
101
+ const emulator = new WebAuthnEmulator();
102
+ const webauthnIO = await WebAuthnIO.create();
103
+ const user = webauthnIO.getUser();
104
+
105
+ // Authenticator の情報を表示します
106
+ console.log("Authenticator Information", emulator.getAuthenticatorInfo());
107
+
108
+ // WebAuthn API Emulator により パスキーを作成します
109
+ const creationOptions = await webauthnIO.getRegistrationOptions(user);
110
+ const creationCredential = emulator.createJSON(origin, creationOptions);
111
+ await webauthnIO.getRegistrationVerification(user, creationCredential);
112
+
113
+ // 認証を webauthn.io で検証します
114
+ const requestOptions = await webauthnIO.getAuthenticationOptions();
115
+ const requestCredential = emulator.getJSON(origin, requestOptions);
116
+ await webauthnIO.getAuthenticationVerification(requestCredential);
117
+ ```
118
+
119
+ ## Playwright による自動テスト
120
+
121
+ このライブラリは Passkeys の E2E テストでの利用を目的としており、特に Playwright での利用を想定しています。Playwright でのテスト用にユーティリティクラス `BrowserInjection` を利用して簡単に、WebAuthn API エミュレータを利用することができます。使い方は下記の通りです。
122
+
123
+ ```TypeScript
124
+ import WebAuthnEmulator, {
125
+ BrowserInjection,
126
+ type PublicKeyCredentialCreationOptionsJSON,
127
+ type PublicKeyCredentialRequestOptionsJSON,
128
+ } from "nid-webauthn-emulator";
129
+
130
+ async function startWebAuthnEmulator(page: Page, origin: string, debug = false, relatedOrigins: string[] = []) {
131
+ const emulator = new WebAuthnEmulator();
132
+
133
+ await page.exposeFunction(
134
+ BrowserInjection.WebAuthnEmulatorCreate,
135
+ async (optionsJSON: PublicKeyCredentialCreationOptionsJSON) => {
136
+ const response = emulator.createJSON(origin, optionsJSON, relatedOrigins);
137
+ return response;
138
+ },
139
+ );
140
+
141
+ await page.exposeFunction(
142
+ BrowserInjection.WebAuthnEmulatorGet,
143
+ async (optionsJSON: PublicKeyCredentialRequestOptionsJSON) => {
144
+ const response = emulator.getJSON(origin, optionsJSON, relatedOrigins);
145
+ return response;
146
+ },
147
+ );
148
+
149
+ await page.exposeFunction(
150
+ BrowserInjection.WebAuthnEmulatorSignalUnknownCredential,
151
+ async (options: UnknownCredentialOptionsJSON) => {
152
+ emulator.signalUnknownCredential(options);
153
+ },
154
+ );
155
+
156
+ await page.exposeFunction(
157
+ BrowserInjection.WebAuthnEmulatorSignalAllAcceptedCredentials,
158
+ async (options: AllAcceptedCredentialsOptionsJSON) => {
159
+ emulator.signalAllAcceptedCredentials(options);
160
+ },
161
+ );
162
+
163
+ await page.exposeFunction(
164
+ BrowserInjection.WebAuthnEmulatorSignalCurrentUserDetails,
165
+ async (options: CurrentUserDetailsOptionsJSON) => {
166
+ emulator.signalCurrentUserDetails(options);
167
+ },
168
+ );
169
+ }
170
+
171
+ test.describe("Passkeys Tests", { tag: ["@daily"] }, () => {
172
+ test("Passkeys login test", async ({ page }) => {
173
+ // Page内で最初に1回だけ定義する exposed functions
174
+ // 必要に応じて関連オリジンを指定できます
175
+ const relatedOrigins = ["https://sub.example.com", "https://alt.example.com"];
176
+ await startWebAuthnEmulator(page, env, true, relatedOrigins);
177
+ await page.goto("https://example.com/passkeys/login");
178
+
179
+ // Passkeys の WebAuthn API をフック開始
180
+ // ページ遷移後に実行する必要がある
181
+ await page.evaluate(BrowserInjection.HookWebAuthnApis);
182
+ });
183
+ });
184
+ ```
185
+
186
+ `startWebAuthnEmulator` では Playwright の `exposeFunction` を利用して、`WebAuthnEmulator` の `createJSON` および `getJSON` メソッドをブラウザのコンテキストに注入します。これにより、Playwright でのテストコンテキストにおいて `WebAuthnEmulator` クラスの `get` および `create` の各 API がそれぞれ `window` オブジェクトの下に定義されるようになります。
187
+
188
+ - `window.webAuthnEmulatorGet`: `WebAuthnEmulator.getJSON` の Exposed Function
189
+ - `window.webAuthnEmulatorCreate`: `WebAuthnEmulator.createJSON` の Exposed Function
190
+ - `window.webAuthnEmulatorSignalUnknownCredential`: `WebAuthnEmulator.signalUnknownCredential` の Exposed Function
191
+ - `window.webAuthnEmulatorSignalAllAcceptedCredentials`: `WebAuthnEmulator.signalAllAcceptedCredentials` の Exposed Function
192
+ - `window.webAuthnEmulatorSignalCurrentUserDetails`: `WebAuthnEmulator.signalCurrentUserDetails` の Exposed Function
193
+
194
+ さらに`startWebAuthnEmulator`関数は`relatedOrigins`パラメータをサポートしています。これにより、異なるオリジンからのリクエストでも同じRP IDを使用できるようになります。例えば、マルチドメイン環境(`example.com`と`sub.example.com`など)でPasskeysを使用する場合に便利です。`relatedOrigins` の値はRP IDで指定されたドメインでホストされた `/.well-known/webauthn` の内容と同じです。
195
+
196
+ これらは Page グローバルに定義されるため、Page インスタンスにつき 1 回だけ定義する必要があります。
197
+
198
+ 次に `navigator.credentials.get` 等の WebAuthn API をフックするために、`BrowserInjection.HookWebAuthnApis` をテストコンテキストにおいて評価します。
199
+
200
+ ```TypeScript
201
+ await page.evaluate(BrowserInjection.HookWebAuthnApis);
202
+ ```
203
+
204
+ `BrowserInjection.HookWebAuthnApis` は JavaScript 関数のシリアライズされた文字列であり、評価すると下記のような処理を行います。
205
+
206
+ - `navigator.credentials.get` の定義を上書きし、`window.webAuthnEmulatorGet` を呼び出す
207
+ - `navigator.credentials.create` の定義を上書きし、`window.webAuthnEmulatorCreate` を呼び出す
208
+ - `PublicKeyCredential.signalUnknownCredential` の定義を追加し、`window.webAuthnEmulatorSignalUnknownCredential` を呼び出す
209
+
210
+ これにより先ほどの `exposeFunction` で定義した `WebAuthnEmulator` のメソッドが、`navigator.credentials.get` および `navigator.credentials.create` 呼び出し時に実行されるようになります。これらの処理中にはテストコンテキストと Playwright のコンテキスト間の通信のためにデータのシリアライズおよびデシリアライズが行われるため、そのための処理も含まれています。
211
+
212
+ ## ライセンス
213
+
214
+ MIT License
215
+
216
+ Copyright (C) 2024 Nikkei Inc.
package/README.md CHANGED
@@ -2,21 +2,24 @@
2
2
 
3
3
  [![CI Status](https://github.com/Nikkei/nid-webauthn-emulator/actions/workflows/ci.yml/badge.svg)](https://github.com/Nikkei/nid-webauthn-emulator/actions/workflows/ci.yml)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/Nikkei/nid-webauthn-emulator)
5
6
 
6
- `NID WebAuthn Emulator` は、[FIDO2/CTAP Authenticator のエミュレータ](src/authenticator/authenticator-emulator.ts) およびそれを利用した [WebAuthn API のエミュレータ](src/webauthn/webauthn-emulator.ts) ライブラリです。それぞれ WebAuthn API および CTAP の仕様に基づいて実装されています。このモジュールは Node.js 上で動作し、ローカルでの Passkeys の統合テストを目的として設計されています。
7
+ [English](README.md) | [日本語](README.ja.md)
7
8
 
8
- それぞれのエミュレータの詳細な仕様は下記を参照してください。
9
+ `NID WebAuthn Emulator` is a library that provides both a [FIDO2/CTAP Authenticator emulator](src/authenticator/authenticator-emulator.ts) and a [WebAuthn API emulator](src/webauthn/webauthn-emulator.ts) built on top of it. Each component is implemented according to the WebAuthn API and CTAP specifications respectively. This module runs on Node.js and is designed for local integration testing of Passkeys.
9
10
 
10
- - [FIDO2/CTAP Authenticator Emulator 開発者向け詳細仕様](docs/authenticator-emulator.md)
11
- - [WebAuthn API Emulator 開発者向け詳細仕様](docs/webauthn-emulator.md)
11
+ For detailed specifications of each emulator, please refer to the following:
12
12
 
13
- ## 使用方法
13
+ - [FIDO2/CTAP Authenticator Emulator Detailed Specification for Developers](docs/authenticator-emulator.en.md)
14
+ - [WebAuthn API Emulator Detailed Specification for Developers](docs/webauthn-emulator.en.md)
15
+
16
+ ## Usage
14
17
 
15
18
  ```bash
16
19
  npm install nid-webauthn-emulator
17
20
  ```
18
21
 
19
- 基本的な使い方は `WebAuthnEmulator` クラスを作成し、`create` および `get` メソッドを利用することで、WebAuthn API における `navigator.credentials.create` および `navigator.credentials.get` をエミュレーションすることができます。
22
+ Basic usage involves creating a `WebAuthnEmulator` class and using the `create` and `get` methods to emulate `navigator.credentials.create` and `navigator.credentials.get` from the WebAuthn API.
20
23
 
21
24
  ```TypeScript
22
25
  import WebAuthnEmulator from "nid-webauthn-emulator";
@@ -28,27 +31,27 @@ emulator.create(origin, creationOptions);
28
31
  emulator.get(origin, requestOptions);
29
32
  ```
30
33
 
31
- また、`createJSON` および `getJSON` メソッドを利用することで、WebAuthn API で WebAuthn API 仕様に基づいた JSON データでのエミュレーションを行うこともできます。
34
+ You can also use the `createJSON` and `getJSON` methods to perform emulation with JSON data based on the WebAuthn API specification.
32
35
 
33
36
  ```TypeScript
34
37
  emulator.createJSON(origin, creationOptionsJSON);
35
38
  emulator.getJSON(origin, requestOptionsJSON);
36
39
  ```
37
40
 
38
- これらの JSON の仕様は、標準仕様の下記に定義されたデータです。
41
+ These JSON specifications are defined as standard specification data in the following:
39
42
 
40
43
  - <https://www.w3.org/TR/webauthn-3/#dictdef-authenticationresponsejson>
41
44
  - <https://www.w3.org/TR/webauthn-3/#dictdef-registrationresponsejson>
42
45
 
43
- `WebAuthnEmulator` クラスは標準で下記の FIDO2/CTAP Authenticator をエミュレートします。
46
+ The `WebAuthnEmulator` class emulates the following FIDO2/CTAP Authenticator by default:
44
47
 
45
- - 自動で User Verification を行います (`uv` フラグを立てます)
46
- - ES256, RS256, EdDSA のアルゴリズムをサポートします
47
- - USB 接続の CTAP2 デバイスをエミュレートします
48
- - AAGUID は `NID-AUTH-3141592` です
49
- - 認証時には Sign Counter を `1` インクリメントさせます
48
+ - Automatically performs User Verification (sets the `uv` flag)
49
+ - Supports ES256, RS256, and EdDSA algorithms
50
+ - Emulates a USB-connected CTAP2 device
51
+ - AAGUID is `NID-AUTH-3141592`
52
+ - Increments the Sign Counter by `1` during authentication
50
53
 
51
- これらの設定は下記のように `AuthenticatorEmulator` クラスを作成し、`WebAuthnEmulator` クラスに渡すことで、Authenticator の挙動を変更することができます。
54
+ These settings can be changed by creating an `AuthenticatorEmulator` class and passing it to the `WebAuthnEmulator` class to modify the Authenticator behavior as follows:
52
55
 
53
56
  ```TypeScript
54
57
  import WebAuthnEmulator, { AuthenticatorEmulator } from "nid-webauthn-emulator";
@@ -65,13 +68,13 @@ const authenticator = new AuthenticatorEmulator({
65
68
  const webAuthnEmulator = new WebAuthnEmulator(authenticator);
66
69
  ```
67
70
 
68
- `AuthenticatorEmulator` は FIDO2/CTAP の仕様のうち下記のコマンドを実装しています。
71
+ `AuthenticatorEmulator` implements the following commands from the FIDO2/CTAP specification:
69
72
 
70
- - `authenticatorMakeCredential` (CTAP2) : 認証情報の作成
71
- - `authenticatorGetAssertion` (CTAP2) : 認証情報の取得
72
- - `authenticatorGetInfo` (CTAP2) : 認証情報の取得
73
+ - `authenticatorMakeCredential` (CTAP2): Creating credentials
74
+ - `authenticatorGetAssertion` (CTAP2): Retrieving credentials
75
+ - `authenticatorGetInfo` (CTAP2): Getting authenticator information
73
76
 
74
- これらは通常は直接利用することはありませんが、`WebAuthnEmulator` クラスの内部で CTAP のプロトコルに従って下記の通り呼び出されています。
77
+ These are typically not used directly, but are called internally by the `WebAuthnEmulator` class according to the CTAP protocol as follows:
75
78
 
76
79
  ```TypeScript
77
80
  const authenticatorRequest = packMakeCredentialRequest({
@@ -88,35 +91,35 @@ const authenticatorRequest = packMakeCredentialRequest({
88
91
  const authenticatorResponse = unpackMakeCredentialResponse(this.authenticator.command(authenticatorRequest));
89
92
  ```
90
93
 
91
- ## [WebAuthn.io](https://webauthn.io/) での実行例
94
+ ## Example with [WebAuthn.io](https://webauthn.io/)
92
95
 
93
- WebAuthn の著名なデモサイトである [webauthn.io](https://webauthn.io/) での使用例を示します。[統合テスト](spec/integration/integration.spec.ts) に実際にうごくテストコード例があります。
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).
94
97
 
95
98
  ```TypeScript
96
- // Origin および WebAuthn API エミュレータを初期化します
97
- // ここでは、https://webauthn.io を Origin として利用します
99
+ // Initialize the Origin and WebAuthn API emulator
100
+ // Here we use https://webauthn.io as the Origin
98
101
  const origin = "https://webauthn.io";
99
102
  const emulator = new WebAuthnEmulator();
100
103
  const webauthnIO = await WebAuthnIO.create();
101
104
  const user = webauthnIO.getUser();
102
105
 
103
- // Authenticator の情報を表示します
106
+ // Display Authenticator information
104
107
  console.log("Authenticator Information", emulator.getAuthenticatorInfo());
105
108
 
106
- // WebAuthn API Emulator により パスキーを作成します
109
+ // Create passkey using WebAuthn API Emulator
107
110
  const creationOptions = await webauthnIO.getRegistrationOptions(user);
108
111
  const creationCredential = emulator.createJSON(origin, creationOptions);
109
112
  await webauthnIO.getRegistrationVerification(user, creationCredential);
110
113
 
111
- // 認証を webauthn.io で検証します
114
+ // Verify authentication with webauthn.io
112
115
  const requestOptions = await webauthnIO.getAuthenticationOptions();
113
116
  const requestCredential = emulator.getJSON(origin, requestOptions);
114
117
  await webauthnIO.getAuthenticationVerification(requestCredential);
115
118
  ```
116
119
 
117
- ## Playwright による自動テスト
120
+ ## Automated Testing with Playwright
118
121
 
119
- このライブラリは Passkeys の E2E テストでの利用を目的としており、特に Playwright での利用を想定しています。Playwright でのテスト用にユーティリティクラス `BrowserInjection` を利用して簡単に、WebAuthn API エミュレータを利用することができます。使い方は下記の通りです。
122
+ This library is intended for use in Passkeys E2E testing, particularly with Playwright. For Playwright testing, you can easily use the WebAuthn API emulator with the utility class `BrowserInjection`. Here's how to use it:
120
123
 
121
124
  ```TypeScript
122
125
  import WebAuthnEmulator, {
@@ -168,47 +171,47 @@ async function startWebAuthnEmulator(page: Page, origin: string, debug = false,
168
171
 
169
172
  test.describe("Passkeys Tests", { tag: ["@daily"] }, () => {
170
173
  test("Passkeys login test", async ({ page }) => {
171
- // Page内で最初に1回だけ定義する exposed functions
172
- // 必要に応じて関連オリジンを指定できます
174
+ // Exposed functions defined once per page initially
175
+ // Related origins can be specified as needed
173
176
  const relatedOrigins = ["https://sub.example.com", "https://alt.example.com"];
174
177
  await startWebAuthnEmulator(page, env, true, relatedOrigins);
175
178
  await page.goto("https://example.com/passkeys/login");
176
179
 
177
- // Passkeys の WebAuthn API をフック開始
178
- // ページ遷移後に実行する必要がある
180
+ // Start hooking Passkeys WebAuthn API
181
+ // Must be executed after page navigation
179
182
  await page.evaluate(BrowserInjection.HookWebAuthnApis);
180
183
  });
181
184
  });
182
185
  ```
183
186
 
184
- `startWebAuthnEmulator` では Playwright の `exposeFunction` を利用して、`WebAuthnEmulator` の `createJSON` および `getJSON` メソッドをブラウザのコンテキストに注入します。これにより、Playwright でのテストコンテキストにおいて `WebAuthnEmulator` クラスの `get` および `create` の各 API がそれぞれ `window` オブジェクトの下に定義されるようになります。
187
+ `startWebAuthnEmulator` uses Playwright's `exposeFunction` to inject the `WebAuthnEmulator`'s `createJSON` and `getJSON` methods into the browser context. This makes the `WebAuthnEmulator` class's `get` and `create` APIs available under the `window` object in the Playwright test context.
185
188
 
186
- - `window.webAuthnEmulatorGet`: `WebAuthnEmulator.getJSON` の Exposed Function
187
- - `window.webAuthnEmulatorCreate`: `WebAuthnEmulator.createJSON` の Exposed Function
188
- - `window.webAuthnEmulatorSignalUnknownCredential`: `WebAuthnEmulator.signalUnknownCredential` の Exposed Function
189
- - `window.webAuthnEmulatorSignalAllAcceptedCredentials`: `WebAuthnEmulator.signalAllAcceptedCredentials` の Exposed Function
190
- - `window.webAuthnEmulatorSignalCurrentUserDetails`: `WebAuthnEmulator.signalCurrentUserDetails` の Exposed Function
189
+ - `window.webAuthnEmulatorGet`: Exposed Function for `WebAuthnEmulator.getJSON`
190
+ - `window.webAuthnEmulatorCreate`: Exposed Function for `WebAuthnEmulator.createJSON`
191
+ - `window.webAuthnEmulatorSignalUnknownCredential`: Exposed Function for `WebAuthnEmulator.signalUnknownCredential`
192
+ - `window.webAuthnEmulatorSignalAllAcceptedCredentials`: Exposed Function for `WebAuthnEmulator.signalAllAcceptedCredentials`
193
+ - `window.webAuthnEmulatorSignalCurrentUserDetails`: Exposed Function for `WebAuthnEmulator.signalCurrentUserDetails`
191
194
 
192
- さらに`startWebAuthnEmulator`関数は`relatedOrigins`パラメータをサポートしています。これにより、異なるオリジンからのリクエストでも同じRP IDを使用できるようになります。例えば、マルチドメイン環境(`example.com`と`sub.example.com`など)でPasskeysを使用する場合に便利です。
195
+ Additionally, the `startWebAuthnEmulator` function supports a `relatedOrigins` parameter. This allows requests from different origins to use the same RP ID. This is useful when using Passkeys in multi-domain environments (such as `example.com` and `sub.example.com`). The value of `relatedOrigins` is the same as the content of `/.well-known/webauthn` hosted on the domain specified by the RP ID.
193
196
 
194
- これらは Page グローバルに定義されるため、Page インスタンスにつき 1 回だけ定義する必要があります。
197
+ These are defined globally per Page, so they need to be defined only once per Page instance.
195
198
 
196
- 次に `navigator.credentials.get` 等の WebAuthn API をフックするために、`BrowserInjection.HookWebAuthnApis` をテストコンテキストにおいて評価します。
199
+ Next, to hook WebAuthn APIs like `navigator.credentials.get`, evaluate `BrowserInjection.HookWebAuthnApis` in the test context.
197
200
 
198
201
  ```TypeScript
199
202
  await page.evaluate(BrowserInjection.HookWebAuthnApis);
200
203
  ```
201
204
 
202
- `BrowserInjection.HookWebAuthnApis` は JavaScript 関数のシリアライズされた文字列であり、評価すると下記のような処理を行います。
205
+ `BrowserInjection.HookWebAuthnApis` is a serialized string of a JavaScript function that, when evaluated, performs the following operations:
203
206
 
204
- - `navigator.credentials.get` の定義を上書きし、`window.webAuthnEmulatorGet` を呼び出す
205
- - `navigator.credentials.create` の定義を上書きし、`window.webAuthnEmulatorCreate` を呼び出す
206
- - `PublicKeyCredential.signalUnknownCredential` の定義を追加し、`window.webAuthnEmulatorSignalUnknownCredential` を呼び出す
207
+ - Overrides the definition of `navigator.credentials.get` to call `window.webAuthnEmulatorGet`
208
+ - Overrides the definition of `navigator.credentials.create` to call `window.webAuthnEmulatorCreate`
209
+ - Adds the definition of `PublicKeyCredential.signalUnknownCredential` to call `window.webAuthnEmulatorSignalUnknownCredential`
207
210
 
208
- これにより先ほどの `exposeFunction` で定義した `WebAuthnEmulator` のメソッドが、`navigator.credentials.get` および `navigator.credentials.create` 呼び出し時に実行されるようになります。これらの処理中にはテストコンテキストと Playwright のコンテキスト間の通信のためにデータのシリアライズおよびデシリアライズが行われるため、そのための処理も含まれています。
211
+ This ensures that the `WebAuthnEmulator` methods defined earlier with `exposeFunction` are executed when `navigator.credentials.get` and `navigator.credentials.create` are called. These processes include serialization and deserialization of data for communication between the test context and Playwright context.
209
212
 
210
- ## ライセンス
213
+ ## License
211
214
 
212
215
  MIT License
213
216
 
214
- Copyright (C) 2024 Nikkei Inc.
217
+ Copyright (C) 2024 Nikkei Inc.
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const globals_1 = require("@jest/globals");
7
7
  const src_1 = require("../../src");
8
8
  const ctap_model_1 = require("../../src/authenticator/ctap-model");
9
- const ctap_model_2 = require("../../src/authenticator/ctap-model");
10
9
  const encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
11
10
  const credentials_memory_repository_1 = require("../../src/repository/credentials-memory-repository");
12
11
  (0, globals_1.describe)("Authenticator Emulator Exceptional Test", () => {
@@ -18,7 +17,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
18
17
  const authenticator = new src_1.AuthenticatorEmulator();
19
18
  (0, globals_1.expect)(() => {
20
19
  authenticator.command(testRequest);
21
- }).toThrowError("CTAP error: CTAP1_ERR_INVALID_COMMAND (1)");
20
+ }).toThrow("CTAP error: CTAP1_ERR_INVALID_COMMAND (1)");
22
21
  });
23
22
  });
24
23
  (0, globals_1.describe)("Authenticator Credential Management Tests", () => {
@@ -69,7 +68,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
69
68
  (0, globals_1.test)("should return the total number of credentials for a specific RP", () => {
70
69
  // Create request for enumerateCredentialsBegin
71
70
  const request = {
72
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
71
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
73
72
  subCommandParams: {
74
73
  rpId: rpId1,
75
74
  },
@@ -82,17 +81,17 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
82
81
  (0, globals_1.test)("should throw an error if rpId is not provided", () => {
83
82
  // Create request without rpId
84
83
  const request = {
85
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
84
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
86
85
  };
87
86
  // Execute the command and expect an error
88
87
  (0, globals_1.expect)(() => {
89
88
  authenticator.authenticatorCredentialManagement(request);
90
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
89
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
91
90
  });
92
91
  (0, globals_1.test)("should return 0 credentials for an RP with no credentials", () => {
93
92
  // Create request for a non-existent RP
94
93
  const request = {
95
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
94
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
96
95
  subCommandParams: {
97
96
  rpId: "nonexistent.com",
98
97
  },
@@ -107,7 +106,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
107
106
  (0, globals_1.test)("should return credentials one by one", () => {
108
107
  // First, call enumerateCredentialsBegin
109
108
  const beginRequest = {
110
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
109
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
111
110
  subCommandParams: {
112
111
  rpId: rpId1,
113
112
  },
@@ -115,7 +114,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
115
114
  authenticator.authenticatorCredentialManagement(beginRequest);
116
115
  // Now call enumerateCredentialsGetNextCredential twice to get both credentials
117
116
  const getNextRequest = {
118
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
117
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
119
118
  };
120
119
  // Get first credential
121
120
  const response1 = authenticator.authenticatorCredentialManagement(getNextRequest);
@@ -134,15 +133,15 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
134
133
  // Verify we can't get more credentials
135
134
  (0, globals_1.expect)(() => {
136
135
  authenticator.authenticatorCredentialManagement(getNextRequest);
137
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
136
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
138
137
  });
139
138
  (0, globals_1.test)("should throw an error if called without calling enumerateCredentialsBegin first", () => {
140
139
  const getNextRequest = {
141
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
140
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
142
141
  };
143
142
  (0, globals_1.expect)(() => {
144
143
  authenticator.authenticatorCredentialManagement(getNextRequest);
145
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
144
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
146
145
  });
147
146
  });
148
147
  (0, globals_1.describe)("updateUserInformation", () => {
@@ -155,7 +154,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
155
154
  };
156
155
  // Create request for updateUserInformation
157
156
  const request = {
158
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
157
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
159
158
  subCommandParams: {
160
159
  rpId: rpId1,
161
160
  user: updatedUser,
@@ -165,14 +164,14 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
165
164
  authenticator.authenticatorCredentialManagement(request);
166
165
  // Verify the user information was updated by enumerating credentials
167
166
  const beginRequest = {
168
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
167
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
169
168
  subCommandParams: {
170
169
  rpId: rpId1,
171
170
  },
172
171
  };
173
172
  authenticator.authenticatorCredentialManagement(beginRequest);
174
173
  const getNextRequest = {
175
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
174
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsGetNextCredential,
176
175
  };
177
176
  // Get credentials and check if user info was updated
178
177
  const nextResponse = authenticator.authenticatorCredentialManagement(getNextRequest);
@@ -185,25 +184,25 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
185
184
  });
186
185
  (0, globals_1.test)("should throw an error if rpId is not provided", () => {
187
186
  const request = {
188
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
187
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
189
188
  subCommandParams: {
190
189
  user: user1,
191
190
  },
192
191
  };
193
192
  (0, globals_1.expect)(() => {
194
193
  authenticator.authenticatorCredentialManagement(request);
195
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
194
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
196
195
  });
197
196
  (0, globals_1.test)("should throw an error if user is not provided", () => {
198
197
  const request = {
199
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
198
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
200
199
  subCommandParams: {
201
200
  rpId: rpId1,
202
201
  },
203
202
  };
204
203
  (0, globals_1.expect)(() => {
205
204
  authenticator.authenticatorCredentialManagement(request);
206
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
205
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP1_ERR_INVALID_PARAMETER));
207
206
  });
208
207
  (0, globals_1.test)("should throw an error if no credentials exist for the user", () => {
209
208
  const nonExistentUser = {
@@ -212,7 +211,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
212
211
  displayName: "Non Existent User",
213
212
  };
214
213
  const request = {
215
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
214
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.updateUserInformation,
216
215
  subCommandParams: {
217
216
  rpId: rpId1,
218
217
  user: nonExistentUser,
@@ -220,7 +219,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
220
219
  };
221
220
  (0, globals_1.expect)(() => {
222
221
  authenticator.authenticatorCredentialManagement(request);
223
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
222
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NO_CREDENTIALS));
224
223
  });
225
224
  });
226
225
  (0, globals_1.describe)("authenticatorCredentialManagement with stateless authenticator", () => {
@@ -231,7 +230,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
231
230
  });
232
231
  // Create request for enumerateCredentialsBegin
233
232
  const request = {
234
- subCommand: ctap_model_2.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
233
+ subCommand: ctap_model_1.CREDENTIAL_MANAGEMENT_SUBCOMMAND.enumerateCredentialsBegin,
235
234
  subCommandParams: {
236
235
  rpId: rpId1,
237
236
  },
@@ -239,7 +238,7 @@ const credentials_memory_repository_1 = require("../../src/repository/credential
239
238
  // Execute the command and expect an error
240
239
  (0, globals_1.expect)(() => {
241
240
  statelessAuthenticator.authenticatorCredentialManagement(request);
242
- }).toThrow(new ctap_model_2.AuthenticationEmulatorError(ctap_model_2.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
241
+ }).toThrow(new ctap_model_1.AuthenticationEmulatorError(ctap_model_1.CTAP_STATUS_CODE.CTAP2_ERR_NOT_ALLOWED));
243
242
  });
244
243
  });
245
244
  });
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const globals_1 = require("@jest/globals");
4
- const globals_2 = require("@jest/globals");
5
4
  const ctap_model_1 = require("../../src/authenticator/ctap-model");
6
5
  (0, globals_1.describe)("CTAP Model Test", () => {
7
6
  (0, globals_1.test)("MakeCredentialRequest CTAP Object pack and unpack", async () => {
@@ -19,8 +18,8 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
19
18
  const packed = (0, ctap_model_1.packMakeCredentialRequest)(testRequest);
20
19
  const unpacked = (0, ctap_model_1.unpackRequest)(packed);
21
20
  const rePacked = (0, ctap_model_1.packMakeCredentialRequest)(unpacked.request);
22
- (0, globals_2.expect)(packed).toEqual(rePacked);
23
- (0, globals_2.expect)(unpacked.request).toEqual(testRequest);
21
+ (0, globals_1.expect)(packed).toEqual(rePacked);
22
+ (0, globals_1.expect)(unpacked.request).toEqual(testRequest);
24
23
  });
25
24
  (0, globals_1.test)("GetAssertionRequest CTAP Object pack and unpack", async () => {
26
25
  const testRequest = {
@@ -35,8 +34,8 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
35
34
  const packed = (0, ctap_model_1.packGetAssertionRequest)(testRequest);
36
35
  const unpacked = (0, ctap_model_1.unpackRequest)(packed);
37
36
  const rePacked = (0, ctap_model_1.packGetAssertionRequest)(unpacked.request);
38
- (0, globals_2.expect)(packed).toEqual(rePacked);
39
- (0, globals_2.expect)(unpacked.request).toEqual(testRequest);
37
+ (0, globals_1.expect)(packed).toEqual(rePacked);
38
+ (0, globals_1.expect)(unpacked.request).toEqual(testRequest);
40
39
  });
41
40
  (0, globals_1.test)("MakeCredentialResponse CTAP Object pack and unpack", async () => {
42
41
  const testResponse = {
@@ -47,8 +46,8 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
47
46
  const packed = (0, ctap_model_1.packMakeCredentialResponse)(testResponse);
48
47
  const unpacked = (0, ctap_model_1.unpackMakeCredentialResponse)(packed);
49
48
  const rePacked = (0, ctap_model_1.packMakeCredentialResponse)(unpacked);
50
- (0, globals_2.expect)(packed).toEqual(rePacked);
51
- (0, globals_2.expect)(unpacked).toEqual(testResponse);
49
+ (0, globals_1.expect)(packed).toEqual(rePacked);
50
+ (0, globals_1.expect)(unpacked).toEqual(testResponse);
52
51
  });
53
52
  (0, globals_1.test)("GetAssertionResponse CTAP Object pack and unpack", async () => {
54
53
  const testResponse = {
@@ -60,8 +59,8 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
60
59
  const packed = (0, ctap_model_1.packGetAssertionResponse)(testResponse);
61
60
  const unpacked = (0, ctap_model_1.unpackGetAssertionResponse)(packed);
62
61
  const rePacked = (0, ctap_model_1.packGetAssertionResponse)(unpacked);
63
- (0, globals_2.expect)(packed).toEqual(rePacked);
64
- (0, globals_2.expect)(unpacked).toEqual(testResponse);
62
+ (0, globals_1.expect)(packed).toEqual(rePacked);
63
+ (0, globals_1.expect)(unpacked).toEqual(testResponse);
65
64
  });
66
65
  (0, globals_1.test)("GetInfoResponse CTAP Object pack and unpack", async () => {
67
66
  const testResponse = {
@@ -75,21 +74,21 @@ const ctap_model_1 = require("../../src/authenticator/ctap-model");
75
74
  const packed = (0, ctap_model_1.packGetInfoResponse)(testResponse);
76
75
  const unpacked = (0, ctap_model_1.unpackGetInfoResponse)(packed);
77
76
  const rePacked = (0, ctap_model_1.packGetInfoResponse)(unpacked);
78
- (0, globals_2.expect)(packed).toEqual(rePacked);
79
- (0, globals_2.expect)(unpacked).toEqual(testResponse);
77
+ (0, globals_1.expect)(packed).toEqual(rePacked);
78
+ (0, globals_1.expect)(unpacked).toEqual(testResponse);
80
79
  });
81
80
  (0, globals_1.test)("Illegal data parse test _ failed to unpack", async () => {
82
81
  const response = {};
83
82
  const expected = "CTAP error: CTAP2_ERR_INVALID_CBOR (18)";
84
- (0, globals_2.expect)(() => (0, ctap_model_1.unpackMakeCredentialResponse)(response)).toThrowError(expected);
85
- (0, globals_2.expect)(() => (0, ctap_model_1.unpackGetAssertionResponse)(response)).toThrowError(expected);
86
- (0, globals_2.expect)(() => (0, ctap_model_1.unpackGetInfoResponse)(response)).toThrowError(expected);
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);
87
86
  });
88
87
  (0, globals_1.test)("Illegal cbor data parse test _ failed to unpack", async () => {
89
88
  const request = {
90
89
  command: ctap_model_1.CTAP_COMMAND.authenticatorMakeCredential,
91
90
  data: new Uint8Array([1, 2, 3, 4, 5]),
92
91
  };
93
- (0, globals_2.expect)(() => (0, ctap_model_1.unpackRequest)(request)).toThrowError("CTAP error: CTAP2_ERR_INVALID_CBOR (18)");
92
+ (0, globals_1.expect)(() => (0, ctap_model_1.unpackRequest)(request)).toThrow("CTAP error: CTAP2_ERR_INVALID_CBOR (18)");
94
93
  });
95
94
  });
@@ -343,7 +343,7 @@ const webauthn_test_server_1 = require("./webauthn-test-server");
343
343
  const emulator = new src_1.default();
344
344
  // Origin is different from the RP ID
345
345
  const testServer = new webauthn_test_server_1.WebAuthnTestServer("https://test-rp.com", "test-rp2.com");
346
- const relatedOrigins = ["https://test-rp1.com", "https://test-rp2.com", "https://test-rp3.com"];
346
+ const relatedOrigins = ["https://test-rp-a.com", "https://test-rp-b.com", "https://test-rp.com"];
347
347
  // Register a credential
348
348
  const regOptions = await testServer.getRegistrationOptions(user);
349
349
  const credential = emulator.createJSON(testServer.origin, regOptions, relatedOrigins);
@@ -345,7 +345,7 @@ function getAssertion(rpIdHash, clientDataHash, newSignCounter, credential, inte
345
345
  },
346
346
  signCount: newSignCounter,
347
347
  };
348
- const payload = new Array();
348
+ const payload = [];
349
349
  payload.push(...(0, webauthn_model_1.packAuthenticatorData)(authenticatorData));
350
350
  payload.push(...clientDataHash);
351
351
  const privateKey = (0, node_crypto_1.createPrivateKey)({
@@ -128,15 +128,15 @@ function packMakeCredentialRequest(request) {
128
128
  return {
129
129
  command: CTAP_COMMAND.authenticatorMakeCredential,
130
130
  data: encode_utils_1.default.encodeCbor({
131
- [0x01]: request.clientDataHash,
132
- [0x02]: request.rp,
133
- [0x03]: request.user,
134
- [0x04]: request.pubKeyCredParams,
135
- [0x05]: request.excludeList,
136
- [0x06]: request.extensions,
137
- [0x07]: request.options,
138
- [0x08]: request.pinAuth,
139
- [0x09]: request.pinProtocol,
131
+ "1": request.clientDataHash,
132
+ "2": request.rp,
133
+ "3": request.user,
134
+ "4": request.pubKeyCredParams,
135
+ "5": request.excludeList,
136
+ "6": request.extensions,
137
+ "7": request.options,
138
+ "8": request.pinAuth,
139
+ "9": request.pinProtocol,
140
140
  }),
141
141
  };
142
142
  }
@@ -144,13 +144,13 @@ function packGetAssertionRequest(request) {
144
144
  return {
145
145
  command: CTAP_COMMAND.authenticatorGetAssertion,
146
146
  data: encode_utils_1.default.encodeCbor({
147
- [0x01]: request.rpId,
148
- [0x02]: request.clientDataHash,
149
- [0x03]: request.allowList,
150
- [0x04]: request.extensions,
151
- [0x05]: request.options,
152
- [0x06]: request.pinAuth,
153
- [0x07]: request.pinProtocol,
147
+ "1": request.rpId,
148
+ "2": request.clientDataHash,
149
+ "3": request.allowList,
150
+ "4": request.extensions,
151
+ "5": request.options,
152
+ "6": request.pinAuth,
153
+ "7": request.pinProtocol,
154
154
  }),
155
155
  };
156
156
  }
@@ -158,16 +158,16 @@ function packCredentialManagementRequest(request) {
158
158
  return {
159
159
  command: CTAP_COMMAND.authenticatorCredentialManagement,
160
160
  data: encode_utils_1.default.encodeCbor({
161
- [0x01]: request.subCommand,
162
- [0x02]: request.subCommandParams
161
+ "1": request.subCommand,
162
+ "2": request.subCommandParams
163
163
  ? {
164
- [0x01]: request.subCommandParams.credentialId,
165
- [0x02]: request.subCommandParams.rpId,
166
- [0x03]: request.subCommandParams.user,
164
+ "1": request.subCommandParams.credentialId,
165
+ "2": request.subCommandParams.rpId,
166
+ "3": request.subCommandParams.user,
167
167
  }
168
168
  : undefined,
169
- [0x03]: request.pinUvAuthProtocol,
170
- [0x04]: request.pinUvAuthParam,
169
+ "3": request.pinUvAuthProtocol,
170
+ "4": request.pinUvAuthParam,
171
171
  }),
172
172
  };
173
173
  }
@@ -211,9 +211,9 @@ function packMakeCredentialResponse(response) {
211
211
  return {
212
212
  status: CTAP_STATUS_CODE.CTAP2_OK,
213
213
  data: encode_utils_1.default.encodeCbor({
214
- [0x01]: response.fmt,
215
- [0x02]: response.authData,
216
- [0x03]: response.attStmt,
214
+ "1": response.fmt,
215
+ "2": response.authData,
216
+ "3": response.attStmt,
217
217
  }),
218
218
  };
219
219
  }
@@ -236,11 +236,11 @@ function packGetAssertionResponse(response) {
236
236
  return {
237
237
  status: CTAP_STATUS_CODE.CTAP2_OK,
238
238
  data: encode_utils_1.default.encodeCbor({
239
- [0x01]: response.credential,
240
- [0x02]: response.authData,
241
- [0x03]: response.signature,
242
- [0x04]: response.user,
243
- [0x05]: response.numberOfCredentials,
239
+ "1": response.credential,
240
+ "2": response.authData,
241
+ "3": response.signature,
242
+ "4": response.user,
243
+ "5": response.numberOfCredentials,
244
244
  }),
245
245
  };
246
246
  }
@@ -264,12 +264,12 @@ function packGetInfoResponse(response) {
264
264
  return {
265
265
  status: CTAP_STATUS_CODE.CTAP2_OK,
266
266
  data: encode_utils_1.default.encodeCbor({
267
- [0x01]: response.versions,
268
- [0x02]: response.extensions,
269
- [0x03]: response.aaguid,
270
- [0x04]: response.options,
271
- [0x05]: response.maxMsgSize,
272
- [0x06]: response.pinProtocols,
267
+ "1": response.versions,
268
+ "2": response.extensions,
269
+ "3": response.aaguid,
270
+ "4": response.options,
271
+ "5": response.maxMsgSize,
272
+ "6": response.pinProtocols,
273
273
  }),
274
274
  };
275
275
  }
@@ -277,17 +277,17 @@ function packCredentialManagementResponse(response) {
277
277
  return {
278
278
  status: CTAP_STATUS_CODE.CTAP2_OK,
279
279
  data: encode_utils_1.default.encodeCbor({
280
- [0x01]: response.existingResidentCredentialsCount,
281
- [0x02]: response.maxPossibleRemainingResidentCredentialsCount,
282
- [0x03]: response.rp,
283
- [0x04]: response.rpIDHash,
284
- [0x05]: response.totalRPs,
285
- [0x06]: response.user,
286
- [0x07]: response.credentialID,
287
- [0x08]: response.publicKey,
288
- [0x09]: response.totalCredentials,
289
- [0x0a]: response.credProtect,
290
- [0x0b]: response.largeBlobKey,
280
+ "1": response.existingResidentCredentialsCount,
281
+ "2": response.maxPossibleRemainingResidentCredentialsCount,
282
+ "3": response.rp,
283
+ "4": response.rpIDHash,
284
+ "5": response.totalRPs,
285
+ "6": response.user,
286
+ "7": response.credentialID,
287
+ "8": response.publicKey,
288
+ "9": response.totalCredentials,
289
+ "10": response.credProtect,
290
+ "11": response.largeBlobKey,
291
291
  }),
292
292
  };
293
293
  }
@@ -1,14 +1,14 @@
1
1
  import { WebAuthnEmulator } from "./webauthn/webauthn-emulator";
2
2
  export default WebAuthnEmulator;
3
- export * from "./webauthn/webauthn-model-json";
4
- export * from "./webauthn/webauthn-model";
5
- export * from "./webauthn/webauthn-emulator";
6
- export * from "./webauthn/cose-key";
7
3
  export * from "./authenticator/authenticator-emulator";
8
4
  export * from "./authenticator/ctap-model";
9
- export * from "./repository/credentials-repository";
10
5
  export * from "./repository/credentials-file-repository";
11
6
  export * from "./repository/credentials-memory-repository";
7
+ export * from "./repository/credentials-repository";
8
+ export * from "./webauthn/cose-key";
9
+ export * from "./webauthn/webauthn-emulator";
10
+ export * from "./webauthn/webauthn-model";
11
+ export * from "./webauthn/webauthn-model-json";
12
12
  export declare const BrowserInjection: {
13
13
  WebAuthnEmulatorGet: string;
14
14
  WebAuthnEmulatorCreate: string;
package/dist/src/index.js CHANGED
@@ -18,15 +18,15 @@ exports.BrowserInjection = void 0;
18
18
  const browser_injection_1 = require("./test-utils/browser-injection");
19
19
  const webauthn_emulator_1 = require("./webauthn/webauthn-emulator");
20
20
  exports.default = webauthn_emulator_1.WebAuthnEmulator;
21
- __exportStar(require("./webauthn/webauthn-model-json"), exports);
22
- __exportStar(require("./webauthn/webauthn-model"), exports);
23
- __exportStar(require("./webauthn/webauthn-emulator"), exports);
24
- __exportStar(require("./webauthn/cose-key"), exports);
25
21
  __exportStar(require("./authenticator/authenticator-emulator"), exports);
26
22
  __exportStar(require("./authenticator/ctap-model"), exports);
27
- __exportStar(require("./repository/credentials-repository"), exports);
28
23
  __exportStar(require("./repository/credentials-file-repository"), exports);
29
24
  __exportStar(require("./repository/credentials-memory-repository"), exports);
25
+ __exportStar(require("./repository/credentials-repository"), exports);
26
+ __exportStar(require("./webauthn/cose-key"), exports);
27
+ __exportStar(require("./webauthn/webauthn-emulator"), exports);
28
+ __exportStar(require("./webauthn/webauthn-model"), exports);
29
+ __exportStar(require("./webauthn/webauthn-model-json"), exports);
30
30
  exports.BrowserInjection = {
31
31
  WebAuthnEmulatorGet: browser_injection_1.WebAuthnEmulatorGet,
32
32
  WebAuthnEmulatorCreate: browser_injection_1.WebAuthnEmulatorCreate,
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WebAuthnEmulator = exports.InvalidRpIdError = exports.NoPublicKeyError = exports.WebAuthnEmulatorError = void 0;
7
- const authenticator_emulator_1 = require("../authenticator/authenticator-emulator");
8
- const encode_utils_1 = __importDefault(require("../libs/encode-utils"));
9
- const webauthn_model_json_1 = require("./webauthn-model-json");
10
7
  const node_crypto_1 = require("node:crypto");
8
+ const authenticator_emulator_1 = require("../authenticator/authenticator-emulator");
11
9
  const ctap_model_1 = require("../authenticator/ctap-model");
10
+ const encode_utils_1 = __importDefault(require("../libs/encode-utils"));
12
11
  const webauthn_model_1 = require("./webauthn-model");
12
+ const webauthn_model_json_1 = require("./webauthn-model-json");
13
13
  class WebAuthnEmulatorError extends Error {
14
14
  }
15
15
  exports.WebAuthnEmulatorError = WebAuthnEmulatorError;
@@ -184,7 +184,7 @@ class WebAuthnEmulator {
184
184
  };
185
185
  const clientDataJSON = JSON.stringify(clientData);
186
186
  const authenticatorRequest = (0, ctap_model_1.packMakeCredentialRequest)({
187
- clientDataHash: (0, node_crypto_1.createHash)("sha256").update(clientDataJSON).digest(),
187
+ clientDataHash: encode_utils_1.default.bufferSourceToUint8Array((0, node_crypto_1.createHash)("sha256").update(clientDataJSON).digest()),
188
188
  rp: { name: options.publicKey.rp.name, id: rpId.value },
189
189
  user: options.publicKey.user,
190
190
  pubKeyCredParams: options.publicKey.pubKeyCredParams,
@@ -26,17 +26,16 @@ class RpId {
26
26
  }
27
27
  /** @see https://www.w3.org/TR/webauthn-3/#sctn-validating-origin */
28
28
  validate(origin, relatedOrigins = []) {
29
- // Create a list of all origins to check (main origin plus related origins)
30
- const originsToCheck = [origin, ...relatedOrigins];
31
- const parsedRpId = (0, tldts_1.parse)(this.value, { validHosts: ["localhost"] });
29
+ const parsedOrigin = (0, tldts_1.parse)(origin, { validHosts: ["localhost"] });
30
+ const expectedOrigins = [this.value, ...relatedOrigins];
32
31
  // Check each origin using standard validation
33
- for (const currentOrigin of originsToCheck) {
34
- const parsedOrigin = (0, tldts_1.parse)(currentOrigin, { validHosts: ["localhost"] });
32
+ for (const expectedOrigin of expectedOrigins) {
33
+ const parsedExpectedOrigin = (0, tldts_1.parse)(expectedOrigin, { validHosts: ["localhost"] });
35
34
  const isValid = Boolean(parsedOrigin.domain &&
36
35
  parsedOrigin.subdomain !== null &&
37
- parsedRpId.subdomain !== null &&
38
- parsedOrigin.domain === parsedRpId.domain &&
39
- parsedOrigin.subdomain.endsWith(parsedRpId.subdomain));
36
+ parsedExpectedOrigin.subdomain !== null &&
37
+ parsedOrigin.domain === parsedExpectedOrigin.domain &&
38
+ parsedOrigin.subdomain.endsWith(parsedExpectedOrigin.subdomain));
40
39
  if (isValid) {
41
40
  return true;
42
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nid-webauthn-emulator",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "keywords": [
5
5
  "test",
6
6
  "e2e",
@@ -15,19 +15,19 @@
15
15
  "main": "dist/src/index.js",
16
16
  "types": "dist/src/index.d.ts",
17
17
  "devDependencies": {
18
- "@biomejs/biome": "^1.9.4",
19
- "@jest/globals": "^29.7.0",
20
- "@simplewebauthn/server": "^13.1.1",
21
- "@tsconfig/recommended": "^1.0.8",
22
- "@types/node": "^22.15.17",
23
- "jest": "^29.7.0",
24
- "ts-jest": "^29.3.2",
18
+ "@biomejs/biome": "^2.1.2",
19
+ "@jest/globals": "^30.0.4",
20
+ "@simplewebauthn/server": "^13.1.2",
21
+ "@tsconfig/recommended": "^1.0.10",
22
+ "@types/node": "^24.2.0",
23
+ "jest": "^30.0.5",
24
+ "ts-jest": "^29.4.1",
25
25
  "ts-node": "^10.9.2",
26
26
  "typescript": "^5.8.3"
27
27
  },
28
28
  "dependencies": {
29
- "cbor": "^10.0.3",
30
- "tldts": "^7.0.7"
29
+ "cbor": "^10.0.10",
30
+ "tldts": "^7.0.10"
31
31
  },
32
32
  "scripts": {
33
33
  "check": "biome check .",