nid-webauthn-emulator 0.2.13 → 0.2.15

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 (36) hide show
  1. package/README.ja.md +10 -1
  2. package/README.md +10 -1
  3. package/dist/spec/authenticator/authenticator-emulator.spec.js +213 -65
  4. package/dist/spec/authenticator/ctap-model.spec.js +58 -53
  5. package/dist/spec/integration/integration.spec.js +7 -4
  6. package/dist/spec/integration/passkeys-api-client.d.ts +0 -1
  7. package/dist/spec/integration/webauthn-io.d.ts +0 -1
  8. package/dist/spec/libs/browser-injection.spec.js +55 -7
  9. package/dist/spec/libs/cbor.spec.js +57 -35
  10. package/dist/spec/libs/cose-key.spec.js +46 -40
  11. package/dist/spec/repository/credential-repository.spec.js +13 -12
  12. package/dist/spec/test-utils/unit-test.spec.js +28 -27
  13. package/dist/spec/webauthn/cose-key.spec.js +18 -17
  14. package/dist/spec/webauthn/webauthn-emulator.spec.js +376 -137
  15. package/dist/spec/webauthn/webauthn-model-json.spec.js +87 -42
  16. package/dist/spec/webauthn/webauthn-model.spec.js +59 -17
  17. package/dist/spec/webauthn/webauthn-test-server.d.ts +0 -1
  18. package/dist/spec/webauthn/webauthn-test-server.js +2 -2
  19. package/dist/src/authenticator/authenticator-emulator.d.ts +3 -0
  20. package/dist/src/authenticator/authenticator-emulator.js +71 -8
  21. package/dist/src/libs/cbor.d.ts +4 -0
  22. package/dist/src/libs/cbor.js +9 -0
  23. package/dist/src/libs/encode-utils.d.ts +2 -1
  24. package/dist/src/libs/encode-utils.js +1 -0
  25. package/dist/src/repository/credentials-file-repository.js +2 -1
  26. package/dist/src/repository/credentials-repository.d.ts +0 -1
  27. package/dist/src/test-utils/unit-test.d.ts +7 -5
  28. package/dist/src/webauthn/cose-key.d.ts +1 -0
  29. package/dist/src/webauthn/cose-key.js +6 -16
  30. package/dist/src/webauthn/webauthn-emulator.d.ts +4 -4
  31. package/dist/src/webauthn/webauthn-emulator.js +100 -3
  32. package/dist/src/webauthn/webauthn-model-json.d.ts +7 -94
  33. package/dist/src/webauthn/webauthn-model-json.js +90 -9
  34. package/dist/src/webauthn/webauthn-model.d.ts +2 -0
  35. package/dist/src/webauthn/webauthn-model.js +28 -7
  36. package/package.json +7 -10
@@ -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
@@ -1,9 +1,16 @@
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");
8
+ const authenticator_emulator_1 = require("../../src/authenticator/authenticator-emulator");
9
+ const encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
4
10
  const browser_injection_1 = require("../../src/test-utils/browser-injection");
