nid-webauthn-emulator 0.2.11 → 0.2.13

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.
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const globals_1 = require("@jest/globals");
7
+ 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", () => {
10
+ const encoded = encode_utils_1.default.encodeCbor({
11
+ 1: "one",
12
+ nil: null,
13
+ values: [false, true, undefined, -2, 24, 0x100, 0x1_0000, 0x1_0000_0000],
14
+ });
15
+ 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]);
19
+ });
20
+ (0, globals_1.test)("handles ArrayBuffer values within objects and arrays", () => {
21
+ const ab = new Uint8Array([1, 2, 3]).buffer; // ArrayBuffer branch
22
+ const ua = new Uint8Array([4, 5]);
23
+ const obj = {
24
+ v1: ab,
25
+ v2: ua,
26
+ arr: [ab, ua],
27
+ };
28
+ const encoded = encode_utils_1.default.encodeCbor(obj);
29
+ const decoded = encode_utils_1.default.decodeCbor(encoded);
30
+ // 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]);
33
+ // Existing Uint8Array round-trips
34
+ (0, globals_1.expect)(Array.from(decoded.v2)).toEqual([4, 5]);
35
+ // Mixed array elements preserved as Uint8Array
36
+ (0, globals_1.expect)(Array.isArray(decoded.arr)).toBe(true);
37
+ 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]);
40
+ });
41
+ (0, globals_1.test)("handles Buffer values without conversion in encoder and to Uint8Array on decode", () => {
42
+ const buf = Buffer.from([9, 8]);
43
+ const obj = { b: buf };
44
+ const encoded = encode_utils_1.default.encodeCbor(obj);
45
+ 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]);
48
+ });
49
+ (0, globals_1.test)("keeps non-exact integer object keys as text string map keys", () => {
50
+ const decoded = encode_utils_1.default.decodeCbor(encode_utils_1.default.encodeCbor({
51
+ "1": false,
52
+ "01": true,
53
+ "1abc": true,
54
+ }));
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);
58
+ });
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();
63
+ });
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");
75
+ });
76
+ });
@@ -0,0 +1,2 @@
1
+ export declare function encodeCbor(data: object): Uint8Array<ArrayBuffer>;
2
+ export declare function decodeCbor<T>(data: Uint8Array<ArrayBuffer>): T;
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeCbor = encodeCbor;
4
+ exports.decodeCbor = decodeCbor;
5
+ function appendCborTypeAndLength(out, majorType, value) {
6
+ const prefix = majorType << 5;
7
+ if (value < 24) {
8
+ out.push(prefix | value);
9
+ return;
10
+ }
11
+ if (value <= 0xff) {
12
+ out.push(prefix | 24, value);
13
+ return;
14
+ }
15
+ if (value <= 0xffff) {
16
+ out.push(prefix | 25, value >> 8, value & 0xff);
17
+ return;
18
+ }
19
+ if (value <= 0xffffffff) {
20
+ out.push(prefix | 26, (value >>> 24) & 0xff, (value >>> 16) & 0xff, (value >>> 8) & 0xff, value & 0xff);
21
+ return;
22
+ }
23
+ const bigValue = BigInt(value);
24
+ out.push(prefix | 27);
25
+ for (let shift = 56n; shift >= 0n; shift -= 8n) {
26
+ out.push(Number((bigValue >> shift) & 0xffn));
27
+ }
28
+ }
29
+ function appendCborByteString(out, data) {
30
+ appendCborTypeAndLength(out, 2, data.byteLength);
31
+ out.push(...data);
32
+ }
33
+ function objectKeyToCborMapKey(key) {
34
+ const numberKey = Number(key);
35
+ return Number.isSafeInteger(numberKey) && String(numberKey) === key ? numberKey : key;
36
+ }
37
+ function appendCborValue(out, value) {
38
+ if (value instanceof Uint8Array) {
39
+ appendCborByteString(out, value);
40
+ return;
41
+ }
42
+ if (value instanceof ArrayBuffer) {
43
+ appendCborByteString(out, new Uint8Array(value));
44
+ return;
45
+ }
46
+ if (Array.isArray(value)) {
47
+ appendCborTypeAndLength(out, 4, value.length);
48
+ for (const item of value)
49
+ appendCborValue(out, item);
50
+ return;
51
+ }
52
+ switch (typeof value) {
53
+ case "number":
54
+ if (!Number.isSafeInteger(value))
55
+ throw new Error("CBOR only supports safe integers");
56
+ if (value >= 0) {
57
+ appendCborTypeAndLength(out, 0, value);
58
+ }
59
+ else {
60
+ appendCborTypeAndLength(out, 1, -1 - value);
61
+ }
62
+ return;
63
+ case "string": {
64
+ const encoded = new TextEncoder().encode(value);
65
+ appendCborTypeAndLength(out, 3, encoded.byteLength);
66
+ out.push(...encoded);
67
+ return;
68
+ }
69
+ case "boolean":
70
+ out.push(value ? 0xf5 : 0xf4);
71
+ return;
72
+ case "undefined":
73
+ out.push(0xf7);
74
+ return;
75
+ case "object":
76
+ if (value === null) {
77
+ out.push(0xf6);
78
+ return;
79
+ }
80
+ break;
81
+ default:
82
+ throw new Error(`Unsupported CBOR value type: ${typeof value}`);
83
+ }
84
+ const entries = Object.entries(value);
85
+ appendCborTypeAndLength(out, 5, entries.length);
86
+ for (const [k, v] of entries) {
87
+ appendCborValue(out, objectKeyToCborMapKey(k));
88
+ appendCborValue(out, v);
89
+ }
90
+ }
91
+ function encodeCbor(data) {
92
+ const out = [];
93
+ appendCborValue(out, data);
94
+ return new Uint8Array(out);
95
+ }
96
+ class CborReader {
97
+ data;
98
+ offset = 0;
99
+ textDecoder = new TextDecoder("utf-8", { fatal: true });
100
+ constructor(data) {
101
+ this.data = data;
102
+ }
103
+ read() {
104
+ const value = this.readValue();
105
+ if (this.offset !== this.data.byteLength) {
106
+ throw new Error("Unexpected trailing CBOR data");
107
+ }
108
+ return value;
109
+ }
110
+ readValue() {
111
+ const initialByte = this.readByte();
112
+ const majorType = initialByte >> 5;
113
+ const additionalInfo = initialByte & 0x1f;
114
+ switch (majorType) {
115
+ case 0:
116
+ return this.readLength(additionalInfo);
117
+ case 1:
118
+ return -1 - this.readLength(additionalInfo);
119
+ case 2:
120
+ return this.readByteString(this.readLength(additionalInfo));
121
+ case 3:
122
+ return this.readTextString(this.readLength(additionalInfo));
123
+ case 4:
124
+ return this.readArray(this.readLength(additionalInfo));
125
+ case 5:
126
+ return this.readMap(this.readLength(additionalInfo));
127
+ case 6:
128
+ throw new Error("Unsupported CBOR tagged value");
129
+ case 7:
130
+ return this.readSimpleValue(additionalInfo);
131
+ }
132
+ }
133
+ readByte() {
134
+ if (this.offset >= this.data.byteLength) {
135
+ throw new Error("Insufficient data");
136
+ }
137
+ return this.data[this.offset++];
138
+ }
139
+ readBytes(length) {
140
+ if (this.offset + length > this.data.byteLength) {
141
+ throw new Error("Insufficient data");
142
+ }
143
+ const bytes = this.data.slice(this.offset, this.offset + length);
144
+ this.offset += length;
145
+ return bytes;
146
+ }
147
+ readLength(additionalInfo) {
148
+ if (additionalInfo < 24)
149
+ return additionalInfo;
150
+ if (additionalInfo === 24)
151
+ return this.readByte();
152
+ if (additionalInfo === 25)
153
+ return (this.readByte() << 8) | this.readByte();
154
+ if (additionalInfo === 26) {
155
+ return this.readByte() * 0x1000000 + ((this.readByte() << 16) | (this.readByte() << 8) | this.readByte());
156
+ }
157
+ if (additionalInfo === 27) {
158
+ let value = 0n;
159
+ for (let i = 0; i < 8; i++) {
160
+ value = (value << 8n) | BigInt(this.readByte());
161
+ }
162
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
163
+ throw new Error("CBOR integer exceeds JavaScript safe integer range");
164
+ }
165
+ return Number(value);
166
+ }
167
+ throw new Error("Unsupported indefinite-length CBOR data");
168
+ }
169
+ readByteString(length) {
170
+ return this.readBytes(length);
171
+ }
172
+ readTextString(length) {
173
+ return this.textDecoder.decode(this.readBytes(length));
174
+ }
175
+ readArray(length) {
176
+ const values = [];
177
+ for (let i = 0; i < length; i++) {
178
+ values.push(this.readValue());
179
+ }
180
+ return values;
181
+ }
182
+ readMap(length) {
183
+ const value = {};
184
+ for (let i = 0; i < length; i++) {
185
+ const key = this.readValue();
186
+ if (typeof key !== "string" && typeof key !== "number") {
187
+ throw new Error("Unsupported CBOR map key type");
188
+ }
189
+ value[key] = this.readValue();
190
+ }
191
+ return value;
192
+ }
193
+ readSimpleValue(additionalInfo) {
194
+ switch (additionalInfo) {
195
+ case 20:
196
+ return false;
197
+ case 21:
198
+ return true;
199
+ case 22:
200
+ return null;
201
+ case 23:
202
+ return undefined;
203
+ default:
204
+ throw new Error(`Unsupported CBOR simple value: ${additionalInfo}`);
205
+ }
206
+ }
207
+ }
208
+ function decodeCbor(data) {
209
+ return new CborReader(data).read();
210
+ }
@@ -1,9 +1,8 @@
1
+ import { decodeCbor, encodeCbor } from "./cbor";
1
2
  declare function encodeBase64Url(data: BufferSource): string;
