@gnufoo/canaad 0.1.0

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.md ADDED
@@ -0,0 +1,104 @@
1
+ # canaad-wasm
2
+
3
+ WASM bindings for AAD (Additional Authenticated Data) canonicalization per RFC 8785.
4
+
5
+ This crate provides WebAssembly bindings for the `canaad-core` library, enabling
6
+ AAD canonicalization in browsers, Node.js, and other WASM runtimes like
7
+ Cloudflare Workers.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @gnufoo/canaad
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Canonicalize JSON
18
+
19
+ ```typescript
20
+ import { canonicalize, canonicalizeString, validate, hash } from '@gnufoo/canaad';
21
+
22
+ // Canonicalize JSON to bytes
23
+ const json = '{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}';
24
+ const bytes: Uint8Array = canonicalize(json);
25
+
26
+ // Canonicalize JSON to string
27
+ const canonical: string = canonicalizeString(json);
28
+ // => '{"purpose":"encryption","resource":"secrets/db","tenant":"org_abc","v":1}'
29
+
30
+ // Validate JSON
31
+ const isValid: boolean = validate(json);
32
+
33
+ // Get SHA-256 hash of canonical form
34
+ const hashBytes: Uint8Array = hash(json);
35
+ ```
36
+
37
+ ### Builder API
38
+
39
+ ```typescript
40
+ import { AadBuilder } from '@gnufoo/canaad';
41
+
42
+ const builder = new AadBuilder()
43
+ .tenant("org_abc")
44
+ .resource("secrets/db")
45
+ .purpose("encryption")
46
+ .timestamp(1706400000)
47
+ .extensionString("x_vault_cluster", "us-east-1")
48
+ .extensionInt("x_app_priority", 5);
49
+
50
+ // Build to bytes
51
+ const bytes: Uint8Array = builder.build();
52
+
53
+ // Build to string
54
+ const canonical: string = builder.buildString();
55
+ ```
56
+
57
+ ### Constants
58
+
59
+ ```typescript
60
+ import { SPEC_VERSION, MAX_SAFE_INTEGER, MAX_SERIALIZED_BYTES } from '@gnufoo/canaad';
61
+
62
+ console.log(SPEC_VERSION); // 1
63
+ console.log(MAX_SAFE_INTEGER); // 9007199254740991 (2^53 - 1)
64
+ console.log(MAX_SERIALIZED_BYTES); // 16384 (16 KiB)
65
+ ```
66
+
67
+ ## Error Handling
68
+
69
+ All functions that can fail will throw JavaScript errors with descriptive messages:
70
+
71
+ ```typescript
72
+ try {
73
+ canonicalize('{"v":1}'); // Missing required fields
74
+ } catch (e) {
75
+ console.error(e.message); // "missing required field: tenant"
76
+ }
77
+ ```
78
+
79
+ ## Supported Environments
80
+
81
+ - **Browsers**: Modern browsers with WASM support
82
+ - **Node.js**: v14+ with WASM support
83
+ - **Cloudflare Workers**: Full support
84
+ - **Deno**: With WASM import
85
+
86
+ ## Building from Source
87
+
88
+ ```bash
89
+ # Install wasm-pack
90
+ cargo install wasm-pack
91
+
92
+ # Build for bundlers (webpack, vite, etc.)
93
+ wasm-pack build --target bundler
94
+
95
+ # Build for Node.js
96
+ wasm-pack build --target nodejs
97
+
98
+ # Build for web (no bundler)
99
+ wasm-pack build --target web
100
+ ```
101
+
102
+ ## License
103
+
104
+ MIT OR Apache-2.0
@@ -0,0 +1,253 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Builder for constructing AAD objects programmatically.
6
+ *
7
+ * Provides a fluent API for building AAD with method chaining.
8
+ * All setter methods return a new builder to enable chaining.
9
+ *
10
+ * # Example (JavaScript)
11
+ *
12
+ * ```javascript
13
+ * const builder = new AadBuilder()
14
+ * .tenant("org_abc")
15
+ * .resource("secrets/db")
16
+ * .purpose("encryption")
17
+ * .timestamp(1706400000)
18
+ * .extensionString("x_vault_cluster", "us-east-1");
19
+ *
20
+ * const bytes = builder.build();
21
+ * const canonical = builder.buildString();
22
+ * ```
23
+ */
24
+ export class AadBuilder {
25
+ free(): void;
26
+ [Symbol.dispose](): void;
27
+ /**
28
+ * Builds the AAD and returns the canonical bytes.
29
+ *
30
+ * # Returns
31
+ *
32
+ * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
33
+ *
34
+ * # Errors
35
+ *
36
+ * Throws a JavaScript error if:
37
+ * - Required fields (tenant, resource, purpose) are missing
38
+ * - Any field value is invalid
39
+ * - Extension keys don't match the required pattern
40
+ * - The serialized output exceeds 16 KiB
41
+ */
42
+ build(): Uint8Array;
43
+ /**
44
+ * Builds the AAD and returns the canonical string.
45
+ *
46
+ * # Returns
47
+ *
48
+ * The canonical (JCS) representation as a string.
49
+ *
50
+ * # Errors
51
+ *
52
+ * Throws a JavaScript error if:
53
+ * - Required fields (tenant, resource, purpose) are missing
54
+ * - Any field value is invalid
55
+ * - Extension keys don't match the required pattern
56
+ * - The serialized output exceeds 16 KiB
57
+ */
58
+ buildString(): string;
59
+ /**
60
+ * Adds an integer extension field.
61
+ *
62
+ * Extension keys must match pattern `x_<app>_<field>` where:
63
+ * - `<app>` is one or more lowercase letters
64
+ * - `<field>` is one or more lowercase letters or underscores
65
+ *
66
+ * # Arguments
67
+ *
68
+ * * `key` - Extension key (e.g., `x_app_priority`)
69
+ * * `value` - Integer value (0 to 2^53-1)
70
+ *
71
+ * # Returns
72
+ *
73
+ * A new builder with the extension added.
74
+ */
75
+ extensionInt(key: string, value: number): AadBuilder;
76
+ /**
77
+ * Adds a string extension field.
78
+ *
79
+ * Extension keys must match pattern `x_<app>_<field>` where:
80
+ * - `<app>` is one or more lowercase letters
81
+ * - `<field>` is one or more lowercase letters or underscores
82
+ *
83
+ * # Arguments
84
+ *
85
+ * * `key` - Extension key (e.g., `x_vault_cluster`)
86
+ * * `value` - String value (no NUL bytes)
87
+ *
88
+ * # Returns
89
+ *
90
+ * A new builder with the extension added.
91
+ */
92
+ extensionString(key: string, value: string): AadBuilder;
93
+ /**
94
+ * Creates a new AAD builder.
95
+ */
96
+ constructor();
97
+ /**
98
+ * Sets the purpose or usage context.
99
+ *
100
+ * # Arguments
101
+ *
102
+ * * `value` - Purpose description (1+ bytes, no NUL bytes)
103
+ *
104
+ * # Returns
105
+ *
106
+ * A new builder with the purpose set.
107
+ */
108
+ purpose(value: string): AadBuilder;
109
+ /**
110
+ * Sets the resource path or identifier.
111
+ *
112
+ * # Arguments
113
+ *
114
+ * * `value` - Resource path (1-1024 bytes, no NUL bytes)
115
+ *
116
+ * # Returns
117
+ *
118
+ * A new builder with the resource set.
119
+ */
120
+ resource(value: string): AadBuilder;
121
+ /**
122
+ * Sets the tenant identifier.
123
+ *
124
+ * # Arguments
125
+ *
126
+ * * `value` - Tenant identifier (1-256 bytes, no NUL bytes)
127
+ *
128
+ * # Returns
129
+ *
130
+ * A new builder with the tenant set.
131
+ */
132
+ tenant(value: string): AadBuilder;
133
+ /**
134
+ * Sets the timestamp.
135
+ *
136
+ * # Arguments
137
+ *
138
+ * * `ts` - Unix timestamp (0 to 2^53-1)
139
+ *
140
+ * # Returns
141
+ *
142
+ * A new builder with the timestamp set.
143
+ */
144
+ timestamp(ts: number): AadBuilder;
145
+ }
146
+
147
+ /**
148
+ * Returns the maximum safe integer value (2^53 - 1).
149
+ *
150
+ * This is the maximum integer value that can be exactly represented in
151
+ * JavaScript's Number type.
152
+ */
153
+ export function MAX_SAFE_INTEGER(): number;
154
+
155
+ /**
156
+ * Returns the maximum serialized AAD size in bytes (16 KiB).
157
+ */
158
+ export function MAX_SERIALIZED_BYTES(): number;
159
+
160
+ /**
161
+ * Returns the current AAD specification version.
162
+ *
163
+ * Currently always returns 1.
164
+ */
165
+ export function SPEC_VERSION(): number;
166
+
167
+ /**
168
+ * Parses and canonicalizes a JSON string to bytes.
169
+ *
170
+ * This function:
171
+ * 1. Parses the JSON with duplicate key detection
172
+ * 2. Validates all fields according to the AAD specification
173
+ * 3. Returns the canonical (JCS) representation as bytes
174
+ *
175
+ * # Arguments
176
+ *
177
+ * * `json` - A JSON string containing an AAD object
178
+ *
179
+ * # Returns
180
+ *
181
+ * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
182
+ *
183
+ * # Errors
184
+ *
185
+ * Throws a JavaScript error if:
186
+ * - The JSON is invalid or contains duplicate keys
187
+ * - Any field violates AAD constraints
188
+ * - The serialized output exceeds 16 KiB
189
+ */
190
+ export function canonicalize(json: string): Uint8Array;
191
+
192
+ /**
193
+ * Parses and canonicalizes a JSON string to a UTF-8 string.
194
+ *
195
+ * This is equivalent to `canonicalize` but returns a string instead of bytes.
196
+ *
197
+ * # Arguments
198
+ *
199
+ * * `json` - A JSON string containing an AAD object
200
+ *
201
+ * # Returns
202
+ *
203
+ * The canonical (JCS) representation as a string.
204
+ *
205
+ * # Errors
206
+ *
207
+ * Throws a JavaScript error if:
208
+ * - The JSON is invalid or contains duplicate keys
209
+ * - Any field violates AAD constraints
210
+ * - The serialized output exceeds 16 KiB
211
+ */
212
+ export function canonicalizeString(json: string): string;
213
+
214
+ /**
215
+ * Computes the SHA-256 hash of the canonical JSON form.
216
+ *
217
+ * This function:
218
+ * 1. Parses and validates the JSON
219
+ * 2. Canonicalizes according to RFC 8785
220
+ * 3. Returns the SHA-256 hash of the canonical bytes
221
+ *
222
+ * # Arguments
223
+ *
224
+ * * `json` - A JSON string containing an AAD object
225
+ *
226
+ * # Returns
227
+ *
228
+ * A 32-byte `Uint8Array` containing the SHA-256 hash.
229
+ *
230
+ * # Errors
231
+ *
232
+ * Throws a JavaScript error if:
233
+ * - The JSON is invalid or contains duplicate keys
234
+ * - Any field violates AAD constraints
235
+ * - The serialized output exceeds 16 KiB
236
+ */
237
+ export function hash(json: string): Uint8Array;
238
+
239
+ /**
240
+ * Validates a JSON string against the AAD specification.
241
+ *
242
+ * This function performs full validation without returning the context.
243
+ * Use this for quick validation checks.
244
+ *
245
+ * # Arguments
246
+ *
247
+ * * `json` - A JSON string to validate
248
+ *
249
+ * # Returns
250
+ *
251
+ * `true` if the JSON is valid AAD, `false` otherwise.
252
+ */
253
+ export function validate(json: string): boolean;
package/canaad_wasm.js ADDED
@@ -0,0 +1,540 @@
1
+ /* @ts-self-types="./canaad_wasm.d.ts" */
2
+
3
+ /**
4
+ * Builder for constructing AAD objects programmatically.
5
+ *
6
+ * Provides a fluent API for building AAD with method chaining.
7
+ * All setter methods return a new builder to enable chaining.
8
+ *
9
+ * # Example (JavaScript)
10
+ *
11
+ * ```javascript
12
+ * const builder = new AadBuilder()
13
+ * .tenant("org_abc")
14
+ * .resource("secrets/db")
15
+ * .purpose("encryption")
16
+ * .timestamp(1706400000)
17
+ * .extensionString("x_vault_cluster", "us-east-1");
18
+ *
19
+ * const bytes = builder.build();
20
+ * const canonical = builder.buildString();
21
+ * ```
22
+ */
23
+ class AadBuilder {
24
+ static __wrap(ptr) {
25
+ ptr = ptr >>> 0;
26
+ const obj = Object.create(AadBuilder.prototype);
27
+ obj.__wbg_ptr = ptr;
28
+ AadBuilderFinalization.register(obj, obj.__wbg_ptr, obj);
29
+ return obj;
30
+ }
31
+ __destroy_into_raw() {
32
+ const ptr = this.__wbg_ptr;
33
+ this.__wbg_ptr = 0;
34
+ AadBuilderFinalization.unregister(this);
35
+ return ptr;
36
+ }
37
+ free() {
38
+ const ptr = this.__destroy_into_raw();
39
+ wasm.__wbg_aadbuilder_free(ptr, 0);
40
+ }
41
+ /**
42
+ * Builds the AAD and returns the canonical bytes.
43
+ *
44
+ * # Returns
45
+ *
46
+ * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
47
+ *
48
+ * # Errors
49
+ *
50
+ * Throws a JavaScript error if:
51
+ * - Required fields (tenant, resource, purpose) are missing
52
+ * - Any field value is invalid
53
+ * - Extension keys don't match the required pattern
54
+ * - The serialized output exceeds 16 KiB
55
+ * @returns {Uint8Array}
56
+ */
57
+ build() {
58
+ const ret = wasm.aadbuilder_build(this.__wbg_ptr);
59
+ if (ret[3]) {
60
+ throw takeFromExternrefTable0(ret[2]);
61
+ }
62
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
63
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
64
+ return v1;
65
+ }
66
+ /**
67
+ * Builds the AAD and returns the canonical string.
68
+ *
69
+ * # Returns
70
+ *
71
+ * The canonical (JCS) representation as a string.
72
+ *
73
+ * # Errors
74
+ *
75
+ * Throws a JavaScript error if:
76
+ * - Required fields (tenant, resource, purpose) are missing
77
+ * - Any field value is invalid
78
+ * - Extension keys don't match the required pattern
79
+ * - The serialized output exceeds 16 KiB
80
+ * @returns {string}
81
+ */
82
+ buildString() {
83
+ let deferred2_0;
84
+ let deferred2_1;
85
+ try {
86
+ const ret = wasm.aadbuilder_buildString(this.__wbg_ptr);
87
+ var ptr1 = ret[0];
88
+ var len1 = ret[1];
89
+ if (ret[3]) {
90
+ ptr1 = 0; len1 = 0;
91
+ throw takeFromExternrefTable0(ret[2]);
92
+ }
93
+ deferred2_0 = ptr1;
94
+ deferred2_1 = len1;
95
+ return getStringFromWasm0(ptr1, len1);
96
+ } finally {
97
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
98
+ }
99
+ }
100
+ /**
101
+ * Adds an integer extension field.
102
+ *
103
+ * Extension keys must match pattern `x_<app>_<field>` where:
104
+ * - `<app>` is one or more lowercase letters
105
+ * - `<field>` is one or more lowercase letters or underscores
106
+ *
107
+ * # Arguments
108
+ *
109
+ * * `key` - Extension key (e.g., `x_app_priority`)
110
+ * * `value` - Integer value (0 to 2^53-1)
111
+ *
112
+ * # Returns
113
+ *
114
+ * A new builder with the extension added.
115
+ * @param {string} key
116
+ * @param {number} value
117
+ * @returns {AadBuilder}
118
+ */
119
+ extensionInt(key, value) {
120
+ const ptr = this.__destroy_into_raw();
121
+ const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
122
+ const len0 = WASM_VECTOR_LEN;
123
+ const ret = wasm.aadbuilder_extensionInt(ptr, ptr0, len0, value);
124
+ return AadBuilder.__wrap(ret);
125
+ }
126
+ /**
127
+ * Adds a string extension field.
128
+ *
129
+ * Extension keys must match pattern `x_<app>_<field>` where:
130
+ * - `<app>` is one or more lowercase letters
131
+ * - `<field>` is one or more lowercase letters or underscores
132
+ *
133
+ * # Arguments
134
+ *
135
+ * * `key` - Extension key (e.g., `x_vault_cluster`)
136
+ * * `value` - String value (no NUL bytes)
137
+ *
138
+ * # Returns
139
+ *
140
+ * A new builder with the extension added.
141
+ * @param {string} key
142
+ * @param {string} value
143
+ * @returns {AadBuilder}
144
+ */
145
+ extensionString(key, value) {
146
+ const ptr = this.__destroy_into_raw();
147
+ const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
148
+ const len0 = WASM_VECTOR_LEN;
149
+ const ptr1 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
150
+ const len1 = WASM_VECTOR_LEN;
151
+ const ret = wasm.aadbuilder_extensionString(ptr, ptr0, len0, ptr1, len1);
152
+ return AadBuilder.__wrap(ret);
153
+ }
154
+ /**
155
+ * Creates a new AAD builder.
156
+ */
157
+ constructor() {
158
+ const ret = wasm.aadbuilder_new();
159
+ this.__wbg_ptr = ret >>> 0;
160
+ AadBuilderFinalization.register(this, this.__wbg_ptr, this);
161
+ return this;
162
+ }
163
+ /**
164
+ * Sets the purpose or usage context.
165
+ *
166
+ * # Arguments
167
+ *
168
+ * * `value` - Purpose description (1+ bytes, no NUL bytes)
169
+ *
170
+ * # Returns
171
+ *
172
+ * A new builder with the purpose set.
173
+ * @param {string} value
174
+ * @returns {AadBuilder}
175
+ */
176
+ purpose(value) {
177
+ const ptr = this.__destroy_into_raw();
178
+ const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
179
+ const len0 = WASM_VECTOR_LEN;
180
+ const ret = wasm.aadbuilder_purpose(ptr, ptr0, len0);
181
+ return AadBuilder.__wrap(ret);
182
+ }
183
+ /**
184
+ * Sets the resource path or identifier.
185
+ *
186
+ * # Arguments
187
+ *
188
+ * * `value` - Resource path (1-1024 bytes, no NUL bytes)
189
+ *
190
+ * # Returns
191
+ *
192
+ * A new builder with the resource set.
193
+ * @param {string} value
194
+ * @returns {AadBuilder}
195
+ */
196
+ resource(value) {
197
+ const ptr = this.__destroy_into_raw();
198
+ const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
199
+ const len0 = WASM_VECTOR_LEN;
200
+ const ret = wasm.aadbuilder_resource(ptr, ptr0, len0);
201
+ return AadBuilder.__wrap(ret);
202
+ }
203
+ /**
204
+ * Sets the tenant identifier.
205
+ *
206
+ * # Arguments
207
+ *
208
+ * * `value` - Tenant identifier (1-256 bytes, no NUL bytes)
209
+ *
210
+ * # Returns
211
+ *
212
+ * A new builder with the tenant set.
213
+ * @param {string} value
214
+ * @returns {AadBuilder}
215
+ */
216
+ tenant(value) {
217
+ const ptr = this.__destroy_into_raw();
218
+ const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
219
+ const len0 = WASM_VECTOR_LEN;
220
+ const ret = wasm.aadbuilder_tenant(ptr, ptr0, len0);
221
+ return AadBuilder.__wrap(ret);
222
+ }
223
+ /**
224
+ * Sets the timestamp.
225
+ *
226
+ * # Arguments
227
+ *
228
+ * * `ts` - Unix timestamp (0 to 2^53-1)
229
+ *
230
+ * # Returns
231
+ *
232
+ * A new builder with the timestamp set.
233
+ * @param {number} ts
234
+ * @returns {AadBuilder}
235
+ */
236
+ timestamp(ts) {
237
+ const ptr = this.__destroy_into_raw();
238
+ const ret = wasm.aadbuilder_timestamp(ptr, ts);
239
+ return AadBuilder.__wrap(ret);
240
+ }
241
+ }
242
+ if (Symbol.dispose) AadBuilder.prototype[Symbol.dispose] = AadBuilder.prototype.free;
243
+ exports.AadBuilder = AadBuilder;
244
+
245
+ /**
246
+ * Returns the maximum safe integer value (2^53 - 1).
247
+ *
248
+ * This is the maximum integer value that can be exactly represented in
249
+ * JavaScript's Number type.
250
+ * @returns {number}
251
+ */
252
+ function MAX_SAFE_INTEGER() {
253
+ const ret = wasm.MAX_SAFE_INTEGER();
254
+ return ret;
255
+ }
256
+ exports.MAX_SAFE_INTEGER = MAX_SAFE_INTEGER;
257
+
258
+ /**
259
+ * Returns the maximum serialized AAD size in bytes (16 KiB).
260
+ * @returns {number}
261
+ */
262
+ function MAX_SERIALIZED_BYTES() {
263
+ const ret = wasm.MAX_SERIALIZED_BYTES();
264
+ return ret >>> 0;
265
+ }
266
+ exports.MAX_SERIALIZED_BYTES = MAX_SERIALIZED_BYTES;
267
+
268
+ /**
269
+ * Returns the current AAD specification version.
270
+ *
271
+ * Currently always returns 1.
272
+ * @returns {number}
273
+ */
274
+ function SPEC_VERSION() {
275
+ const ret = wasm.SPEC_VERSION();
276
+ return ret >>> 0;
277
+ }
278
+ exports.SPEC_VERSION = SPEC_VERSION;
279
+
280
+ /**
281
+ * Parses and canonicalizes a JSON string to bytes.
282
+ *
283
+ * This function:
284
+ * 1. Parses the JSON with duplicate key detection
285
+ * 2. Validates all fields according to the AAD specification
286
+ * 3. Returns the canonical (JCS) representation as bytes
287
+ *
288
+ * # Arguments
289
+ *
290
+ * * `json` - A JSON string containing an AAD object
291
+ *
292
+ * # Returns
293
+ *
294
+ * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
295
+ *
296
+ * # Errors
297
+ *
298
+ * Throws a JavaScript error if:
299
+ * - The JSON is invalid or contains duplicate keys
300
+ * - Any field violates AAD constraints
301
+ * - The serialized output exceeds 16 KiB
302
+ * @param {string} json
303
+ * @returns {Uint8Array}
304
+ */
305
+ function canonicalize(json) {
306
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
307
+ const len0 = WASM_VECTOR_LEN;
308
+ const ret = wasm.canonicalize(ptr0, len0);
309
+ if (ret[3]) {
310
+ throw takeFromExternrefTable0(ret[2]);
311
+ }
312
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
313
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
314
+ return v2;
315
+ }
316
+ exports.canonicalize = canonicalize;
317
+
318
+ /**
319
+ * Parses and canonicalizes a JSON string to a UTF-8 string.
320
+ *
321
+ * This is equivalent to `canonicalize` but returns a string instead of bytes.
322
+ *
323
+ * # Arguments
324
+ *
325
+ * * `json` - A JSON string containing an AAD object
326
+ *
327
+ * # Returns
328
+ *
329
+ * The canonical (JCS) representation as a string.
330
+ *
331
+ * # Errors
332
+ *
333
+ * Throws a JavaScript error if:
334
+ * - The JSON is invalid or contains duplicate keys
335
+ * - Any field violates AAD constraints
336
+ * - The serialized output exceeds 16 KiB
337
+ * @param {string} json
338
+ * @returns {string}
339
+ */
340
+ function canonicalizeString(json) {
341
+ let deferred3_0;
342
+ let deferred3_1;
343
+ try {
344
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
345
+ const len0 = WASM_VECTOR_LEN;
346
+ const ret = wasm.canonicalizeString(ptr0, len0);
347
+ var ptr2 = ret[0];
348
+ var len2 = ret[1];
349
+ if (ret[3]) {
350
+ ptr2 = 0; len2 = 0;
351
+ throw takeFromExternrefTable0(ret[2]);
352
+ }
353
+ deferred3_0 = ptr2;
354
+ deferred3_1 = len2;
355
+ return getStringFromWasm0(ptr2, len2);
356
+ } finally {
357
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
358
+ }
359
+ }
360
+ exports.canonicalizeString = canonicalizeString;
361
+
362
+ /**
363
+ * Computes the SHA-256 hash of the canonical JSON form.
364
+ *
365
+ * This function:
366
+ * 1. Parses and validates the JSON
367
+ * 2. Canonicalizes according to RFC 8785
368
+ * 3. Returns the SHA-256 hash of the canonical bytes
369
+ *
370
+ * # Arguments
371
+ *
372
+ * * `json` - A JSON string containing an AAD object
373
+ *
374
+ * # Returns
375
+ *
376
+ * A 32-byte `Uint8Array` containing the SHA-256 hash.
377
+ *
378
+ * # Errors
379
+ *
380
+ * Throws a JavaScript error if:
381
+ * - The JSON is invalid or contains duplicate keys
382
+ * - Any field violates AAD constraints
383
+ * - The serialized output exceeds 16 KiB
384
+ * @param {string} json
385
+ * @returns {Uint8Array}
386
+ */
387
+ function hash(json) {
388
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
389
+ const len0 = WASM_VECTOR_LEN;
390
+ const ret = wasm.hash(ptr0, len0);
391
+ if (ret[3]) {
392
+ throw takeFromExternrefTable0(ret[2]);
393
+ }
394
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
395
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
396
+ return v2;
397
+ }
398
+ exports.hash = hash;
399
+
400
+ /**
401
+ * Validates a JSON string against the AAD specification.
402
+ *
403
+ * This function performs full validation without returning the context.
404
+ * Use this for quick validation checks.
405
+ *
406
+ * # Arguments
407
+ *
408
+ * * `json` - A JSON string to validate
409
+ *
410
+ * # Returns
411
+ *
412
+ * `true` if the JSON is valid AAD, `false` otherwise.
413
+ * @param {string} json
414
+ * @returns {boolean}
415
+ */
416
+ function validate(json) {
417
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
418
+ const len0 = WASM_VECTOR_LEN;
419
+ const ret = wasm.validate(ptr0, len0);
420
+ return ret !== 0;
421
+ }
422
+ exports.validate = validate;
423
+
424
+ function __wbg_get_imports() {
425
+ const import0 = {
426
+ __proto__: null,
427
+ __wbg_Error_8c4e43fe74559d73: function(arg0, arg1) {
428
+ const ret = Error(getStringFromWasm0(arg0, arg1));
429
+ return ret;
430
+ },
431
+ __wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
432
+ throw new Error(getStringFromWasm0(arg0, arg1));
433
+ },
434
+ __wbindgen_init_externref_table: function() {
435
+ const table = wasm.__wbindgen_externrefs;
436
+ const offset = table.grow(4);
437
+ table.set(0, undefined);
438
+ table.set(offset + 0, undefined);
439
+ table.set(offset + 1, null);
440
+ table.set(offset + 2, true);
441
+ table.set(offset + 3, false);
442
+ },
443
+ };
444
+ return {
445
+ __proto__: null,
446
+ "./canaad_wasm_bg.js": import0,
447
+ };
448
+ }
449
+
450
+ const AadBuilderFinalization = (typeof FinalizationRegistry === 'undefined')
451
+ ? { register: () => {}, unregister: () => {} }
452
+ : new FinalizationRegistry(ptr => wasm.__wbg_aadbuilder_free(ptr >>> 0, 1));
453
+
454
+ function getArrayU8FromWasm0(ptr, len) {
455
+ ptr = ptr >>> 0;
456
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
457
+ }
458
+
459
+ function getStringFromWasm0(ptr, len) {
460
+ ptr = ptr >>> 0;
461
+ return decodeText(ptr, len);
462
+ }
463
+
464
+ let cachedUint8ArrayMemory0 = null;
465
+ function getUint8ArrayMemory0() {
466
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
467
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
468
+ }
469
+ return cachedUint8ArrayMemory0;
470
+ }
471
+
472
+ function passStringToWasm0(arg, malloc, realloc) {
473
+ if (realloc === undefined) {
474
+ const buf = cachedTextEncoder.encode(arg);
475
+ const ptr = malloc(buf.length, 1) >>> 0;
476
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
477
+ WASM_VECTOR_LEN = buf.length;
478
+ return ptr;
479
+ }
480
+
481
+ let len = arg.length;
482
+ let ptr = malloc(len, 1) >>> 0;
483
+
484
+ const mem = getUint8ArrayMemory0();
485
+
486
+ let offset = 0;
487
+
488
+ for (; offset < len; offset++) {
489
+ const code = arg.charCodeAt(offset);
490
+ if (code > 0x7F) break;
491
+ mem[ptr + offset] = code;
492
+ }
493
+ if (offset !== len) {
494
+ if (offset !== 0) {
495
+ arg = arg.slice(offset);
496
+ }
497
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
498
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
499
+ const ret = cachedTextEncoder.encodeInto(arg, view);
500
+
501
+ offset += ret.written;
502
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
503
+ }
504
+
505
+ WASM_VECTOR_LEN = offset;
506
+ return ptr;
507
+ }
508
+
509
+ function takeFromExternrefTable0(idx) {
510
+ const value = wasm.__wbindgen_externrefs.get(idx);
511
+ wasm.__externref_table_dealloc(idx);
512
+ return value;
513
+ }
514
+
515
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
516
+ cachedTextDecoder.decode();
517
+ function decodeText(ptr, len) {
518
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
519
+ }
520
+
521
+ const cachedTextEncoder = new TextEncoder();
522
+
523
+ if (!('encodeInto' in cachedTextEncoder)) {
524
+ cachedTextEncoder.encodeInto = function (arg, view) {
525
+ const buf = cachedTextEncoder.encode(arg);
526
+ view.set(buf);
527
+ return {
528
+ read: arg.length,
529
+ written: buf.length
530
+ };
531
+ };
532
+ }
533
+
534
+ let WASM_VECTOR_LEN = 0;
535
+
536
+ const wasmPath = `${__dirname}/canaad_wasm_bg.wasm`;
537
+ const wasmBytes = require('fs').readFileSync(wasmPath);
538
+ const wasmModule = new WebAssembly.Module(wasmBytes);
539
+ const wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
540
+ wasm.__wbindgen_start();
Binary file
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@gnufoo/canaad",
3
+ "description": "WASM bindings for AAD canonicalization per RFC 8785",
4
+ "version": "0.1.0",
5
+ "license": "MIT OR Apache-2.0",
6
+ "files": [
7
+ "canaad_wasm_bg.wasm",
8
+ "canaad_wasm.js",
9
+ "canaad_wasm.d.ts"
10
+ ],
11
+ "main": "canaad_wasm.js",
12
+ "types": "canaad_wasm.d.ts",
13
+ "keywords": [
14
+ "aead",
15
+ "aad",
16
+ "canonicalization",
17
+ "jcs",
18
+ "rfc8785"
19
+ ]
20
+ }