5
- (0, globals_1.describe)("Browser Injection Test", () => {
6
- (0, globals_1.test)("Browser Injection Test", async () => {
11
+ const webauthn_emulator_1 = require("../../src/webauthn/webauthn-emulator");
12
+ (0, node_test_1.describe)("Browser Injection Test", () => {
13
+ (0, node_test_1.test)("Browser Injection Test", async () => {
7
14
  const window = { navigator: { credentials: { create: undefined, get: undefined } } };
8
15
  const PublicKeyCredential = {
9
16
  isConditionalMediationAvailable: async () => false,
@@ -11,9 +18,50 @@ const browser_injection_1 = require("../../src/test-utils/browser-injection");
11
18
  };
12
19
  // biome-ignore lint/security/noGlobalEval: This is a test code.
13
20
  eval(browser_injection_1.HookWebAuthnApis);
14
- (0, globals_1.expect)(await PublicKeyCredential.isConditionalMediationAvailable()).toBeTruthy();
15
- (0, globals_1.expect)(window.navigator.credentials.create).toBeDefined();
16
- (0, globals_1.expect)(window.navigator.credentials.get).toBeDefined();
17
- (0, globals_1.expect)(PublicKeyCredential.signalUnknownCredential).toBeDefined();
21
+ strict_1.default.ok(await PublicKeyCredential.isConditionalMediationAvailable());
22
+ strict_1.default.notEqual(window.navigator.credentials.create, undefined);
23
+ strict_1.default.notEqual(window.navigator.credentials.get, undefined);
24
+ strict_1.default.notEqual(PublicKeyCredential.signalUnknownCredential, undefined);
25
+ });
26
+ // The hooked create/get run in-page, so every helper they reach must be exported.
27
+ (0, node_test_1.test)("hooked create and get round-trip prf through the emulator", async () => {
28
+ const origin = "https://test-rp.org";
29
+ const emulator = new webauthn_emulator_1.WebAuthnEmulator(new authenticator_emulator_1.AuthenticatorEmulator({ hmacSecret: "hmac-secret-mc" }));
30
+ const window = {
31
+ navigator: { credentials: { create: undefined, get: undefined } },
32
+ webAuthnEmulatorCreate: async (optionsJSON) => emulator.createJSON(origin, optionsJSON),
33
+ webAuthnEmulatorGet: async (optionsJSON) => emulator.getJSON(origin, optionsJSON),
34
+ };
35
+ const PublicKeyCredential = { isConditionalMediationAvailable: async () => false };
36
+ // biome-ignore lint/security/noGlobalEval: This is a test code.
37
+ eval(browser_injection_1.HookWebAuthnApis);
38
+ strict_1.default.ok(await PublicKeyCredential.isConditionalMediationAvailable());
39
+ const first = encode_utils_1.default.strToUint8Array("prf-input-first");
40
+ const create = window.navigator.credentials.create;
41
+ strict_1.default.ok(create);
42
+ const created = await create({
43
+ publicKey: {
44
+ rp: { id: "test-rp.org", name: "rp" },
45
+ user: { id: encode_utils_1.default.strToUint8Array("user"), name: "user", displayName: "user" },
46
+ challenge: encode_utils_1.default.strToUint8Array("challenge"),
47
+ pubKeyCredParams: [{ alg: -7, type: "public-key" }],
48
+ extensions: { prf: { eval: { first } } },
49
+ },
50
+ });
51
+ const createdPrf = created.getClientExtensionResults().prf?.results?.first;
52
+ strict_1.default.ok(createdPrf instanceof ArrayBuffer);
53
+ strict_1.default.equal(createdPrf.byteLength, 32);
54
+ const get = window.navigator.credentials.get;
55
+ strict_1.default.ok(get);
56
+ const asserted = await get({
57
+ publicKey: {
58
+ rpId: "test-rp.org",
59
+ challenge: encode_utils_1.default.strToUint8Array("challenge-2"),
60
+ extensions: { prf: { eval: { first } } },
61
+ },
62
+ });
63
+ const assertedPrf = asserted.getClientExtensionResults().prf?.results?.first;
64
+ strict_1.default.ok(assertedPrf instanceof ArrayBuffer);
65
+ strict_1.default.deepEqual(new Uint8Array(assertedPrf), new Uint8Array(createdPrf));
18
66
  });
19
67
  });
@@ -3,21 +3,22 @@ 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 encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
8
- (0, globals_1.describe)("CBOR encode/decode edge cases", () => {
9
- (0, globals_1.test)("round-trips primitive values and large integer encodings", () => {
9
+ (0, node_test_1.describe)("CBOR encode/decode edge cases", () => {
10
+ (0, node_test_1.test)("round-trips primitive values and large integer encodings", () => {
10
11
  const encoded = encode_utils_1.default.encodeCbor({
11
12
  1: "one",
12
13
  nil: null,
13
14
  values: [false, true, undefined, -2, 24, 0x100, 0x1_0000, 0x1_0000_0000],
14
15
  });
15
16
  const decoded = encode_utils_1.default.decodeCbor(encoded);
16
- (0, globals_1.expect)(decoded[1]).toBe("one");
17
- (0, globals_1.expect)(decoded.nil).toBeNull();
18
- (0, globals_1.expect)(decoded.values).toEqual([false, true, undefined, -2, 24, 0x100, 0x1_0000, 0x1_0000_0000]);
17
+ strict_1.default.equal(decoded[1], "one");
18
+ strict_1.default.equal(decoded.nil, null);
19
+ strict_1.default.deepEqual(decoded.values, [false, true, undefined, -2, 24, 0x100, 0x1_0000, 0x1_0000_0000]);
19
20
  });
20
- (0, globals_1.test)("handles ArrayBuffer values within objects and arrays", () => {
21
+ (0, node_test_1.test)("handles ArrayBuffer values within objects and arrays", () => {
21
22
  const ab = new Uint8Array([1, 2, 3]).buffer; // ArrayBuffer branch
22
23
  const ua = new Uint8Array([4, 5]);
23
24
  const obj = {
@@ -28,49 +29,70 @@ const encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
28
29
  const encoded = encode_utils_1.default.encodeCbor(obj);
29
30
  const decoded = encode_utils_1.default.decodeCbor(encoded);
30
31
  // ArrayBuffer is decoded back to Uint8Array
31
- (0, globals_1.expect)(decoded.v1).toBeInstanceOf(Uint8Array);
32
- (0, globals_1.expect)(Array.from(decoded.v1)).toEqual([1, 2, 3]);
32
+ strict_1.default.ok(decoded.v1 instanceof Uint8Array);
33
+ strict_1.default.deepEqual(Array.from(decoded.v1), [1, 2, 3]);
33
34
  // Existing Uint8Array round-trips
34
- (0, globals_1.expect)(Array.from(decoded.v2)).toEqual([4, 5]);
35
+ strict_1.default.deepEqual(Array.from(decoded.v2), [4, 5]);
35
36
  // Mixed array elements preserved as Uint8Array
36
- (0, globals_1.expect)(Array.isArray(decoded.arr)).toBe(true);
37
+ strict_1.default.equal(Array.isArray(decoded.arr), true);
37
38
  const [a0, a1] = decoded.arr;
38
- (0, globals_1.expect)(Array.from(a0)).toEqual([1, 2, 3]);
39
- (0, globals_1.expect)(Array.from(a1)).toEqual([4, 5]);
39
+ strict_1.default.deepEqual(Array.from(a0), [1, 2, 3]);
40
+ strict_1.default.deepEqual(Array.from(a1), [4, 5]);
40
41
  });
41
- (0, globals_1.test)("handles Buffer values without conversion in encoder and to Uint8Array on decode", () => {
42
+ (0, node_test_1.test)("handles Buffer values without conversion in encoder and to Uint8Array on decode", () => {
42
43
  const buf = Buffer.from([9, 8]);
43
44
  const obj = { b: buf };
44
45
  const encoded = encode_utils_1.default.encodeCbor(obj);
45
46
  const decoded = encode_utils_1.default.decodeCbor(encoded);
46
- (0, globals_1.expect)(decoded.b).toBeInstanceOf(Uint8Array);
47
- (0, globals_1.expect)(Array.from(decoded.b)).toEqual([9, 8]);
47
+ strict_1.default.ok(decoded.b instanceof Uint8Array);
48
+ strict_1.default.deepEqual(Array.from(decoded.b), [9, 8]);
48
49
  });
49
- (0, globals_1.test)("keeps non-exact integer object keys as text string map keys", () => {
50
+ (0, node_test_1.test)("keeps non-exact integer object keys as text string map keys", () => {
50
51
  const decoded = encode_utils_1.default.decodeCbor(encode_utils_1.default.encodeCbor({
51
52
  "1": false,
52
53
  "01": true,
53
54
  "1abc": true,
54
55
  }));
55
- (0, globals_1.expect)(decoded[1]).toBe(false);
56
- (0, globals_1.expect)(decoded["01"]).toBe(true);
57
- (0, globals_1.expect)(decoded["1abc"]).toBe(true);
56
+ strict_1.default.equal(decoded[1], false);
57
+ strict_1.default.equal(decoded["01"], true);
58
+ strict_1.default.equal(decoded["1abc"], true);
58
59
  });
59
- (0, globals_1.test)("decodes explicit integer widths", () => {
60
- (0, globals_1.expect)(encode_utils_1.default.decodeCbor(new Uint8Array([0x1a, 0x00, 0x01, 0x00, 0x00]))).toBe(0x1_0000);
61
- (0, globals_1.expect)(encode_utils_1.default.decodeCbor(new Uint8Array([0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]))).toBe(0x1_0000_0000);
62
- (0, globals_1.expect)(encode_utils_1.default.decodeCbor(new Uint8Array([0xf6]))).toBeNull();
60
+ (0, node_test_1.test)("decodes explicit integer widths", () => {
61
+ strict_1.default.equal(encode_utils_1.default.decodeCbor(new Uint8Array([0x1a, 0x00, 0x01, 0x00, 0x00])), 0x1_0000);
62
+ strict_1.default.equal(encode_utils_1.default.decodeCbor(new Uint8Array([0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00])), 0x1_0000_0000);
63
+ strict_1.default.equal(encode_utils_1.default.decodeCbor(new Uint8Array([0xf6])), null);
63
64
  });
64
- (0, globals_1.test)("rejects unsupported values and malformed input", () => {
65
- (0, globals_1.expect)(() => encode_utils_1.default.encodeCbor(Symbol("unsupported"))).toThrow("Unsupported CBOR value type: symbol");
66
- (0, globals_1.expect)(() => encode_utils_1.default.encodeCbor({ value: Number.NaN })).toThrow("CBOR only supports safe integers");
67
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array())).toThrow("Insufficient data");
68
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x42, 0x01]))).toThrow("Insufficient data");
69
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x5f]))).toThrow("Unsupported indefinite-length CBOR data");
70
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x01, 0x02]))).toThrow("Unexpected trailing CBOR data");
71
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xc1, 0x01]))).toThrow("Unsupported CBOR tagged value");
72
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xf8]))).toThrow("Unsupported CBOR simple value: 24");
73
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xa1, 0x41, 0x01, 0x01]))).toThrow("Unsupported CBOR map key type");
74
- (0, globals_1.expect)(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x1b, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))).toThrow("CBOR integer exceeds JavaScript safe integer range");
65
+ (0, node_test_1.test)("decodeCborWithRemainder returns the first value and trailing bytes", () => {
66
+ const first = encode_utils_1.default.encodeCbor({ 1: "a", [-2]: new Uint8Array([9, 9]) });
67
+ const second = encode_utils_1.default.encodeCbor({ 2: "b" });
68
+ const combined = new Uint8Array([...first, ...second]);
69
+ const { value, remainder } = encode_utils_1.default.decodeCborWithRemainder(combined);
70
+ strict_1.default.equal(value[1], "a");
71
+ strict_1.default.deepEqual(value[-2], new Uint8Array([9, 9]));
72
+ strict_1.default.deepEqual(remainder, second);
73
+ });
74
+ (0, node_test_1.test)("rejects unsupported values and malformed input", () => {
75
+ strict_1.default.throws(() => encode_utils_1.default.encodeCbor(Symbol("unsupported")), {
76
+ message: "Unsupported CBOR value type: symbol",
77
+ });
78
+ strict_1.default.throws(() => encode_utils_1.default.encodeCbor({ value: Number.NaN }), { message: "CBOR only supports safe integers" });
79
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array()), { message: "Insufficient data" });
80
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x42, 0x01])), { message: "Insufficient data" });
81
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x5f])), {
82
+ message: "Unsupported indefinite-length CBOR data",
83
+ });
84
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x01, 0x02])), {
85
+ message: "Unexpected trailing CBOR data",
86
+ });
87
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xc1, 0x01])), {
88
+ message: "Unsupported CBOR tagged value",
89
+ });
90
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xf8])), {
91
+ message: "Unsupported CBOR simple value: 24",
92
+ });
93
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0xa1, 0x41, 0x01, 0x01])), {
94
+ message: "Unsupported CBOR map key type",
95
+ });
96
+ strict_1.default.throws(() => encode_utils_1.default.decodeCbor(new Uint8Array([0x1b, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), { message: "CBOR integer exceeds JavaScript safe integer range" });
75
97
  });
