@gnufoo/canaad 0.5.1 → 2.0.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 +82 -50
- package/canaad_wasm.d.ts +42 -23
- package/canaad_wasm.js +79 -23
- package/canaad_wasm_bg.wasm +0 -0
- package/canaad_wasm_bg.wasm.d.ts +6 -3
- package/package.json +17 -31
- package/canaad_wasm_bg.js +0 -527
- package/errors.d.ts +0 -5
- package/errors.js +0 -10
- package/init.d.ts +0 -11
- package/init.js +0 -27
- package/meta.d.ts +0 -27
- package/meta.js +0 -61
- package/tool.d.ts +0 -14
- package/tool.js +0 -50
package/README.md
CHANGED
|
@@ -1,84 +1,116 @@
|
|
|
1
|
-
#
|
|
1
|
+
# canaad-wasm
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@gnufoo/canaad)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
AAD canonicalization for the browser and Cloudflare Workers. Same spec, same bytes as canaad-core.
|
|
6
|
+
|
|
7
|
+
## Initialize
|
|
8
|
+
|
|
9
|
+
WASM must be initialized once before any function calls.
|
|
10
|
+
|
|
11
|
+
Browser / Cloudflare Workers:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import init, { canonicalizeDefault } from '@gnufoo/canaad';
|
|
15
|
+
|
|
16
|
+
await init();
|
|
7
17
|
```
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
Node.js:
|
|
10
20
|
|
|
11
21
|
```typescript
|
|
12
|
-
import {
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { initSync, canonicalizeDefault } from '@gnufoo/canaad';
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
const str = canonicalizeString('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
|
|
16
|
-
const ok = validate(json);
|
|
17
|
-
const sha = hash(json); // 32-byte SHA-256
|
|
25
|
+
initSync({ module: readFileSync(new URL('./canaad_wasm_bg.wasm', import.meta.url)) });
|
|
18
26
|
```
|
|
19
27
|
|
|
20
|
-
##
|
|
28
|
+
## Default profile
|
|
21
29
|
|
|
22
30
|
```typescript
|
|
23
|
-
|
|
31
|
+
const bytes = canonicalizeDefault('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
|
|
32
|
+
// → Uint8Array
|
|
24
33
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.extensionString("x_vault_cluster", "us-east-1")
|
|
31
|
-
.extensionInt("x_app_priority", 5)
|
|
32
|
-
.build(); // Uint8Array
|
|
34
|
+
const str = canonicalizeDefaultString('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
|
|
35
|
+
// → string
|
|
36
|
+
|
|
37
|
+
const ok = validateDefault('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
|
|
38
|
+
// → boolean
|
|
33
39
|
```
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
## Generic object layer
|
|
42
|
+
|
|
43
|
+
Canonicalize any valid JSON object — no required fields, no version check:
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
```typescript
|
|
46
|
+
const bytes = canonicalizeObject('{"z":"last","a":"first"}');
|
|
47
|
+
// → Uint8Array
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
const str = canonicalizeObjectString('{"z":"last","a":"first"}');
|
|
50
|
+
// → '{"a":"first","z":"last"}'
|
|
51
|
+
|
|
52
|
+
const ok = validateObject('{"anything":"goes"}');
|
|
53
|
+
// → true
|
|
54
|
+
```
|
|
42
55
|
|
|
43
|
-
|
|
56
|
+
Use this layer to build custom profiles.
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|--------|-------------|
|
|
47
|
-
| `@gnufoo/canaad` | Direct WASM functions (after init) |
|
|
48
|
-
| `@gnufoo/canaad/init` | `initWasm()` + `isInitialized()` |
|
|
49
|
-
| `@gnufoo/canaad/meta` | Zod schemas + metadata (no WASM, SSG-safe) |
|
|
50
|
-
| `@gnufoo/canaad/tool` | `toolDefinition` with `execute()` |
|
|
58
|
+
## Hash
|
|
51
59
|
|
|
52
|
-
|
|
60
|
+
SHA-256 of the canonical form (default profile):
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
```typescript
|
|
63
|
+
const sha = hash('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
|
|
64
|
+
// → Uint8Array (32 bytes)
|
|
65
|
+
```
|
|
55
66
|
|
|
56
|
-
##
|
|
67
|
+
## Build
|
|
57
68
|
|
|
58
69
|
```typescript
|
|
59
|
-
import
|
|
60
|
-
import { toolDefinition } from '@gnufoo/canaad/tool';
|
|
70
|
+
import { AadBuilder } from '@gnufoo/canaad';
|
|
61
71
|
|
|
62
|
-
|
|
72
|
+
const aad = new AadBuilder()
|
|
73
|
+
.tenant("org_abc")
|
|
74
|
+
.resource("secrets/db")
|
|
75
|
+
.purpose("encryption")
|
|
76
|
+
.timestamp(1706400000)
|
|
77
|
+
.extensionString("x_vault_cluster", "us-east-1")
|
|
78
|
+
.extensionInt("x_app_priority", 5)
|
|
79
|
+
.build(); // → Uint8Array
|
|
63
80
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
81
|
+
const str = new AadBuilder()
|
|
82
|
+
.tenant("org_abc")
|
|
83
|
+
.resource("secrets/db")
|
|
84
|
+
.purpose("encryption")
|
|
85
|
+
.buildString(); // → string
|
|
70
86
|
```
|
|
71
87
|
|
|
72
|
-
|
|
88
|
+
Numbers only — no BigInt. `build()` and `buildString()` reject NaN, Infinity, negative, fractional, and values above `Number.MAX_SAFE_INTEGER`.
|
|
73
89
|
|
|
74
|
-
|
|
90
|
+
## Constants
|
|
75
91
|
|
|
76
92
|
```typescript
|
|
77
|
-
|
|
93
|
+
SPEC_VERSION() // → 1 (current AAD spec version)
|
|
94
|
+
MAX_SAFE_INTEGER() // → 9007199254740991 (2^53 - 1, max allowed integer value)
|
|
95
|
+
MAX_SERIALIZED_BYTES() // → 16384 (16 KiB size limit)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Errors
|
|
78
99
|
|
|
79
|
-
|
|
100
|
+
Failed calls throw with a descriptive message:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
try {
|
|
104
|
+
canonicalizeDefault('{"v":1}');
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.error(e.message); // "missing required field: tenant"
|
|
107
|
+
}
|
|
80
108
|
```
|
|
81
109
|
|
|
82
|
-
##
|
|
110
|
+
## Build from source
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
wasm-pack build --target web --out-dir ../../pkg crates/canaad-wasm
|
|
114
|
+
```
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
`--target web` exports an explicit `init()` you control — works with Cloudflare Workers and Vite.
|
package/canaad_wasm.d.ts
CHANGED
|
@@ -2,83 +2,99 @@
|
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
|
|
6
6
|
*/
|
|
7
7
|
export class AadBuilder {
|
|
8
8
|
free(): void;
|
|
9
9
|
[Symbol.dispose](): void;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* builds AAD and returns canonical bytes.
|
|
12
12
|
*/
|
|
13
13
|
build(): Uint8Array;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* builds AAD and returns canonical UTF-8 string.
|
|
16
16
|
*/
|
|
17
17
|
buildString(): string;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* adds an integer extension. Validated at `build()`.
|
|
20
20
|
*/
|
|
21
21
|
extensionInt(key: string, value: number): AadBuilder;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* adds a string extension. Key format: `x_<app>_<field>`.
|
|
24
24
|
*/
|
|
25
25
|
extensionString(key: string, value: string): AadBuilder;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* creates an empty builder. Setters store raw values; validation runs on `build()`.
|
|
28
28
|
*/
|
|
29
29
|
constructor();
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* sets the purpose. 1+ bytes, no NUL.
|
|
32
32
|
*/
|
|
33
33
|
purpose(value: string): AadBuilder;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* sets the resource. 1-1024 bytes, no NUL.
|
|
36
36
|
*/
|
|
37
37
|
resource(value: string): AadBuilder;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* sets the tenant. 1-256 bytes, no NUL.
|
|
40
40
|
*/
|
|
41
41
|
tenant(value: string): AadBuilder;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* sets the timestamp. Validated at `build()`.
|
|
44
44
|
*/
|
|
45
45
|
timestamp(ts: number): AadBuilder;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* maximum safe integer (2^53 - 1).
|
|
50
50
|
*/
|
|
51
51
|
export function MAX_SAFE_INTEGER(): number;
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* maximum serialized AAD size in bytes (16 KiB).
|
|
55
55
|
*/
|
|
56
56
|
export function MAX_SERIALIZED_BYTES(): number;
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
59
|
+
* current AAD specification version (always 1).
|
|
60
60
|
*/
|
|
61
61
|
export function SPEC_VERSION(): number;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* parses and canonicalizes a JSON string to bytes using the default AAD profile.
|
|
65
65
|
*/
|
|
66
|
-
export function
|
|
66
|
+
export function canonicalizeDefault(json: string): Uint8Array;
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* parses and canonicalizes a JSON string to a UTF-8 string using the default AAD profile.
|
|
70
70
|
*/
|
|
71
|
-
export function
|
|
71
|
+
export function canonicalizeDefaultString(json: string): string;
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
74
|
+
* canonicalizes any valid JSON object to bytes (core rules only, no profile fields required).
|
|
75
|
+
*/
|
|
76
|
+
export function canonicalizeObject(json: string): Uint8Array;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* canonicalizes any valid JSON object to a UTF-8 string (core rules only, no profile fields required).
|
|
80
|
+
*/
|
|
81
|
+
export function canonicalizeObjectString(json: string): string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* SHA-256 hash of the canonical JSON form (default AAD profile).
|
|
75
85
|
*/
|
|
76
86
|
export function hash(json: string): Uint8Array;
|
|
77
87
|
|
|
78
88
|
/**
|
|
79
|
-
*
|
|
89
|
+
* validates a JSON string against the default AAD profile. Returns false on any error.
|
|
90
|
+
*/
|
|
91
|
+
export function validateDefault(json: string): boolean;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* validates a JSON string against core rules only (size, duplicate keys, object shape).
|
|
95
|
+
* Returns false on any error.
|
|
80
96
|
*/
|
|
81
|
-
export function
|
|
97
|
+
export function validateObject(json: string): boolean;
|
|
82
98
|
|
|
83
99
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
84
100
|
|
|
@@ -97,10 +113,13 @@ export interface InitOutput {
|
|
|
97
113
|
readonly aadbuilder_resource: (a: number, b: number, c: number) => number;
|
|
98
114
|
readonly aadbuilder_tenant: (a: number, b: number, c: number) => number;
|
|
99
115
|
readonly aadbuilder_timestamp: (a: number, b: number) => number;
|
|
100
|
-
readonly
|
|
101
|
-
readonly
|
|
116
|
+
readonly canonicalizeDefault: (a: number, b: number) => [number, number, number, number];
|
|
117
|
+
readonly canonicalizeDefaultString: (a: number, b: number) => [number, number, number, number];
|
|
118
|
+
readonly canonicalizeObject: (a: number, b: number) => [number, number, number, number];
|
|
119
|
+
readonly canonicalizeObjectString: (a: number, b: number) => [number, number, number, number];
|
|
102
120
|
readonly hash: (a: number, b: number) => [number, number, number, number];
|
|
103
|
-
readonly
|
|
121
|
+
readonly validateDefault: (a: number, b: number) => number;
|
|
122
|
+
readonly validateObject: (a: number, b: number) => number;
|
|
104
123
|
readonly __wbindgen_externrefs: WebAssembly.Table;
|
|
105
124
|
readonly __externref_table_dealloc: (a: number) => void;
|
|
106
125
|
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
package/canaad_wasm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* @ts-self-types="./canaad_wasm.d.ts" */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
|
|
5
5
|
*/
|
|
6
6
|
export class AadBuilder {
|
|
7
7
|
static __wrap(ptr) {
|
|
@@ -22,7 +22,7 @@ export class AadBuilder {
|
|
|
22
22
|
wasm.__wbg_aadbuilder_free(ptr, 0);
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* builds AAD and returns canonical bytes.
|
|
26
26
|
* @returns {Uint8Array}
|
|
27
27
|
*/
|
|
28
28
|
build() {
|
|
@@ -35,7 +35,7 @@ export class AadBuilder {
|
|
|
35
35
|
return v1;
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* builds AAD and returns canonical UTF-8 string.
|
|
39
39
|
* @returns {string}
|
|
40
40
|
*/
|
|
41
41
|
buildString() {
|
|
@@ -57,7 +57,7 @@ export class AadBuilder {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* adds an integer extension. Validated at `build()`.
|
|
61
61
|
* @param {string} key
|
|
62
62
|
* @param {number} value
|
|
63
63
|
* @returns {AadBuilder}
|
|
@@ -70,7 +70,7 @@ export class AadBuilder {
|
|
|
70
70
|
return AadBuilder.__wrap(ret);
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* adds a string extension. Key format: `x_<app>_<field>`.
|
|
74
74
|
* @param {string} key
|
|
75
75
|
* @param {string} value
|
|
76
76
|
* @returns {AadBuilder}
|
|
@@ -85,7 +85,7 @@ export class AadBuilder {
|
|
|
85
85
|
return AadBuilder.__wrap(ret);
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
88
|
+
* creates an empty builder. Setters store raw values; validation runs on `build()`.
|
|
89
89
|
*/
|
|
90
90
|
constructor() {
|
|
91
91
|
const ret = wasm.aadbuilder_new();
|
|
@@ -94,7 +94,7 @@ export class AadBuilder {
|
|
|
94
94
|
return this;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
97
|
+
* sets the purpose. 1+ bytes, no NUL.
|
|
98
98
|
* @param {string} value
|
|
99
99
|
* @returns {AadBuilder}
|
|
100
100
|
*/
|
|
@@ -106,7 +106,7 @@ export class AadBuilder {
|
|
|
106
106
|
return AadBuilder.__wrap(ret);
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
|
-
*
|
|
109
|
+
* sets the resource. 1-1024 bytes, no NUL.
|
|
110
110
|
* @param {string} value
|
|
111
111
|
* @returns {AadBuilder}
|
|
112
112
|
*/
|
|
@@ -118,7 +118,7 @@ export class AadBuilder {
|
|
|
118
118
|
return AadBuilder.__wrap(ret);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
*
|
|
121
|
+
* sets the tenant. 1-256 bytes, no NUL.
|
|
122
122
|
* @param {string} value
|
|
123
123
|
* @returns {AadBuilder}
|
|
124
124
|
*/
|
|
@@ -130,7 +130,7 @@ export class AadBuilder {
|
|
|
130
130
|
return AadBuilder.__wrap(ret);
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
133
|
-
*
|
|
133
|
+
* sets the timestamp. Validated at `build()`.
|
|
134
134
|
* @param {number} ts
|
|
135
135
|
* @returns {AadBuilder}
|
|
136
136
|
*/
|
|
@@ -143,7 +143,7 @@ export class AadBuilder {
|
|
|
143
143
|
if (Symbol.dispose) AadBuilder.prototype[Symbol.dispose] = AadBuilder.prototype.free;
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
|
-
*
|
|
146
|
+
* maximum safe integer (2^53 - 1).
|
|
147
147
|
* @returns {number}
|
|
148
148
|
*/
|
|
149
149
|
export function MAX_SAFE_INTEGER() {
|
|
@@ -152,7 +152,7 @@ export function MAX_SAFE_INTEGER() {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
*
|
|
155
|
+
* maximum serialized AAD size in bytes (16 KiB).
|
|
156
156
|
* @returns {number}
|
|
157
157
|
*/
|
|
158
158
|
export function MAX_SERIALIZED_BYTES() {
|
|
@@ -161,7 +161,7 @@ export function MAX_SERIALIZED_BYTES() {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
|
-
*
|
|
164
|
+
* current AAD specification version (always 1).
|
|
165
165
|
* @returns {number}
|
|
166
166
|
*/
|
|
167
167
|
export function SPEC_VERSION() {
|
|
@@ -170,14 +170,14 @@ export function SPEC_VERSION() {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
*
|
|
173
|
+
* parses and canonicalizes a JSON string to bytes using the default AAD profile.
|
|
174
174
|
* @param {string} json
|
|
175
175
|
* @returns {Uint8Array}
|
|
176
176
|
*/
|
|
177
|
-
export function
|
|
177
|
+
export function canonicalizeDefault(json) {
|
|
178
178
|
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
179
179
|
const len0 = WASM_VECTOR_LEN;
|
|
180
|
-
const ret = wasm.
|
|
180
|
+
const ret = wasm.canonicalizeDefault(ptr0, len0);
|
|
181
181
|
if (ret[3]) {
|
|
182
182
|
throw takeFromExternrefTable0(ret[2]);
|
|
183
183
|
}
|
|
@@ -187,17 +187,17 @@ export function canonicalize(json) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/**
|
|
190
|
-
*
|
|
190
|
+
* parses and canonicalizes a JSON string to a UTF-8 string using the default AAD profile.
|
|
191
191
|
* @param {string} json
|
|
192
192
|
* @returns {string}
|
|
193
193
|
*/
|
|
194
|
-
export function
|
|
194
|
+
export function canonicalizeDefaultString(json) {
|
|
195
195
|
let deferred3_0;
|
|
196
196
|
let deferred3_1;
|
|
197
197
|
try {
|
|
198
198
|
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
199
199
|
const len0 = WASM_VECTOR_LEN;
|
|
200
|
-
const ret = wasm.
|
|
200
|
+
const ret = wasm.canonicalizeDefaultString(ptr0, len0);
|
|
201
201
|
var ptr2 = ret[0];
|
|
202
202
|
var len2 = ret[1];
|
|
203
203
|
if (ret[3]) {
|
|
@@ -213,7 +213,50 @@ export function canonicalizeString(json) {
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
/**
|
|
216
|
-
*
|
|
216
|
+
* canonicalizes any valid JSON object to bytes (core rules only, no profile fields required).
|
|
217
|
+
* @param {string} json
|
|
218
|
+
* @returns {Uint8Array}
|
|
219
|
+
*/
|
|
220
|
+
export function canonicalizeObject(json) {
|
|
221
|
+
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
222
|
+
const len0 = WASM_VECTOR_LEN;
|
|
223
|
+
const ret = wasm.canonicalizeObject(ptr0, len0);
|
|
224
|
+
if (ret[3]) {
|
|
225
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
226
|
+
}
|
|
227
|
+
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
228
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
229
|
+
return v2;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* canonicalizes any valid JSON object to a UTF-8 string (core rules only, no profile fields required).
|
|
234
|
+
* @param {string} json
|
|
235
|
+
* @returns {string}
|
|
236
|
+
*/
|
|
237
|
+
export function canonicalizeObjectString(json) {
|
|
238
|
+
let deferred3_0;
|
|
239
|
+
let deferred3_1;
|
|
240
|
+
try {
|
|
241
|
+
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
242
|
+
const len0 = WASM_VECTOR_LEN;
|
|
243
|
+
const ret = wasm.canonicalizeObjectString(ptr0, len0);
|
|
244
|
+
var ptr2 = ret[0];
|
|
245
|
+
var len2 = ret[1];
|
|
246
|
+
if (ret[3]) {
|
|
247
|
+
ptr2 = 0; len2 = 0;
|
|
248
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
249
|
+
}
|
|
250
|
+
deferred3_0 = ptr2;
|
|
251
|
+
deferred3_1 = len2;
|
|
252
|
+
return getStringFromWasm0(ptr2, len2);
|
|
253
|
+
} finally {
|
|
254
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* SHA-256 hash of the canonical JSON form (default AAD profile).
|
|
217
260
|
* @param {string} json
|
|
218
261
|
* @returns {Uint8Array}
|
|
219
262
|
*/
|
|
@@ -230,14 +273,27 @@ export function hash(json) {
|
|
|
230
273
|
}
|
|
231
274
|
|
|
232
275
|
/**
|
|
233
|
-
*
|
|
276
|
+
* validates a JSON string against the default AAD profile. Returns false on any error.
|
|
277
|
+
* @param {string} json
|
|
278
|
+
* @returns {boolean}
|
|
279
|
+
*/
|
|
280
|
+
export function validateDefault(json) {
|
|
281
|
+
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
282
|
+
const len0 = WASM_VECTOR_LEN;
|
|
283
|
+
const ret = wasm.validateDefault(ptr0, len0);
|
|
284
|
+
return ret !== 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* validates a JSON string against core rules only (size, duplicate keys, object shape).
|
|
289
|
+
* Returns false on any error.
|
|
234
290
|
* @param {string} json
|
|
235
291
|
* @returns {boolean}
|
|
236
292
|
*/
|
|
237
|
-
export function
|
|
293
|
+
export function validateObject(json) {
|
|
238
294
|
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
239
295
|
const len0 = WASM_VECTOR_LEN;
|
|
240
|
-
const ret = wasm.
|
|
296
|
+
const ret = wasm.validateObject(ptr0, len0);
|
|
241
297
|
return ret !== 0;
|
|
242
298
|
}
|
|
243
299
|
|
package/canaad_wasm_bg.wasm
CHANGED
|
Binary file
|
package/canaad_wasm_bg.wasm.d.ts
CHANGED
|
@@ -14,10 +14,13 @@ export const aadbuilder_purpose: (a: number, b: number, c: number) => number;
|
|
|
14
14
|
export const aadbuilder_resource: (a: number, b: number, c: number) => number;
|
|
15
15
|
export const aadbuilder_tenant: (a: number, b: number, c: number) => number;
|
|
16
16
|
export const aadbuilder_timestamp: (a: number, b: number) => number;
|
|
17
|
-
export const
|
|
18
|
-
export const
|
|
17
|
+
export const canonicalizeDefault: (a: number, b: number) => [number, number, number, number];
|
|
18
|
+
export const canonicalizeDefaultString: (a: number, b: number) => [number, number, number, number];
|
|
19
|
+
export const canonicalizeObject: (a: number, b: number) => [number, number, number, number];
|
|
20
|
+
export const canonicalizeObjectString: (a: number, b: number) => [number, number, number, number];
|
|
19
21
|
export const hash: (a: number, b: number) => [number, number, number, number];
|
|
20
|
-
export const
|
|
22
|
+
export const validateDefault: (a: number, b: number) => number;
|
|
23
|
+
export const validateObject: (a: number, b: number) => number;
|
|
21
24
|
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
22
25
|
export const __externref_table_dealloc: (a: number) => void;
|
|
23
26
|
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
package/package.json
CHANGED
|
@@ -1,47 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gnufoo/canaad",
|
|
3
|
-
"version": "0.5.1",
|
|
4
3
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"./meta": {
|
|
12
|
-
"types": "./meta.d.ts",
|
|
13
|
-
"import": "./meta.js"
|
|
14
|
-
},
|
|
15
|
-
"./tool": {
|
|
16
|
-
"types": "./tool.d.ts",
|
|
17
|
-
"import": "./tool.js"
|
|
18
|
-
},
|
|
19
|
-
"./init": {
|
|
20
|
-
"types": "./init.d.ts",
|
|
21
|
-
"import": "./init.js"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"zod": "^3.24.0"
|
|
4
|
+
"description": "WASM bindings for AAD canonicalization per RFC 8785",
|
|
5
|
+
"version": "2.0.0",
|
|
6
|
+
"license": "MIT OR Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gnufood/canaad"
|
|
26
10
|
},
|
|
27
11
|
"files": [
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
12
|
+
"canaad_wasm.js",
|
|
13
|
+
"canaad_wasm.d.ts",
|
|
14
|
+
"canaad_wasm_bg.wasm",
|
|
15
|
+
"canaad_wasm_bg.wasm.d.ts"
|
|
31
16
|
],
|
|
17
|
+
"types": "canaad_wasm.d.ts",
|
|
32
18
|
"sideEffects": false,
|
|
33
19
|
"keywords": [
|
|
34
20
|
"aead",
|
|
35
21
|
"aad",
|
|
36
22
|
"canonicalization",
|
|
37
23
|
"jcs",
|
|
38
|
-
"rfc8785"
|
|
39
|
-
"wasm"
|
|
24
|
+
"rfc8785"
|
|
40
25
|
],
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./canaad_wasm.d.ts",
|
|
29
|
+
"import": "./canaad_wasm.js"
|
|
30
|
+
}
|
|
45
31
|
},
|
|
46
32
|
"homepage": "https://gnu.foo/projects/canaad",
|
|
47
33
|
"bugs": {
|
package/canaad_wasm_bg.js
DELETED
|
@@ -1,527 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builder for constructing AAD objects programmatically.
|
|
3
|
-
*
|
|
4
|
-
* Provides a fluent API for building AAD with method chaining.
|
|
5
|
-
* All setter methods return a new builder to enable chaining.
|
|
6
|
-
*
|
|
7
|
-
* # Example (JavaScript)
|
|
8
|
-
*
|
|
9
|
-
* ```javascript
|
|
10
|
-
* const builder = new AadBuilder()
|
|
11
|
-
* .tenant("org_abc")
|
|
12
|
-
* .resource("secrets/db")
|
|
13
|
-
* .purpose("encryption")
|
|
14
|
-
* .timestamp(1706400000)
|
|
15
|
-
* .extensionString("x_vault_cluster", "us-east-1");
|
|
16
|
-
*
|
|
17
|
-
* const bytes = builder.build();
|
|
18
|
-
* const canonical = builder.buildString();
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export class AadBuilder {
|
|
22
|
-
static __wrap(ptr) {
|
|
23
|
-
ptr = ptr >>> 0;
|
|
24
|
-
const obj = Object.create(AadBuilder.prototype);
|
|
25
|
-
obj.__wbg_ptr = ptr;
|
|
26
|
-
AadBuilderFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
27
|
-
return obj;
|
|
28
|
-
}
|
|
29
|
-
__destroy_into_raw() {
|
|
30
|
-
const ptr = this.__wbg_ptr;
|
|
31
|
-
this.__wbg_ptr = 0;
|
|
32
|
-
AadBuilderFinalization.unregister(this);
|
|
33
|
-
return ptr;
|
|
34
|
-
}
|
|
35
|
-
free() {
|
|
36
|
-
const ptr = this.__destroy_into_raw();
|
|
37
|
-
wasm.__wbg_aadbuilder_free(ptr, 0);
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Builds the AAD and returns the canonical bytes.
|
|
41
|
-
*
|
|
42
|
-
* # Returns
|
|
43
|
-
*
|
|
44
|
-
* A `Uint8Array` containing the UTF-8 encoded canonical JSON.
|
|
45
|
-
*
|
|
46
|
-
* # Errors
|
|
47
|
-
*
|
|
48
|
-
* Throws a JavaScript error if:
|
|
49
|
-
* - Required fields (tenant, resource, purpose) are missing
|
|
50
|
-
* - Any field value is invalid
|
|
51
|
-
* - Extension keys don't match the required pattern
|
|
52
|
-
* - The serialized output exceeds 16 KiB
|
|
53
|
-
* @returns {Uint8Array}
|
|
54
|
-
*/
|
|
55
|
-
build() {
|
|
56
|
-
const ret = wasm.aadbuilder_build(this.__wbg_ptr);
|
|
57
|
-
if (ret[3]) {
|
|
58
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
59
|
-
}
|
|
60
|
-
var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
61
|
-
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
62
|
-
return v1;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Builds the AAD and returns the canonical string.
|
|
66
|
-
*
|
|
67
|
-
* # Returns
|
|
68
|
-
*
|
|
69
|
-
* The canonical (JCS) representation as a string.
|
|
70
|
-
*
|
|
71
|
-
* # Errors
|
|
72
|
-
*
|
|
73
|
-
* Throws a JavaScript error if:
|
|
74
|
-
* - Required fields (tenant, resource, purpose) are missing
|
|
75
|
-
* - Any field value is invalid
|
|
76
|
-
* - Extension keys don't match the required pattern
|
|
77
|
-
* - The serialized output exceeds 16 KiB
|
|
78
|
-
* @returns {string}
|
|
79
|
-
*/
|
|
80
|
-
buildString() {
|
|
81
|
-
let deferred2_0;
|
|
82
|
-
let deferred2_1;
|
|
83
|
-
try {
|
|
84
|
-
const ret = wasm.aadbuilder_buildString(this.__wbg_ptr);
|
|
85
|
-
var ptr1 = ret[0];
|
|
86
|
-
var len1 = ret[1];
|
|
87
|
-
if (ret[3]) {
|
|
88
|
-
ptr1 = 0; len1 = 0;
|
|
89
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
90
|
-
}
|
|
91
|
-
deferred2_0 = ptr1;
|
|
92
|
-
deferred2_1 = len1;
|
|
93
|
-
return getStringFromWasm0(ptr1, len1);
|
|
94
|
-
} finally {
|
|
95
|
-
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Adds an integer extension field.
|
|
100
|
-
*
|
|
101
|
-
* Extension keys must match pattern `x_<app>_<field>` where:
|
|
102
|
-
* - `<app>` is one or more lowercase letters
|
|
103
|
-
* - `<field>` is one or more lowercase letters or underscores
|
|
104
|
-
*
|
|
105
|
-
* # Arguments
|
|
106
|
-
*
|
|
107
|
-
* * `key` - Extension key (e.g., `x_app_priority`)
|
|
108
|
-
* * `value` - Integer value (0 to 2^53-1)
|
|
109
|
-
*
|
|
110
|
-
* # Returns
|
|
111
|
-
*
|
|
112
|
-
* A new builder with the extension added.
|
|
113
|
-
* @param {string} key
|
|
114
|
-
* @param {number} value
|
|
115
|
-
* @returns {AadBuilder}
|
|
116
|
-
*/
|
|
117
|
-
extensionInt(key, value) {
|
|
118
|
-
const ptr = this.__destroy_into_raw();
|
|
119
|
-
const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
120
|
-
const len0 = WASM_VECTOR_LEN;
|
|
121
|
-
const ret = wasm.aadbuilder_extensionInt(ptr, ptr0, len0, value);
|
|
122
|
-
return AadBuilder.__wrap(ret);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Adds a string extension field.
|
|
126
|
-
*
|
|
127
|
-
* Extension keys must match pattern `x_<app>_<field>` where:
|
|
128
|
-
* - `<app>` is one or more lowercase letters
|
|
129
|
-
* - `<field>` is one or more lowercase letters or underscores
|
|
130
|
-
*
|
|
131
|
-
* # Arguments
|
|
132
|
-
*
|
|
133
|
-
* * `key` - Extension key (e.g., `x_vault_cluster`)
|
|
134
|
-
* * `value` - String value (no NUL bytes)
|
|
135
|
-
*
|
|
136
|
-
* # Returns
|
|
137
|
-
*
|
|
138
|
-
* A new builder with the extension added.
|
|
139
|
-
* @param {string} key
|
|
140
|
-
* @param {string} value
|
|
141
|
-
* @returns {AadBuilder}
|
|
142
|
-
*/
|
|
143
|
-
extensionString(key, value) {
|
|
144
|
-
const ptr = this.__destroy_into_raw();
|
|
145
|
-
const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
146
|
-
const len0 = WASM_VECTOR_LEN;
|
|
147
|
-
const ptr1 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
148
|
-
const len1 = WASM_VECTOR_LEN;
|
|
149
|
-
const ret = wasm.aadbuilder_extensionString(ptr, ptr0, len0, ptr1, len1);
|
|
150
|
-
return AadBuilder.__wrap(ret);
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Creates a new AAD builder.
|
|
154
|
-
*/
|
|
155
|
-
constructor() {
|
|
156
|
-
const ret = wasm.aadbuilder_new();
|
|
157
|
-
this.__wbg_ptr = ret >>> 0;
|
|
158
|
-
AadBuilderFinalization.register(this, this.__wbg_ptr, this);
|
|
159
|
-
return this;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Sets the purpose or usage context.
|
|
163
|
-
*
|
|
164
|
-
* # Arguments
|
|
165
|
-
*
|
|
166
|
-
* * `value` - Purpose description (1+ bytes, no NUL bytes)
|
|
167
|
-
*
|
|
168
|
-
* # Returns
|
|
169
|
-
*
|
|
170
|
-
* A new builder with the purpose set.
|
|
171
|
-
* @param {string} value
|
|
172
|
-
* @returns {AadBuilder}
|
|
173
|
-
*/
|
|
174
|
-
purpose(value) {
|
|
175
|
-
const ptr = this.__destroy_into_raw();
|
|
176
|
-
const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
177
|
-
const len0 = WASM_VECTOR_LEN;
|
|
178
|
-
const ret = wasm.aadbuilder_purpose(ptr, ptr0, len0);
|
|
179
|
-
return AadBuilder.__wrap(ret);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Sets the resource path or identifier.
|
|
183
|
-
*
|
|
184
|
-
* # Arguments
|
|
185
|
-
*
|
|
186
|
-
* * `value` - Resource path (1-1024 bytes, no NUL bytes)
|
|
187
|
-
*
|
|
188
|
-
* # Returns
|
|
189
|
-
*
|
|
190
|
-
* A new builder with the resource set.
|
|
191
|
-
* @param {string} value
|
|
192
|
-
* @returns {AadBuilder}
|
|
193
|
-
*/
|
|
194
|
-
resource(value) {
|
|
195
|
-
const ptr = this.__destroy_into_raw();
|
|
196
|
-
const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
197
|
-
const len0 = WASM_VECTOR_LEN;
|
|
198
|
-
const ret = wasm.aadbuilder_resource(ptr, ptr0, len0);
|
|
199
|
-
return AadBuilder.__wrap(ret);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Sets the tenant identifier.
|
|
203
|
-
*
|
|
204
|
-
* # Arguments
|
|
205
|
-
*
|
|
206
|
-
* * `value` - Tenant identifier (1-256 bytes, no NUL bytes)
|
|
207
|
-
*
|
|
208
|
-
* # Returns
|
|
209
|
-
*
|
|
210
|
-
* A new builder with the tenant set.
|
|
211
|
-
* @param {string} value
|
|
212
|
-
* @returns {AadBuilder}
|
|
213
|
-
*/
|
|
214
|
-
tenant(value) {
|
|
215
|
-
const ptr = this.__destroy_into_raw();
|
|
216
|
-
const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
217
|
-
const len0 = WASM_VECTOR_LEN;
|
|
218
|
-
const ret = wasm.aadbuilder_tenant(ptr, ptr0, len0);
|
|
219
|
-
return AadBuilder.__wrap(ret);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Sets the timestamp.
|
|
223
|
-
*
|
|
224
|
-
* # Arguments
|
|
225
|
-
*
|
|
226
|
-
* * `ts` - Unix timestamp (0 to 2^53-1)
|
|
227
|
-
*
|
|
228
|
-
* # Returns
|
|
229
|
-
*
|
|
230
|
-
* A new builder with the timestamp set.
|
|
231
|
-
* @param {number} ts
|
|
232
|
-
* @returns {AadBuilder}
|
|
233
|
-
*/
|
|
234
|
-
timestamp(ts) {
|
|
235
|
-
const ptr = this.__destroy_into_raw();
|
|
236
|
-
const ret = wasm.aadbuilder_timestamp(ptr, ts);
|
|
237
|
-
return AadBuilder.__wrap(ret);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (Symbol.dispose) AadBuilder.prototype[Symbol.dispose] = AadBuilder.prototype.free;
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Returns the maximum safe integer value (2^53 - 1).
|
|
244
|
-
*
|
|
245
|
-
* This is the maximum integer value that can be exactly represented in
|
|
246
|
-
* JavaScript's Number type.
|
|
247
|
-
* @returns {number}
|
|
248
|
-
*/
|
|
249
|
-
export function MAX_SAFE_INTEGER() {
|
|
250
|
-
const ret = wasm.MAX_SAFE_INTEGER();
|
|
251
|
-
return ret;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Returns the maximum serialized AAD size in bytes (16 KiB).
|
|
256
|
-
* @returns {number}
|
|
257
|
-
*/
|
|
258
|
-
export function MAX_SERIALIZED_BYTES() {
|
|
259
|
-
const ret = wasm.MAX_SERIALIZED_BYTES();
|
|
260
|
-
return ret >>> 0;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Returns the current AAD specification version.
|
|
265
|
-
*
|
|
266
|
-
* Currently always returns 1.
|
|
267
|
-
* @returns {number}
|
|
268
|
-
*/
|
|
269
|
-
export function SPEC_VERSION() {
|
|
270
|
-
const ret = wasm.SPEC_VERSION();
|
|
271
|
-
return ret >>> 0;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Parses and canonicalizes a JSON string to bytes.
|
|
276
|
-
*
|
|
277
|
-
* This function:
|
|
278
|
-
* 1. Parses the JSON with duplicate key detection
|
|
279
|
-
* 2. Validates all fields according to the AAD specification
|
|
280
|
-
* 3. Returns the canonical (JCS) representation as bytes
|
|
281
|
-
*
|
|
282
|
-
* # Arguments
|
|
283
|
-
*
|
|
284
|
-
* * `json` - A JSON string containing an AAD object
|
|
285
|
-
*
|
|
286
|
-
* # Returns
|
|
287
|
-
*
|
|
288
|
-
* A `Uint8Array` containing the UTF-8 encoded canonical JSON.
|
|
289
|
-
*
|
|
290
|
-
* # Errors
|
|
291
|
-
*
|
|
292
|
-
* Throws a JavaScript error if:
|
|
293
|
-
* - The JSON is invalid or contains duplicate keys
|
|
294
|
-
* - Any field violates AAD constraints
|
|
295
|
-
* - The serialized output exceeds 16 KiB
|
|
296
|
-
* @param {string} json
|
|
297
|
-
* @returns {Uint8Array}
|
|
298
|
-
*/
|
|
299
|
-
export function canonicalize(json) {
|
|
300
|
-
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
301
|
-
const len0 = WASM_VECTOR_LEN;
|
|
302
|
-
const ret = wasm.canonicalize(ptr0, len0);
|
|
303
|
-
if (ret[3]) {
|
|
304
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
305
|
-
}
|
|
306
|
-
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
307
|
-
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
308
|
-
return v2;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Parses and canonicalizes a JSON string to a UTF-8 string.
|
|
313
|
-
*
|
|
314
|
-
* This is equivalent to `canonicalize` but returns a string instead of bytes.
|
|
315
|
-
*
|
|
316
|
-
* # Arguments
|
|
317
|
-
*
|
|
318
|
-
* * `json` - A JSON string containing an AAD object
|
|
319
|
-
*
|
|
320
|
-
* # Returns
|
|
321
|
-
*
|
|
322
|
-
* The canonical (JCS) representation as a string.
|
|
323
|
-
*
|
|
324
|
-
* # Errors
|
|
325
|
-
*
|
|
326
|
-
* Throws a JavaScript error if:
|
|
327
|
-
* - The JSON is invalid or contains duplicate keys
|
|
328
|
-
* - Any field violates AAD constraints
|
|
329
|
-
* - The serialized output exceeds 16 KiB
|
|
330
|
-
* @param {string} json
|
|
331
|
-
* @returns {string}
|
|
332
|
-
*/
|
|
333
|
-
export function canonicalizeString(json) {
|
|
334
|
-
let deferred3_0;
|
|
335
|
-
let deferred3_1;
|
|
336
|
-
try {
|
|
337
|
-
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
338
|
-
const len0 = WASM_VECTOR_LEN;
|
|
339
|
-
const ret = wasm.canonicalizeString(ptr0, len0);
|
|
340
|
-
var ptr2 = ret[0];
|
|
341
|
-
var len2 = ret[1];
|
|
342
|
-
if (ret[3]) {
|
|
343
|
-
ptr2 = 0; len2 = 0;
|
|
344
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
345
|
-
}
|
|
346
|
-
deferred3_0 = ptr2;
|
|
347
|
-
deferred3_1 = len2;
|
|
348
|
-
return getStringFromWasm0(ptr2, len2);
|
|
349
|
-
} finally {
|
|
350
|
-
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Computes the SHA-256 hash of the canonical JSON form.
|
|
356
|
-
*
|
|
357
|
-
* This function:
|
|
358
|
-
* 1. Parses and validates the JSON
|
|
359
|
-
* 2. Canonicalizes according to RFC 8785
|
|
360
|
-
* 3. Returns the SHA-256 hash of the canonical bytes
|
|
361
|
-
*
|
|
362
|
-
* # Arguments
|
|
363
|
-
*
|
|
364
|
-
* * `json` - A JSON string containing an AAD object
|
|
365
|
-
*
|
|
366
|
-
* # Returns
|
|
367
|
-
*
|
|
368
|
-
* A 32-byte `Uint8Array` containing the SHA-256 hash.
|
|
369
|
-
*
|
|
370
|
-
* # Errors
|
|
371
|
-
*
|
|
372
|
-
* Throws a JavaScript error if:
|
|
373
|
-
* - The JSON is invalid or contains duplicate keys
|
|
374
|
-
* - Any field violates AAD constraints
|
|
375
|
-
* - The serialized output exceeds 16 KiB
|
|
376
|
-
* @param {string} json
|
|
377
|
-
* @returns {Uint8Array}
|
|
378
|
-
*/
|
|
379
|
-
export function hash(json) {
|
|
380
|
-
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
381
|
-
const len0 = WASM_VECTOR_LEN;
|
|
382
|
-
const ret = wasm.hash(ptr0, len0);
|
|
383
|
-
if (ret[3]) {
|
|
384
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
385
|
-
}
|
|
386
|
-
var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
387
|
-
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
388
|
-
return v2;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Validates a JSON string against the AAD specification.
|
|
393
|
-
*
|
|
394
|
-
* This function performs full validation without returning the context.
|
|
395
|
-
* Use this for quick validation checks.
|
|
396
|
-
*
|
|
397
|
-
* # Arguments
|
|
398
|
-
*
|
|
399
|
-
* * `json` - A JSON string to validate
|
|
400
|
-
*
|
|
401
|
-
* # Returns
|
|
402
|
-
*
|
|
403
|
-
* `true` if the JSON is valid AAD, `false` otherwise.
|
|
404
|
-
* @param {string} json
|
|
405
|
-
* @returns {boolean}
|
|
406
|
-
*/
|
|
407
|
-
export function validate(json) {
|
|
408
|
-
const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
409
|
-
const len0 = WASM_VECTOR_LEN;
|
|
410
|
-
const ret = wasm.validate(ptr0, len0);
|
|
411
|
-
return ret !== 0;
|
|
412
|
-
}
|
|
413
|
-
export function __wbg_Error_8c4e43fe74559d73(arg0, arg1) {
|
|
414
|
-
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
415
|
-
return ret;
|
|
416
|
-
}
|
|
417
|
-
export function __wbg___wbindgen_throw_be289d5034ed271b(arg0, arg1) {
|
|
418
|
-
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
419
|
-
}
|
|
420
|
-
export function __wbindgen_init_externref_table() {
|
|
421
|
-
const table = wasm.__wbindgen_externrefs;
|
|
422
|
-
const offset = table.grow(4);
|
|
423
|
-
table.set(0, undefined);
|
|
424
|
-
table.set(offset + 0, undefined);
|
|
425
|
-
table.set(offset + 1, null);
|
|
426
|
-
table.set(offset + 2, true);
|
|
427
|
-
table.set(offset + 3, false);
|
|
428
|
-
}
|
|
429
|
-
const AadBuilderFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
430
|
-
? { register: () => {}, unregister: () => {} }
|
|
431
|
-
: new FinalizationRegistry(ptr => wasm.__wbg_aadbuilder_free(ptr >>> 0, 1));
|
|
432
|
-
|
|
433
|
-
function getArrayU8FromWasm0(ptr, len) {
|
|
434
|
-
ptr = ptr >>> 0;
|
|
435
|
-
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function getStringFromWasm0(ptr, len) {
|
|
439
|
-
ptr = ptr >>> 0;
|
|
440
|
-
return decodeText(ptr, len);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
let cachedUint8ArrayMemory0 = null;
|
|
444
|
-
function getUint8ArrayMemory0() {
|
|
445
|
-
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
446
|
-
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
447
|
-
}
|
|
448
|
-
return cachedUint8ArrayMemory0;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function passStringToWasm0(arg, malloc, realloc) {
|
|
452
|
-
if (realloc === undefined) {
|
|
453
|
-
const buf = cachedTextEncoder.encode(arg);
|
|
454
|
-
const ptr = malloc(buf.length, 1) >>> 0;
|
|
455
|
-
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
456
|
-
WASM_VECTOR_LEN = buf.length;
|
|
457
|
-
return ptr;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
let len = arg.length;
|
|
461
|
-
let ptr = malloc(len, 1) >>> 0;
|
|
462
|
-
|
|
463
|
-
const mem = getUint8ArrayMemory0();
|
|
464
|
-
|
|
465
|
-
let offset = 0;
|
|
466
|
-
|
|
467
|
-
for (; offset < len; offset++) {
|
|
468
|
-
const code = arg.charCodeAt(offset);
|
|
469
|
-
if (code > 0x7F) break;
|
|
470
|
-
mem[ptr + offset] = code;
|
|
471
|
-
}
|
|
472
|
-
if (offset !== len) {
|
|
473
|
-
if (offset !== 0) {
|
|
474
|
-
arg = arg.slice(offset);
|
|
475
|
-
}
|
|
476
|
-
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
477
|
-
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
478
|
-
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
479
|
-
|
|
480
|
-
offset += ret.written;
|
|
481
|
-
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
WASM_VECTOR_LEN = offset;
|
|
485
|
-
return ptr;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
function takeFromExternrefTable0(idx) {
|
|
489
|
-
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
490
|
-
wasm.__externref_table_dealloc(idx);
|
|
491
|
-
return value;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
495
|
-
cachedTextDecoder.decode();
|
|
496
|
-
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
497
|
-
let numBytesDecoded = 0;
|
|
498
|
-
function decodeText(ptr, len) {
|
|
499
|
-
numBytesDecoded += len;
|
|
500
|
-
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
501
|
-
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
502
|
-
cachedTextDecoder.decode();
|
|
503
|
-
numBytesDecoded = len;
|
|
504
|
-
}
|
|
505
|
-
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const cachedTextEncoder = new TextEncoder();
|
|
509
|
-
|
|
510
|
-
if (!('encodeInto' in cachedTextEncoder)) {
|
|
511
|
-
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
512
|
-
const buf = cachedTextEncoder.encode(arg);
|
|
513
|
-
view.set(buf);
|
|
514
|
-
return {
|
|
515
|
-
read: arg.length,
|
|
516
|
-
written: buf.length
|
|
517
|
-
};
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
let WASM_VECTOR_LEN = 0;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
let wasm;
|
|
525
|
-
export function __wbg_set_wasm(val) {
|
|
526
|
-
wasm = val;
|
|
527
|
-
}
|
package/errors.d.ts
DELETED
package/errors.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/** Thrown when an operation is called before `initWasm()` completes. */
|
|
2
|
-
export class WasmNotInitializedError extends Error {
|
|
3
|
-
/** Discriminant for branded error handling — always `'WasmNotInitializedError'`. */
|
|
4
|
-
kind = 'WasmNotInitializedError';
|
|
5
|
-
|
|
6
|
-
constructor() {
|
|
7
|
-
super('WASM not initialized. Call initWasm() first.');
|
|
8
|
-
this.name = 'WasmNotInitializedError';
|
|
9
|
-
}
|
|
10
|
-
}
|
package/init.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Initialize WASM. Call once before using any WASM functions.
|
|
3
|
-
*
|
|
4
|
-
* @param wasmModule - pass a precompiled WebAssembly.Module in Workers, omit in browser
|
|
5
|
-
*/
|
|
6
|
-
export function initWasm(wasmModule?: WebAssembly.Module): Promise<void>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* True if WASM has been initialized via `initWasm()`.
|
|
10
|
-
*/
|
|
11
|
-
export function isInitialized(): boolean;
|
package/init.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import init from './canaad_wasm.js';
|
|
2
|
-
|
|
3
|
-
let initialized = false;
|
|
4
|
-
let initPromise = null;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Initialize WASM. Call once before using any WASM functions.
|
|
8
|
-
*
|
|
9
|
-
* @param {WebAssembly.Module | undefined} wasmModule - pass a precompiled module in Workers, omit in browser
|
|
10
|
-
*/
|
|
11
|
-
export async function initWasm(wasmModule) {
|
|
12
|
-
if (initialized) return;
|
|
13
|
-
if (initPromise) return initPromise;
|
|
14
|
-
|
|
15
|
-
initPromise = init(wasmModule).then(() => {
|
|
16
|
-
initialized = true;
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
return initPromise;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* True if WASM has been initialized via `initWasm()`.
|
|
24
|
-
*/
|
|
25
|
-
export function isInitialized() {
|
|
26
|
-
return initialized;
|
|
27
|
-
}
|
package/meta.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
/** Validates and parses all AAD action inputs. */
|
|
4
|
-
export declare const inputSchema: z.ZodType;
|
|
5
|
-
|
|
6
|
-
/** Validates and parses all AAD action outputs. */
|
|
7
|
-
export declare const outputSchema: z.ZodType;
|
|
8
|
-
|
|
9
|
-
/** Discriminated union of all action input shapes. */
|
|
10
|
-
export type CanaadInput = z.infer<typeof inputSchema>;
|
|
11
|
-
|
|
12
|
-
/** Discriminated union of all action output shapes. */
|
|
13
|
-
export type CanaadOutput = z.infer<typeof outputSchema>;
|
|
14
|
-
|
|
15
|
-
/** Tool metadata: id, name, slug, description, category, execution type, positional args, schemas, and optional registry links. */
|
|
16
|
-
export declare const meta: {
|
|
17
|
-
id: string;
|
|
18
|
-
name: string;
|
|
19
|
-
slug: string;
|
|
20
|
-
description: string;
|
|
21
|
-
category: string;
|
|
22
|
-
executionType: string;
|
|
23
|
-
positionalArgs: { order: string[]; required: number };
|
|
24
|
-
packages?: { npm?: string; crates?: string };
|
|
25
|
-
inputSchema: typeof inputSchema;
|
|
26
|
-
outputSchema: typeof outputSchema;
|
|
27
|
-
};
|
package/meta.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
// AAD spec: tenant field capped at 256 UTF-8 bytes.
|
|
4
|
-
const TENANT_MAX_BYTES = 256;
|
|
5
|
-
// AAD spec: resource field capped at 1024 UTF-8 bytes.
|
|
6
|
-
const RESOURCE_MAX_BYTES = 1024;
|
|
7
|
-
const encoder = new TextEncoder();
|
|
8
|
-
|
|
9
|
-
const extensionSchema = z.object({
|
|
10
|
-
key: z.string().regex(/^x_[a-z]+_[a-z_]+$/),
|
|
11
|
-
value: z.union([z.string(), z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER)]),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export const inputSchema = z.discriminatedUnion('action', [
|
|
15
|
-
z.object({
|
|
16
|
-
action: z.literal('canonicalize'),
|
|
17
|
-
input: z.string(),
|
|
18
|
-
outputFormat: z.enum(['bytes', 'string']).default('string'),
|
|
19
|
-
}),
|
|
20
|
-
z.object({
|
|
21
|
-
action: z.literal('validate'),
|
|
22
|
-
input: z.string(),
|
|
23
|
-
}),
|
|
24
|
-
z.object({
|
|
25
|
-
action: z.literal('hash'),
|
|
26
|
-
input: z.string(),
|
|
27
|
-
outputFormat: z.enum(['hex', 'base64']).default('hex'),
|
|
28
|
-
}),
|
|
29
|
-
z.object({
|
|
30
|
-
action: z.literal('build'),
|
|
31
|
-
tenant: z.string().min(1).refine(s => encoder.encode(s).length <= TENANT_MAX_BYTES, `tenant exceeds ${TENANT_MAX_BYTES} bytes`),
|
|
32
|
-
resource: z.string().min(1).refine(s => encoder.encode(s).length <= RESOURCE_MAX_BYTES, `resource exceeds ${RESOURCE_MAX_BYTES} bytes`),
|
|
33
|
-
purpose: z.string().min(1),
|
|
34
|
-
timestamp: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
35
|
-
extensions: z.array(extensionSchema).optional(),
|
|
36
|
-
outputFormat: z.enum(['bytes', 'string']).default('string'),
|
|
37
|
-
}),
|
|
38
|
-
]);
|
|
39
|
-
|
|
40
|
-
export const outputSchema = z.discriminatedUnion('action', [
|
|
41
|
-
z.object({ action: z.literal('canonicalize'), output: z.union([z.string(), z.array(z.number())]), outputFormat: z.enum(['bytes', 'string']) }),
|
|
42
|
-
z.object({ action: z.literal('validate'), valid: z.boolean() }),
|
|
43
|
-
z.object({ action: z.literal('hash'), hash: z.string(), outputFormat: z.enum(['hex', 'base64']) }),
|
|
44
|
-
z.object({ action: z.literal('build'), output: z.union([z.string(), z.array(z.number())]), outputFormat: z.enum(['bytes', 'string']) }),
|
|
45
|
-
]);
|
|
46
|
-
|
|
47
|
-
export const meta = {
|
|
48
|
-
id: 'canaad',
|
|
49
|
-
name: 'canaad',
|
|
50
|
-
slug: 'canaad',
|
|
51
|
-
description: 'canonicalize JSON for AAD (Additional Authenticated Data) per RFC 8785',
|
|
52
|
-
category: 'crypto',
|
|
53
|
-
executionType: 'hybrid',
|
|
54
|
-
positionalArgs: { order: ['action', 'input'], required: 1 },
|
|
55
|
-
packages: {
|
|
56
|
-
npm: '@gnufoo/canaad',
|
|
57
|
-
crates: 'canaad-core',
|
|
58
|
-
},
|
|
59
|
-
inputSchema,
|
|
60
|
-
outputSchema,
|
|
61
|
-
};
|
package/tool.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { meta, CanaadInput, CanaadOutput } from './meta.js';
|
|
2
|
-
import type { initWasm, isInitialized } from './init.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Main tool export. Merges AAD metadata with WASM lifecycle methods and the action dispatcher.
|
|
6
|
-
*/
|
|
7
|
-
export declare const toolDefinition: typeof meta & {
|
|
8
|
-
initWasm: typeof initWasm;
|
|
9
|
-
isInitialized: typeof isInitialized;
|
|
10
|
-
/** Dispatches an AAD action to WASM. Requires prior `initWasm()` call. */
|
|
11
|
-
execute(input: CanaadInput): Promise<CanaadOutput>;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export { WasmNotInitializedError } from './errors.js';
|
package/tool.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { meta, inputSchema } from './meta.js';
|
|
2
|
-
import { initWasm, isInitialized } from './init.js';
|
|
3
|
-
import { canonicalize, canonicalizeString, hash, validate, AadBuilder } from './canaad_wasm.js';
|
|
4
|
-
import { WasmNotInitializedError } from './errors.js';
|
|
5
|
-
const bytesToHex = (bytes) => Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
6
|
-
const bytesToBase64 = (bytes) => globalThis.btoa(String.fromCharCode(...bytes));
|
|
7
|
-
/**
|
|
8
|
-
* Main tool export. Merges AAD metadata with WASM lifecycle methods and the action dispatcher.
|
|
9
|
-
*/
|
|
10
|
-
export const toolDefinition = {
|
|
11
|
-
...meta,
|
|
12
|
-
initWasm,
|
|
13
|
-
isInitialized,
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Dispatches an AAD action to WASM. Requires prior `initWasm()` call.
|
|
17
|
-
*/
|
|
18
|
-
async execute(rawInput) {
|
|
19
|
-
if (!isInitialized()) {
|
|
20
|
-
throw new WasmNotInitializedError();
|
|
21
|
-
}
|
|
22
|
-
const input = inputSchema.parse(rawInput);
|
|
23
|
-
switch (input.action) {
|
|
24
|
-
case 'canonicalize': {
|
|
25
|
-
if (input.outputFormat === 'bytes') {
|
|
26
|
-
return { action: 'canonicalize', output: Array.from(canonicalize(input.input)), outputFormat: 'bytes' };
|
|
27
|
-
}
|
|
28
|
-
return { action: 'canonicalize', output: canonicalizeString(input.input), outputFormat: 'string' };
|
|
29
|
-
}
|
|
30
|
-
case 'validate':
|
|
31
|
-
return { action: 'validate', valid: validate(input.input) };
|
|
32
|
-
case 'hash': {
|
|
33
|
-
const h = hash(input.input);
|
|
34
|
-
return { action: 'hash', hash: input.outputFormat === 'base64' ? bytesToBase64(h) : bytesToHex(h), outputFormat: input.outputFormat };
|
|
35
|
-
}
|
|
36
|
-
case 'build': {
|
|
37
|
-
let b = new AadBuilder().tenant(input.tenant).resource(input.resource).purpose(input.purpose);
|
|
38
|
-
if (input.timestamp !== undefined) b = b.timestamp(input.timestamp);
|
|
39
|
-
for (const ext of input.extensions || []) {
|
|
40
|
-
b = typeof ext.value === 'string' ? b.extensionString(ext.key, ext.value) : b.extensionInt(ext.key, ext.value);
|
|
41
|
-
}
|
|
42
|
-
if (input.outputFormat === 'bytes') {
|
|
43
|
-
return { action: 'build', output: Array.from(b.build()), outputFormat: 'bytes' };
|
|
44
|
-
}
|
|
45
|
-
return { action: 'build', output: b.buildString(), outputFormat: 'string' };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
export { WasmNotInitializedError } from './errors.js';
|