@revibase/ctap2-js 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"cborUtils.d.ts","sourceRoot":"","sources":["../../src/ctap2/cborUtils.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAoE7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAUzD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAa5D;AAED,wBAAgB,UAAU,CACzB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAClC,GAAG,EAAE,MAAM,GACT,OAAO,CAeT"}
1
+ {"version":3,"file":"cborUtils.d.ts","sourceRoot":"","sources":["../../src/ctap2/cborUtils.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAuD7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAUzD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAS5D;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAClC,GAAG,EAAE,MAAM,GACV,OAAO,CAeT"}
@@ -9,6 +9,7 @@ const cbor_x_1 = require("cbor-x");
9
9
  const ctapCborEncoder = new cbor_x_1.Encoder({
10
10
  useTag259ForMaps: false,
11
11
  useRecords: false,
12
+ variableMapSize: true,
12
13
  mapsAsObjects: true,
13
14
  structuredClone: false,
14
15
  tagUint8Array: false,
@@ -42,10 +43,7 @@ function canonicalizeCtapValue(value) {
42
43
  return value;
43
44
  }
44
45
  const t = typeof value;
45
- if (t === "boolean" ||
46
- t === "number" ||
47
- t === "string" ||
48
- t === "bigint") {
46
+ if (t === "boolean" || t === "number" || t === "string" || t === "bigint") {
49
47
  return value;
50
48
  }
51
49
  if (value instanceof Uint8Array) {
@@ -65,9 +63,7 @@ function canonicalizeCtapValue(value) {
65
63
  }
66
64
  const allNum = keys.every((k) => typeof k === "number");
67
65
  if (allNum) {
68
- const sorted = keys
69
- .slice()
70
- .sort((a, b) => a - b);
66
+ const sorted = keys.slice().sort((a, b) => a - b);
71
67
  const m = new Map();
72
68
  for (const k of sorted) {
73
69
  m.set(k, canonicalizeCtapValue(value.get(k)));
@@ -76,9 +72,7 @@ function canonicalizeCtapValue(value) {
76
72
  }
77
73
  const allStr = keys.every((k) => typeof k === "string");
78
74
  if (allStr) {
79
- const sorted = keys
80
- .slice()
81
- .sort(compareCtapTextMapKeys);
75
+ const sorted = keys.slice().sort(compareCtapTextMapKeys);
82
76
  const o = {};
83
77
  for (const k of sorted) {
84
78
  o[k] = canonicalizeCtapValue(value.get(k));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revibase/ctap2-js",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Passkeys over NFC directly",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -5,12 +5,13 @@ import { Encoder } from "cbor-x";
5
5
  * plain CBOR map (no tag), or authenticators return FIDO_ERR_CBOR_UNEXPECTED_TYPE (0x11).
6
6
  */
7
7
  const ctapCborEncoder = new Encoder({
8
- useTag259ForMaps: false,
9
- useRecords: false,
10
- mapsAsObjects: true,
11
- structuredClone: false,
12
- tagUint8Array: false,
13
- bundleStrings: false,
8
+ useTag259ForMaps: false,
9
+ useRecords: false,
10
+ variableMapSize: true,
11
+ mapsAsObjects: true,
12
+ structuredClone: false,
13
+ tagUint8Array: false,
14
+ bundleStrings: false,
14
15
  } as ConstructorParameters<typeof Encoder>[0]);
15
16
 
16
17
  const textEncoder = new TextEncoder();
@@ -20,17 +21,17 @@ const textEncoder = new TextEncoder();
20
21
  * shorter UTF-8 length sorts first; same length → lower byte-wise lexical order.
21
22
  */
22
23
  export function compareCtapTextMapKeys(a: string, b: string): number {
23
- const ab = textEncoder.encode(a);
24
- const bb = textEncoder.encode(b);
25
- if (ab.length !== bb.length) {
26
- return ab.length - bb.length;
27
- }
28
- for (let i = 0; i < ab.length; i++) {
29
- if (ab[i] !== bb[i]) {
30
- return ab[i] - bb[i];
31
- }
32
- }
33
- return 0;
24
+ const ab = textEncoder.encode(a);
25
+ const bb = textEncoder.encode(b);
26
+ if (ab.length !== bb.length) {
27
+ return ab.length - bb.length;
28
+ }
29
+ for (let i = 0; i < ab.length; i++) {
30
+ if (ab[i] !== bb[i]) {
31
+ return ab[i] - bb[i];
32
+ }
33
+ }
34
+ return 0;
34
35
  }
35
36
 
36
37
  /**
@@ -38,118 +39,101 @@ export function compareCtapTextMapKeys(a: string, b: string): number {
38
39
  * Integer-key maps (command parameters, COSE, etc.) are sorted numerically.
39
40
  */
40
41
  export function canonicalizeCtapValue(value: unknown): unknown {
41
- if (value === null || value === undefined) {
42
- return value;
43
- }
44
- const t = typeof value;
45
- if (
46
- t === "boolean" ||
47
- t === "number" ||
48
- t === "string" ||
49
- t === "bigint"
50
- ) {
51
- return value;
52
- }
53
- if (value instanceof Uint8Array) {
54
- return value;
55
- }
56
- if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
57
- const view = value as ArrayBufferView;
58
- return new Uint8Array(
59
- view.buffer,
60
- view.byteOffset,
61
- view.byteLength,
62
- );
63
- }
64
- if (Array.isArray(value)) {
65
- return value.map((v) => canonicalizeCtapValue(v));
66
- }
67
- if (value instanceof Map) {
68
- const keys = [...value.keys()];
69
- if (keys.length === 0) {
70
- return new Map();
71
- }
72
- const allNum = keys.every((k) => typeof k === "number");
73
- if (allNum) {
74
- const sorted = (keys as number[])
75
- .slice()
76
- .sort((a, b) => a - b);
77
- const m = new Map<number, unknown>();
78
- for (const k of sorted) {
79
- m.set(k, canonicalizeCtapValue(value.get(k)));
80
- }
81
- return m;
82
- }
83
- const allStr = keys.every((k) => typeof k === "string");
84
- if (allStr) {
85
- const sorted = (keys as string[])
86
- .slice()
87
- .sort(compareCtapTextMapKeys);
88
- const o: Record<string, unknown> = {};
89
- for (const k of sorted) {
90
- o[k] = canonicalizeCtapValue(value.get(k));
91
- }
92
- return o;
93
- }
94
- throw new Error(
95
- "CTAP CBOR: map keys must be all numbers or all strings for canonical encoding",
96
- );
97
- }
98
- if (t === "object") {
99
- const o = value as Record<string, unknown>;
100
- const keys = Object.keys(o).sort(compareCtapTextMapKeys);
101
- const out: Record<string, unknown> = {};
102
- for (const k of keys) {
103
- out[k] = canonicalizeCtapValue(o[k]);
104
- }
105
- return out;
106
- }
107
- return value;
42
+ if (value === null || value === undefined) {
43
+ return value;
44
+ }
45
+ const t = typeof value;
46
+ if (t === "boolean" || t === "number" || t === "string" || t === "bigint") {
47
+ return value;
48
+ }
49
+ if (value instanceof Uint8Array) {
50
+ return value;
51
+ }
52
+ if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
53
+ const view = value as ArrayBufferView;
54
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
55
+ }
56
+ if (Array.isArray(value)) {
57
+ return value.map((v) => canonicalizeCtapValue(v));
58
+ }
59
+ if (value instanceof Map) {
60
+ const keys = [...value.keys()];
61
+ if (keys.length === 0) {
62
+ return new Map();
63
+ }
64
+ const allNum = keys.every((k) => typeof k === "number");
65
+ if (allNum) {
66
+ const sorted = (keys as number[]).slice().sort((a, b) => a - b);
67
+ const m = new Map<number, unknown>();
68
+ for (const k of sorted) {
69
+ m.set(k, canonicalizeCtapValue(value.get(k)));
70
+ }
71
+ return m;
72
+ }
73
+ const allStr = keys.every((k) => typeof k === "string");
74
+ if (allStr) {
75
+ const sorted = (keys as string[]).slice().sort(compareCtapTextMapKeys);
76
+ const o: Record<string, unknown> = {};
77
+ for (const k of sorted) {
78
+ o[k] = canonicalizeCtapValue(value.get(k));
79
+ }
80
+ return o;
81
+ }
82
+ throw new Error(
83
+ "CTAP CBOR: map keys must be all numbers or all strings for canonical encoding",
84
+ );
85
+ }
86
+ if (t === "object") {
87
+ const o = value as Record<string, unknown>;
88
+ const keys = Object.keys(o).sort(compareCtapTextMapKeys);
89
+ const out: Record<string, unknown> = {};
90
+ for (const k of keys) {
91
+ out[k] = canonicalizeCtapValue(o[k]);
92
+ }
93
+ return out;
94
+ }
95
+ return value;
108
96
  }
109
97
 
110
98
  export function encodeCtapCbor(value: unknown): Uint8Array {
111
- const encoded = ctapCborEncoder.encode(canonicalizeCtapValue(value));
112
- if (encoded instanceof Uint8Array) {
113
- return new Uint8Array(encoded);
114
- }
115
- if (ArrayBuffer.isView(encoded)) {
116
- const v = encoded as ArrayBufferView;
117
- return new Uint8Array(v.buffer, v.byteOffset, v.byteLength);
118
- }
119
- return Uint8Array.from(encoded as ArrayLike<number>);
99
+ const encoded = ctapCborEncoder.encode(canonicalizeCtapValue(value));
100
+ if (encoded instanceof Uint8Array) {
101
+ return new Uint8Array(encoded);
102
+ }
103
+ if (ArrayBuffer.isView(encoded)) {
104
+ const v = encoded as ArrayBufferView;
105
+ return new Uint8Array(v.buffer, v.byteOffset, v.byteLength);
106
+ }
107
+ return Uint8Array.from(encoded as ArrayLike<number>);
120
108
  }
121
109
 
122
110
  export function bytesView(v: unknown): Uint8Array | undefined {
123
- if (v instanceof Uint8Array) {
124
- return new Uint8Array(v);
125
- }
126
- if (ArrayBuffer.isView(v) && !(v instanceof DataView)) {
127
- const view = v as ArrayBufferView;
128
- return new Uint8Array(
129
- view.buffer,
130
- view.byteOffset,
131
- view.byteLength,
132
- );
133
- }
134
- return undefined;
111
+ if (v instanceof Uint8Array) {
112
+ return new Uint8Array(v);
113
+ }
114
+ if (ArrayBuffer.isView(v) && !(v instanceof DataView)) {
115
+ const view = v as ArrayBufferView;
116
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
117
+ }
118
+ return undefined;
135
119
  }
136
120
 
137
121
  export function cborMapGet(
138
- map: Map<number, unknown> | object,
139
- key: number,
122
+ map: Map<number, unknown> | object,
123
+ key: number,
140
124
  ): unknown {
141
- if (map instanceof Map) {
142
- return map.get(key);
143
- }
144
- if (map !== null && typeof map === "object") {
145
- const o = map as Record<number | string, unknown>;
146
- if (key in o) {
147
- return o[key];
148
- }
149
- const s = String(key);
150
- if (s in o) {
151
- return o[s];
152
- }
153
- }
154
- return undefined;
125
+ if (map instanceof Map) {
126
+ return map.get(key);
127
+ }
128
+ if (map !== null && typeof map === "object") {
129
+ const o = map as Record<number | string, unknown>;
130
+ if (key in o) {
131
+ return o[key];
132
+ }
133
+ const s = String(key);
134
+ if (s in o) {
135
+ return o[s];
136
+ }
137
+ }
138
+ return undefined;
155
139
  }