76
98
  });
@@ -1,47 +1,53 @@
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 authenticator_emulator_1 = require("../../src/authenticator/authenticator-emulator");
5
9
  const cose_key_1 = require("../../src/webauthn/cose-key");
6
10
  const webauthn_model_1 = require("../../src/webauthn/webauthn-model");
7
- globals_1.describe.each([-7, -8, -257])("CoseKey Test: %s", (alg) => {
8
- const getKey = () => {
9
- const authenticator = new authenticator_emulator_1.AuthenticatorEmulator();
10
- const rpId = new webauthn_model_1.RpId("example.com");
11
- const userHandle = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
12
- const credential = authenticator.authenticatorMakeCredential({
13
- rp: { id: rpId.value, name: "example" },
14
- user: { id: userHandle, name: "example", displayName: "example" },
15
- pubKeyCredParams: [{ alg, type: "public-key" }],
16
- clientDataHash: new Uint8Array(32),
11
+ for (const alg of [-7, -8, -257]) {
12
+ (0, node_test_1.describe)(`CoseKey Test: ${alg}`, () => {
13
+ const getKey = () => {
14
+ const authenticator = new authenticator_emulator_1.AuthenticatorEmulator();
15
+ const rpId = new webauthn_model_1.RpId("example.com");
16
+ const userHandle = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
17
+ const credential = authenticator.authenticatorMakeCredential({
18
+ rp: { id: rpId.value, name: "example" },
19
+ user: { id: userHandle, name: "example", displayName: "example" },
20
+ pubKeyCredParams: [{ alg, type: "public-key" }],
21
+ clientDataHash: new Uint8Array(32),
22
+ });
23
+ return (0, webauthn_model_1.unpackAuthenticatorData)(credential.authData).attestedCredentialData?.credentialPublicKey;
24
+ };
25
+ (0, node_test_1.test)("Der format _ serialize and deserialize test", async () => {
26
+ const testCoseKey = getKey();
27
+ const serialized = testCoseKey.toDer();
28
+ const deserialized = cose_key_1.CoseKey.fromDer(testCoseKey.toDer());
29
+ const reSerialized = deserialized.toDer();
30
+ strict_1.default.deepEqual(testCoseKey.alg, alg);
31
+ strict_1.default.deepEqual(testCoseKey, deserialized);
32
+ strict_1.default.deepEqual(serialized, reSerialized);
33
+ });
34
+ (0, node_test_1.test)("Jwk format _ serialize and deserialize test", async () => {
35
+ const testCoseKey = getKey();
36
+ const serialized = testCoseKey.toJwk();
37
+ const deserialized = cose_key_1.CoseKey.fromJwk(testCoseKey.toJwk()).toJwk();
38
+ const reSerialized = cose_key_1.CoseKey.fromJwk(deserialized).toJwk();
39
+ strict_1.default.deepEqual(testCoseKey.alg, alg);
40
+ strict_1.default.deepEqual(serialized, deserialized);
41
+ strict_1.default.deepEqual(serialized, reSerialized);
42
+ });
43
+ (0, node_test_1.test)("KeyObject format _ serialize and deserialize test", async () => {
44
+ const testCoseKey = getKey();
45
+ const serialized = testCoseKey.toKeyObject();
46
+ const deserialized = cose_key_1.CoseKey.fromKeyObject(testCoseKey.toKeyObject()).toKeyObject();
47
+ const reSerialized = cose_key_1.CoseKey.fromKeyObject(deserialized).toKeyObject();
48
+ strict_1.default.deepEqual(testCoseKey.alg, alg);
49
+ strict_1.default.deepEqual(serialized, deserialized);
50
+ strict_1.default.deepEqual(serialized, reSerialized);
17
51
  });
18
- return (0, webauthn_model_1.unpackAuthenticatorData)(credential.authData).attestedCredentialData?.credentialPublicKey;
19
- };
20
- (0, globals_1.test)("Der format _ serialize and deserialize test", async () => {
21
- const testCoseKey = getKey();
22
- const serialized = testCoseKey.toDer();
23
- const deserialized = cose_key_1.CoseKey.fromDer(testCoseKey.toDer());
24
- const reSerialized = deserialized.toDer();
25
- (0, globals_1.expect)(testCoseKey.alg).toEqual(alg);
26
- (0, globals_1.expect)(testCoseKey).toEqual(deserialized);
27
- (0, globals_1.expect)(serialized).toEqual(reSerialized);
28
- });
29
- (0, globals_1.test)("Jwk format _ serialize and deserialize test", async () => {
30
- const testCoseKey = getKey();
31
- const serialized = testCoseKey.toJwk();
32
- const deserialized = cose_key_1.CoseKey.fromJwk(testCoseKey.toJwk()).toJwk();
33
- const reSerialized = cose_key_1.CoseKey.fromJwk(deserialized).toJwk();
34
- (0, globals_1.expect)(testCoseKey.alg).toEqual(alg);
35
- (0, globals_1.expect)(serialized).toEqual(deserialized);
36
- (0, globals_1.expect)(serialized).toEqual(reSerialized);
37
- });
38
- (0, globals_1.test)("KeyObject format _ serialize and deserialize test", async () => {
39
- const testCoseKey = getKey();
40
- const serialized = testCoseKey.toKeyObject();
41
- const deserialized = cose_key_1.CoseKey.fromKeyObject(testCoseKey.toKeyObject()).toKeyObject();
42
- const reSerialized = cose_key_1.CoseKey.fromKeyObject(deserialized).toKeyObject();
43
- (0, globals_1.expect)(testCoseKey.alg).toEqual(alg);
44
- (0, globals_1.expect)(serialized).toEqual(deserialized);
45
- (0, globals_1.expect)(serialized).toEqual(reSerialized);
46
52
  });
47
- });
53
+ }