2
3
  declare function decodeBase64Url(base64Url: string): Uint8Array<ArrayBuffer>;
3
4
  declare function bufferSourceToUint8Array(data: BufferSource): Uint8Array<ArrayBuffer>;
4
5
  declare function strToUint8Array(data: string): Uint8Array<ArrayBuffer>;
5
- declare function encodeCbor(data: object): Uint8Array<ArrayBuffer>;
6
- declare function decodeCbor<T>(data: Uint8Array<ArrayBuffer>): T;
7
6
  declare const EncodeUtils: {
8
7
  strToUint8Array: typeof strToUint8Array;
9
8
  bufferSourceToUint8Array: typeof bufferSourceToUint8Array;
@@ -1,9 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const cbor_1 = __importDefault(require("cbor"));
3
+ const cbor_1 = require("./cbor");
7
4
  function encodeBase64Url(data) {
8
5
  const buffer = bufferSourceToUint8Array(data);
9
6
  let binaryString = "";
@@ -29,70 +26,12 @@ function bufferSourceToUint8Array(data) {
29
26
  function strToUint8Array(data) {
30
27
  return new Uint8Array(data.split("").map((c) => c.charCodeAt(0)));
31
28
  }
32
- function encodeCbor(data) {
33
- function encoder(value) {
34
- if (value instanceof Buffer) {
35
- return value;
36
- }
37
- if (value instanceof Uint8Array) {
38
- return Buffer.from(value);
39
- }
40
- if (value instanceof ArrayBuffer) {
41
- return Buffer.from(value);
42
- }
43
- if (Array.isArray(value)) {
44
- return value.map((v) => encoder(v));
45
- }
46
- if (typeof value === "object" && value !== null) {
47
- const encodedData = new Map();
48
- for (const [k, v] of Object.entries(value)) {
49
- const ki = Number.parseInt(k, 10);
50
- if (Number.isNaN(ki)) {
51
- encodedData.set(k, encoder(v));
52
- }
53
- else {
54
- encodedData.set(ki, encoder(v));
55
- }
56
- }
57
- return encodedData;
58
- }
59
- return value;
60
- }
61
- return new Uint8Array(cbor_1.default.encode(encoder(data)));
62
- }
63
- function decodeCbor(data) {
64
- const canonicalData = cbor_1.default.decode(data);
65
- function decoder(value) {
66
- if (value instanceof Buffer) {
67
- return new Uint8Array(value);
68
- }
69
- if (Array.isArray(value)) {
70
- return value.map((v) => decoder(v));
71
- }
72
- if (value instanceof Map) {
73
- const decodedData = {};
74
- for (const [k, v] of value) {
75
- Object.assign(decodedData, { [k]: decoder(v) });
76
- }
77
- return decodedData;
78
- }
79
- if (typeof value === "object" && value !== null) {
80
- const decodedData = {};
81
- for (const [k, v] of Object.entries(value)) {
82
- Object.assign(decodedData, { [k]: decoder(v) });
83
- }
84
- return decodedData;
85
- }
86
- return value;
87
- }
88
- return decoder(canonicalData);
89
- }
90
29
  const EncodeUtils = {
91
30
  strToUint8Array,
92
31
  bufferSourceToUint8Array,
93
32
  encodeBase64Url,
94
33
  decodeBase64Url,
95
- encodeCbor,
96
- decodeCbor,
34
+ encodeCbor: cbor_1.encodeCbor,
35
+ decodeCbor: cbor_1.decodeCbor,
97
36
  };
98
37
  exports.default = EncodeUtils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nid-webauthn-emulator",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "keywords": [
5
5
  "test",
6
6
  "e2e",
@@ -18,19 +18,18 @@
18
18
  "main": "dist/src/index.js",
19
19
  "types": "dist/src/index.d.ts",
20
20
  "devDependencies": {
21
- "@biomejs/biome": "^2.4.9",
22
- "@jest/globals": "^30.3.0",
23
- "@simplewebauthn/server": "^13.3.0",
24
- "@tsconfig/recommended": "^1.0.13",
25
- "@types/node": "^25.5.0",
26
- "jest": "^30.3.0",
27
- "ts-jest": "^29.4.6",
28
- "ts-node": "^10.9.2",
29
- "typescript": "^5.9.3"
21
+ "@biomejs/biome": "2.4.15",
22
+ "@jest/globals": "30.4.1",
23
+ "@simplewebauthn/server": "13.3.0",
24
+ "@tsconfig/recommended": "1.0.13",
25
+ "@types/node": "25.9.1",
26
+ "jest": "30.4.2",
27
+ "ts-jest": "29.4.11",
28
+ "ts-node": "10.9.2",
29
+ "typescript": "5.9.3"
30
30
  },
31
31
  "dependencies": {
32
- "cbor": "^10.0.12",
33
- "tldts": "^7.0.27"
32
+ "tldts": "7.1.2"
34
33
  },
35
34
  "scripts": {
36
35
  "check": "biome check .",
@@ -1,38 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const globals_1 = require("@jest/globals");
7
- const encode_utils_1 = __importDefault(require("../../src/libs/encode-utils"));
8
- (0, globals_1.describe)("EncodeUtils encodeCbor/decodeCbor edge cases", () => {
9
- (0, globals_1.test)("handles ArrayBuffer values within objects and arrays", () => {
10
- const ab = new Uint8Array([1, 2, 3]).buffer; // ArrayBuffer branch
11
- const ua = new Uint8Array([4, 5]);
12
- const obj = {
13
- v1: ab,
14
- v2: ua,
15
- arr: [ab, ua],
16
- };
17
- const encoded = encode_utils_1.default.encodeCbor(obj);
18
- const decoded = encode_utils_1.default.decodeCbor(encoded);
19
- // ArrayBuffer is decoded back to Uint8Array
20
- (0, globals_1.expect)(decoded.v1).toBeInstanceOf(Uint8Array);
21
- (0, globals_1.expect)(Array.from(decoded.v1)).toEqual([1, 2, 3]);
22
- // Existing Uint8Array round-trips
23
- (0, globals_1.expect)(Array.from(decoded.v2)).toEqual([4, 5]);
24
- // Mixed array elements preserved as Uint8Array
25
- (0, globals_1.expect)(Array.isArray(decoded.arr)).toBe(true);
26
- const [a0, a1] = decoded.arr;
27
- (0, globals_1.expect)(Array.from(a0)).toEqual([1, 2, 3]);
28
- (0, globals_1.expect)(Array.from(a1)).toEqual([4, 5]);
29
- });
30
- (0, globals_1.test)("handles Buffer values without conversion in encoder and to Uint8Array on decode", () => {
31
- const buf = Buffer.from([9, 8]);
32
- const obj = { b: buf };
33
- const encoded = encode_utils_1.default.encodeCbor(obj);
34
- const decoded = encode_utils_1.default.decodeCbor(encoded);
35
- (0, globals_1.expect)(decoded.b).toBeInstanceOf(Uint8Array);
36
- (0, globals_1.expect)(Array.from(decoded.b)).toEqual([9, 8]);
37
- });
38
- });