@axiam/opaque-wasm 1.0.0-alpha32

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,60 @@
1
+ # axiam-opaque-wasm
2
+
3
+ WebAssembly build of AXIAM's OPAQUE (RFC 9807) client, published to npm as
4
+ `@axiam/opaque-wasm` and consumed by the TypeScript SDK and the React admin UI.
5
+
6
+ ## Why this exists
7
+
8
+ `sdks/CONTRACT.md` §23.1 forbids an SDK from implementing OPAQUE itself. SRP was
9
+ hand-written eleven times because it is modular arithmetic and every language
10
+ has a bignum; OPAQUE needs an oblivious PRF, `hash_to_curve`,
11
+ `expand_message_xmd`, an envelope construction and a three-message AKE. So there
12
+ is one implementation — `crates/axiam-opaque` — and this crate is how JavaScript
13
+ reaches it.
14
+
15
+ ## Building
16
+
17
+ ```bash
18
+ wasm-pack build --target web --release crates/axiam-opaque-wasm
19
+ ```
20
+
21
+ Not a Cargo workspace member on purpose: it only ever builds for `wasm32`, and
22
+ including it would make a plain `cargo test` at the repository root try to
23
+ compile `wasm-bindgen` for the host.
24
+
25
+ ## Usage
26
+
27
+ ```js
28
+ import init, { OpaqueLogin, OpaqueKsf } from "@axiam/opaque-wasm";
29
+
30
+ await init();
31
+
32
+ // 1. Blind the password and start the exchange.
33
+ const login = new OpaqueLogin(password);
34
+ const started = await postJson("/api/v1/auth/opaque/login/start", {
35
+ org_slug, tenant_slug, username_or_email, ke1: login.ke1,
36
+ });
37
+
38
+ // 2. Build the KSF from what the SERVER named — never from local defaults.
39
+ const ksf = started.ksf === "argon2id"
40
+ ? OpaqueKsf.argon2id(started.memory_kib, started.iterations, started.parallelism)
41
+ : OpaqueKsf.scrypt(started.log_n, started.r, started.p);
42
+
43
+ // 3. Open the envelope. A throw here means wrong password, unknown account,
44
+ // or a server that does not hold the record — indistinguishable by design,
45
+ // and nothing further may be posted.
46
+ const finished = login.finish(password, started.ke2, ksf);
47
+
48
+ await postJson("/api/v1/auth/opaque/login/finish", {
49
+ opaque_session: started.opaque_session,
50
+ ke3: finished.ke3,
51
+ });
52
+ ```
53
+
54
+ `login` is **consumed** by `finish`: a second call throws rather than reusing
55
+ one OPRF blind across two exchanges.
56
+
57
+ ## What this does not do
58
+
59
+ It performs no HTTP. Endpoint selection, cookie handling and error mapping
60
+ belong to the SDK or application that calls it — see CONTRACT §23.4 and §23.5.
@@ -0,0 +1,212 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Key-stretching parameters, as named by the server.
6
+ *
7
+ * A caller MUST build this from the `ksf` fields of a `register/start` or
8
+ * `login/start` response rather than from its own configuration: a credential
9
+ * enrolled under one cost keeps working after a tenant raises its policy, so a
10
+ * client that guessed would derive a different randomized password and fail
11
+ * against a record that is perfectly good.
12
+ */
13
+ export class OpaqueKsf {
14
+ private constructor();
15
+ free(): void;
16
+ [Symbol.dispose](): void;
17
+ /**
18
+ * Argon2id parameters, range-checked per CONTRACT §23.4 rule 4.
19
+ */
20
+ static argon2id(memory_kib: number, iterations: number, parallelism: number): OpaqueKsf;
21
+ /**
22
+ * scrypt parameters, range-checked per CONTRACT §23.4 rule 4.
23
+ */
24
+ static scrypt(log_n: number, r: number, p: number): OpaqueKsf;
25
+ }
26
+
27
+ /**
28
+ * In-flight login state.
29
+ */
30
+ export class OpaqueLogin {
31
+ free(): void;
32
+ [Symbol.dispose](): void;
33
+ /**
34
+ * Open the envelope and produce `KE3`. **Consumes** this object.
35
+ *
36
+ * A thrown error here is the *whole* of the client's authentication check,
37
+ * and it covers both halves of the mutual authentication: the envelope
38
+ * only opens under the right password, and `KE2`'s MAC only verifies if
39
+ * the server actually holds the record. Per CONTRACT §23.4 rule 7 the
40
+ * caller MUST NOT post anything to `login/finish` after it throws.
41
+ */
42
+ finish(password: string, ke2: string, ksf: OpaqueKsf): OpaqueLoginResult;
43
+ /**
44
+ * Blind the password and generate the client's ephemeral share.
45
+ */
46
+ constructor(password: string);
47
+ /**
48
+ * Hex `KE1`, to post to `/auth/opaque/login/start`.
49
+ */
50
+ readonly ke1: string;
51
+ }
52
+
53
+ /**
54
+ * The result of a completed login.
55
+ */
56
+ export class OpaqueLoginResult {
57
+ private constructor();
58
+ free(): void;
59
+ [Symbol.dispose](): void;
60
+ /**
61
+ * Hex `export_key`, identical to the enrolment's for the same password.
62
+ */
63
+ readonly exportKey: string;
64
+ /**
65
+ * Hex `KE3`, to post to `/auth/opaque/login/finish`.
66
+ */
67
+ readonly ke3: string;
68
+ /**
69
+ * Hex mutually authenticated session key. AXIAM issues ordinary session
70
+ * cookies rather than binding anything to this.
71
+ */
72
+ readonly sessionKey: string;
73
+ }
74
+
75
+ /**
76
+ * In-flight registration state.
77
+ */
78
+ export class OpaqueRegistration {
79
+ free(): void;
80
+ [Symbol.dispose](): void;
81
+ /**
82
+ * Unblind, stretch and seal the envelope. **Consumes** this object.
83
+ */
84
+ finish(password: string, registration_response: string, ksf: OpaqueKsf): OpaqueRegistrationResult;
85
+ /**
86
+ * Blind the password. The `request` getter carries the hex
87
+ * `RegistrationRequest` to post to `/auth/opaque/register/start`.
88
+ */
89
+ constructor(password: string);
90
+ /**
91
+ * Hex `RegistrationRequest`.
92
+ */
93
+ readonly request: string;
94
+ }
95
+
96
+ /**
97
+ * The result of a completed enrolment.
98
+ */
99
+ export class OpaqueRegistrationResult {
100
+ private constructor();
101
+ free(): void;
102
+ [Symbol.dispose](): void;
103
+ /**
104
+ * Hex `export_key`. AXIAM does not use it and no endpoint accepts it; it
105
+ * is surfaced because it cannot be re-derived later without the password.
106
+ */
107
+ readonly exportKey: string;
108
+ /**
109
+ * Hex `RegistrationRecord`, to embed in the request body's `opaque` object.
110
+ */
111
+ readonly record: string;
112
+ }
113
+
114
+ /**
115
+ * Run a complete OPAQUE registration and login inside this module, for
116
+ * release smoke-testing.
117
+ *
118
+ * # Why this is exported
119
+ *
120
+ * An old `binaryen` silently miscompiles WebAssembly built from this crate:
121
+ * `wasm-pack` reports success and the elliptic-curve arithmetic inside is
122
+ * wrong. "It built" is therefore not evidence that the artifact works, and the
123
+ * failure would surface as users who cannot log in.
124
+ *
125
+ * There is no fixed input to replay against — OPAQUE's blind is generated
126
+ * inside the protocol and is not injectable — so the available check is to
127
+ * perform both halves of a real exchange and assert they agree. A miscompiled
128
+ * scalar multiplication produces an envelope that will not open, which is
129
+ * exactly what this catches.
130
+ *
131
+ * Returns `true` on success and throws on failure, so a smoke test can assert
132
+ * on either.
133
+ *
134
+ * **Never call this in application code.** It talks to no server and
135
+ * authenticates nobody.
136
+ */
137
+ export function __conformanceRoundTrip(): boolean;
138
+
139
+ /**
140
+ * Non-zero when this build can perform OPAQUE.
141
+ *
142
+ * Always `true` — if the module instantiated, it works. It exists so a
143
+ * TypeScript `opaqueAvailable()` (CONTRACT §23.2) has something to call after
144
+ * a successful `init()`, and so a build whose WASM failed to load can answer
145
+ * the same question with `false` without a special case.
146
+ */
147
+ export function opaqueAvailable(): boolean;
148
+
149
+ /**
150
+ * Install the panic hook so a Rust panic surfaces as a stack trace in the
151
+ * browser console rather than `unreachable executed`.
152
+ *
153
+ * Idempotent; a caller may invoke it once at module init.
154
+ */
155
+ export function start(): void;
156
+
157
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
158
+
159
+ export interface InitOutput {
160
+ readonly memory: WebAssembly.Memory;
161
+ readonly __conformanceRoundTrip: () => [number, number, number];
162
+ readonly __wbg_opaqueksf_free: (a: number, b: number) => void;
163
+ readonly __wbg_opaquelogin_free: (a: number, b: number) => void;
164
+ readonly __wbg_opaqueloginresult_free: (a: number, b: number) => void;
165
+ readonly __wbg_opaqueregistration_free: (a: number, b: number) => void;
166
+ readonly __wbg_opaqueregistrationresult_free: (a: number, b: number) => void;
167
+ readonly opaqueAvailable: () => number;
168
+ readonly opaqueksf_argon2id: (a: number, b: number, c: number) => [number, number, number];
169
+ readonly opaqueksf_scrypt: (a: number, b: number, c: number) => [number, number, number];
170
+ readonly opaquelogin_finish: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
171
+ readonly opaquelogin_ke1: (a: number) => [number, number];
172
+ readonly opaquelogin_new: (a: number, b: number) => [number, number, number];
173
+ readonly opaqueloginresult_exportKey: (a: number) => [number, number];
174
+ readonly opaqueloginresult_ke3: (a: number) => [number, number];
175
+ readonly opaqueloginresult_sessionKey: (a: number) => [number, number];
176
+ readonly opaqueregistration_finish: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
177
+ readonly opaqueregistration_new: (a: number, b: number) => [number, number, number];
178
+ readonly opaqueregistration_request: (a: number) => [number, number];
179
+ readonly opaqueregistrationresult_exportKey: (a: number) => [number, number];
180
+ readonly opaqueregistrationresult_record: (a: number) => [number, number];
181
+ readonly start: () => void;
182
+ readonly __wbindgen_exn_store: (a: number) => void;
183
+ readonly __externref_table_alloc: () => number;
184
+ readonly __wbindgen_externrefs: WebAssembly.Table;
185
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
186
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
187
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
188
+ readonly __externref_table_dealloc: (a: number) => void;
189
+ readonly __wbindgen_start: () => void;
190
+ }
191
+
192
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
193
+
194
+ /**
195
+ * Instantiates the given `module`, which can either be bytes or
196
+ * a precompiled `WebAssembly.Module`.
197
+ *
198
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
199
+ *
200
+ * @returns {InitOutput}
201
+ */
202
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
203
+
204
+ /**
205
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
206
+ * for everything else, calls `WebAssembly.instantiate` directly.
207
+ *
208
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
209
+ *
210
+ * @returns {Promise<InitOutput>}
211
+ */
212
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,760 @@
1
+ /* @ts-self-types="./axiam_opaque.d.ts" */
2
+
3
+ /**
4
+ * Key-stretching parameters, as named by the server.
5
+ *
6
+ * A caller MUST build this from the `ksf` fields of a `register/start` or
7
+ * `login/start` response rather than from its own configuration: a credential
8
+ * enrolled under one cost keeps working after a tenant raises its policy, so a
9
+ * client that guessed would derive a different randomized password and fail
10
+ * against a record that is perfectly good.
11
+ */
12
+ export class OpaqueKsf {
13
+ static __wrap(ptr) {
14
+ const obj = Object.create(OpaqueKsf.prototype);
15
+ obj.__wbg_ptr = ptr;
16
+ OpaqueKsfFinalization.register(obj, obj.__wbg_ptr, obj);
17
+ return obj;
18
+ }
19
+ __destroy_into_raw() {
20
+ const ptr = this.__wbg_ptr;
21
+ this.__wbg_ptr = 0;
22
+ OpaqueKsfFinalization.unregister(this);
23
+ return ptr;
24
+ }
25
+ free() {
26
+ const ptr = this.__destroy_into_raw();
27
+ wasm.__wbg_opaqueksf_free(ptr, 0);
28
+ }
29
+ /**
30
+ * Argon2id parameters, range-checked per CONTRACT §23.4 rule 4.
31
+ * @param {number} memory_kib
32
+ * @param {number} iterations
33
+ * @param {number} parallelism
34
+ * @returns {OpaqueKsf}
35
+ */
36
+ static argon2id(memory_kib, iterations, parallelism) {
37
+ const ret = wasm.opaqueksf_argon2id(memory_kib, iterations, parallelism);
38
+ if (ret[2]) {
39
+ throw takeFromExternrefTable0(ret[1]);
40
+ }
41
+ return OpaqueKsf.__wrap(ret[0]);
42
+ }
43
+ /**
44
+ * scrypt parameters, range-checked per CONTRACT §23.4 rule 4.
45
+ * @param {number} log_n
46
+ * @param {number} r
47
+ * @param {number} p
48
+ * @returns {OpaqueKsf}
49
+ */
50
+ static scrypt(log_n, r, p) {
51
+ const ret = wasm.opaqueksf_scrypt(log_n, r, p);
52
+ if (ret[2]) {
53
+ throw takeFromExternrefTable0(ret[1]);
54
+ }
55
+ return OpaqueKsf.__wrap(ret[0]);
56
+ }
57
+ }
58
+ if (Symbol.dispose) OpaqueKsf.prototype[Symbol.dispose] = OpaqueKsf.prototype.free;
59
+
60
+ /**
61
+ * In-flight login state.
62
+ */
63
+ export class OpaqueLogin {
64
+ __destroy_into_raw() {
65
+ const ptr = this.__wbg_ptr;
66
+ this.__wbg_ptr = 0;
67
+ OpaqueLoginFinalization.unregister(this);
68
+ return ptr;
69
+ }
70
+ free() {
71
+ const ptr = this.__destroy_into_raw();
72
+ wasm.__wbg_opaquelogin_free(ptr, 0);
73
+ }
74
+ /**
75
+ * Open the envelope and produce `KE3`. **Consumes** this object.
76
+ *
77
+ * A thrown error here is the *whole* of the client's authentication check,
78
+ * and it covers both halves of the mutual authentication: the envelope
79
+ * only opens under the right password, and `KE2`'s MAC only verifies if
80
+ * the server actually holds the record. Per CONTRACT §23.4 rule 7 the
81
+ * caller MUST NOT post anything to `login/finish` after it throws.
82
+ * @param {string} password
83
+ * @param {string} ke2
84
+ * @param {OpaqueKsf} ksf
85
+ * @returns {OpaqueLoginResult}
86
+ */
87
+ finish(password, ke2, ksf) {
88
+ const ptr = this.__destroy_into_raw();
89
+ const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
90
+ const len0 = WASM_VECTOR_LEN;
91
+ const ptr1 = passStringToWasm0(ke2, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
92
+ const len1 = WASM_VECTOR_LEN;
93
+ _assertClass(ksf, OpaqueKsf);
94
+ const ret = wasm.opaquelogin_finish(ptr, ptr0, len0, ptr1, len1, ksf.__wbg_ptr);
95
+ if (ret[2]) {
96
+ throw takeFromExternrefTable0(ret[1]);
97
+ }
98
+ return OpaqueLoginResult.__wrap(ret[0]);
99
+ }
100
+ /**
101
+ * Hex `KE1`, to post to `/auth/opaque/login/start`.
102
+ * @returns {string}
103
+ */
104
+ get ke1() {
105
+ let deferred1_0;
106
+ let deferred1_1;
107
+ try {
108
+ const ret = wasm.opaquelogin_ke1(this.__wbg_ptr);
109
+ deferred1_0 = ret[0];
110
+ deferred1_1 = ret[1];
111
+ return getStringFromWasm0(ret[0], ret[1]);
112
+ } finally {
113
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
114
+ }
115
+ }
116
+ /**
117
+ * Blind the password and generate the client's ephemeral share.
118
+ * @param {string} password
119
+ */
120
+ constructor(password) {
121
+ const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
122
+ const len0 = WASM_VECTOR_LEN;
123
+ const ret = wasm.opaquelogin_new(ptr0, len0);
124
+ if (ret[2]) {
125
+ throw takeFromExternrefTable0(ret[1]);
126
+ }
127
+ this.__wbg_ptr = ret[0];
128
+ OpaqueLoginFinalization.register(this, this.__wbg_ptr, this);
129
+ return this;
130
+ }
131
+ }
132
+ if (Symbol.dispose) OpaqueLogin.prototype[Symbol.dispose] = OpaqueLogin.prototype.free;
133
+
134
+ /**
135
+ * The result of a completed login.
136
+ */
137
+ export class OpaqueLoginResult {
138
+ static __wrap(ptr) {
139
+ const obj = Object.create(OpaqueLoginResult.prototype);
140
+ obj.__wbg_ptr = ptr;
141
+ OpaqueLoginResultFinalization.register(obj, obj.__wbg_ptr, obj);
142
+ return obj;
143
+ }
144
+ __destroy_into_raw() {
145
+ const ptr = this.__wbg_ptr;
146
+ this.__wbg_ptr = 0;
147
+ OpaqueLoginResultFinalization.unregister(this);
148
+ return ptr;
149
+ }
150
+ free() {
151
+ const ptr = this.__destroy_into_raw();
152
+ wasm.__wbg_opaqueloginresult_free(ptr, 0);
153
+ }
154
+ /**
155
+ * Hex `export_key`, identical to the enrolment's for the same password.
156
+ * @returns {string}
157
+ */
158
+ get exportKey() {
159
+ let deferred1_0;
160
+ let deferred1_1;
161
+ try {
162
+ const ret = wasm.opaqueloginresult_exportKey(this.__wbg_ptr);
163
+ deferred1_0 = ret[0];
164
+ deferred1_1 = ret[1];
165
+ return getStringFromWasm0(ret[0], ret[1]);
166
+ } finally {
167
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
168
+ }
169
+ }
170
+ /**
171
+ * Hex `KE3`, to post to `/auth/opaque/login/finish`.
172
+ * @returns {string}
173
+ */
174
+ get ke3() {
175
+ let deferred1_0;
176
+ let deferred1_1;
177
+ try {
178
+ const ret = wasm.opaqueloginresult_ke3(this.__wbg_ptr);
179
+ deferred1_0 = ret[0];
180
+ deferred1_1 = ret[1];
181
+ return getStringFromWasm0(ret[0], ret[1]);
182
+ } finally {
183
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
184
+ }
185
+ }
186
+ /**
187
+ * Hex mutually authenticated session key. AXIAM issues ordinary session
188
+ * cookies rather than binding anything to this.
189
+ * @returns {string}
190
+ */
191
+ get sessionKey() {
192
+ let deferred1_0;
193
+ let deferred1_1;
194
+ try {
195
+ const ret = wasm.opaqueloginresult_sessionKey(this.__wbg_ptr);
196
+ deferred1_0 = ret[0];
197
+ deferred1_1 = ret[1];
198
+ return getStringFromWasm0(ret[0], ret[1]);
199
+ } finally {
200
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
201
+ }
202
+ }
203
+ }
204
+ if (Symbol.dispose) OpaqueLoginResult.prototype[Symbol.dispose] = OpaqueLoginResult.prototype.free;
205
+
206
+ /**
207
+ * In-flight registration state.
208
+ */
209
+ export class OpaqueRegistration {
210
+ __destroy_into_raw() {
211
+ const ptr = this.__wbg_ptr;
212
+ this.__wbg_ptr = 0;
213
+ OpaqueRegistrationFinalization.unregister(this);
214
+ return ptr;
215
+ }
216
+ free() {
217
+ const ptr = this.__destroy_into_raw();
218
+ wasm.__wbg_opaqueregistration_free(ptr, 0);
219
+ }
220
+ /**
221
+ * Unblind, stretch and seal the envelope. **Consumes** this object.
222
+ * @param {string} password
223
+ * @param {string} registration_response
224
+ * @param {OpaqueKsf} ksf
225
+ * @returns {OpaqueRegistrationResult}
226
+ */
227
+ finish(password, registration_response, ksf) {
228
+ const ptr = this.__destroy_into_raw();
229
+ const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
230
+ const len0 = WASM_VECTOR_LEN;
231
+ const ptr1 = passStringToWasm0(registration_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
232
+ const len1 = WASM_VECTOR_LEN;
233
+ _assertClass(ksf, OpaqueKsf);
234
+ const ret = wasm.opaqueregistration_finish(ptr, ptr0, len0, ptr1, len1, ksf.__wbg_ptr);
235
+ if (ret[2]) {
236
+ throw takeFromExternrefTable0(ret[1]);
237
+ }
238
+ return OpaqueRegistrationResult.__wrap(ret[0]);
239
+ }
240
+ /**
241
+ * Blind the password. The `request` getter carries the hex
242
+ * `RegistrationRequest` to post to `/auth/opaque/register/start`.
243
+ * @param {string} password
244
+ */
245
+ constructor(password) {
246
+ const ptr0 = passStringToWasm0(password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
247
+ const len0 = WASM_VECTOR_LEN;
248
+ const ret = wasm.opaqueregistration_new(ptr0, len0);
249
+ if (ret[2]) {
250
+ throw takeFromExternrefTable0(ret[1]);
251
+ }
252
+ this.__wbg_ptr = ret[0];
253
+ OpaqueRegistrationFinalization.register(this, this.__wbg_ptr, this);
254
+ return this;
255
+ }
256
+ /**
257
+ * Hex `RegistrationRequest`.
258
+ * @returns {string}
259
+ */
260
+ get request() {
261
+ let deferred1_0;
262
+ let deferred1_1;
263
+ try {
264
+ const ret = wasm.opaqueregistration_request(this.__wbg_ptr);
265
+ deferred1_0 = ret[0];
266
+ deferred1_1 = ret[1];
267
+ return getStringFromWasm0(ret[0], ret[1]);
268
+ } finally {
269
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
270
+ }
271
+ }
272
+ }
273
+ if (Symbol.dispose) OpaqueRegistration.prototype[Symbol.dispose] = OpaqueRegistration.prototype.free;
274
+
275
+ /**
276
+ * The result of a completed enrolment.
277
+ */
278
+ export class OpaqueRegistrationResult {
279
+ static __wrap(ptr) {
280
+ const obj = Object.create(OpaqueRegistrationResult.prototype);
281
+ obj.__wbg_ptr = ptr;
282
+ OpaqueRegistrationResultFinalization.register(obj, obj.__wbg_ptr, obj);
283
+ return obj;
284
+ }
285
+ __destroy_into_raw() {
286
+ const ptr = this.__wbg_ptr;
287
+ this.__wbg_ptr = 0;
288
+ OpaqueRegistrationResultFinalization.unregister(this);
289
+ return ptr;
290
+ }
291
+ free() {
292
+ const ptr = this.__destroy_into_raw();
293
+ wasm.__wbg_opaqueregistrationresult_free(ptr, 0);
294
+ }
295
+ /**
296
+ * Hex `export_key`. AXIAM does not use it and no endpoint accepts it; it
297
+ * is surfaced because it cannot be re-derived later without the password.
298
+ * @returns {string}
299
+ */
300
+ get exportKey() {
301
+ let deferred1_0;
302
+ let deferred1_1;
303
+ try {
304
+ const ret = wasm.opaqueregistrationresult_exportKey(this.__wbg_ptr);
305
+ deferred1_0 = ret[0];
306
+ deferred1_1 = ret[1];
307
+ return getStringFromWasm0(ret[0], ret[1]);
308
+ } finally {
309
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
310
+ }
311
+ }
312
+ /**
313
+ * Hex `RegistrationRecord`, to embed in the request body's `opaque` object.
314
+ * @returns {string}
315
+ */
316
+ get record() {
317
+ let deferred1_0;
318
+ let deferred1_1;
319
+ try {
320
+ const ret = wasm.opaqueregistrationresult_record(this.__wbg_ptr);
321
+ deferred1_0 = ret[0];
322
+ deferred1_1 = ret[1];
323
+ return getStringFromWasm0(ret[0], ret[1]);
324
+ } finally {
325
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
326
+ }
327
+ }
328
+ }
329
+ if (Symbol.dispose) OpaqueRegistrationResult.prototype[Symbol.dispose] = OpaqueRegistrationResult.prototype.free;
330
+
331
+ /**
332
+ * Run a complete OPAQUE registration and login inside this module, for
333
+ * release smoke-testing.
334
+ *
335
+ * # Why this is exported
336
+ *
337
+ * An old `binaryen` silently miscompiles WebAssembly built from this crate:
338
+ * `wasm-pack` reports success and the elliptic-curve arithmetic inside is
339
+ * wrong. "It built" is therefore not evidence that the artifact works, and the
340
+ * failure would surface as users who cannot log in.
341
+ *
342
+ * There is no fixed input to replay against — OPAQUE's blind is generated
343
+ * inside the protocol and is not injectable — so the available check is to
344
+ * perform both halves of a real exchange and assert they agree. A miscompiled
345
+ * scalar multiplication produces an envelope that will not open, which is
346
+ * exactly what this catches.
347
+ *
348
+ * Returns `true` on success and throws on failure, so a smoke test can assert
349
+ * on either.
350
+ *
351
+ * **Never call this in application code.** It talks to no server and
352
+ * authenticates nobody.
353
+ * @returns {boolean}
354
+ */
355
+ export function __conformanceRoundTrip() {
356
+ const ret = wasm.__conformanceRoundTrip();
357
+ if (ret[2]) {
358
+ throw takeFromExternrefTable0(ret[1]);
359
+ }
360
+ return ret[0] !== 0;
361
+ }
362
+
363
+ /**
364
+ * Non-zero when this build can perform OPAQUE.
365
+ *
366
+ * Always `true` — if the module instantiated, it works. It exists so a
367
+ * TypeScript `opaqueAvailable()` (CONTRACT §23.2) has something to call after
368
+ * a successful `init()`, and so a build whose WASM failed to load can answer
369
+ * the same question with `false` without a special case.
370
+ * @returns {boolean}
371
+ */
372
+ export function opaqueAvailable() {
373
+ const ret = wasm.opaqueAvailable();
374
+ return ret !== 0;
375
+ }
376
+
377
+ /**
378
+ * Install the panic hook so a Rust panic surfaces as a stack trace in the
379
+ * browser console rather than `unreachable executed`.
380
+ *
381
+ * Idempotent; a caller may invoke it once at module init.
382
+ */
383
+ export function start() {
384
+ wasm.start();
385
+ }
386
+ function __wbg_get_imports() {
387
+ const import0 = {
388
+ __proto__: null,
389
+ __wbg_Error_408e67f47ca7b58b: function(arg0, arg1) {
390
+ const ret = Error(getStringFromWasm0(arg0, arg1));
391
+ return ret;
392
+ },
393
+ __wbg___wbindgen_is_function_5e4570eb24ffa122: function(arg0) {
394
+ const ret = typeof(arg0) === 'function';
395
+ return ret;
396
+ },
397
+ __wbg___wbindgen_is_object_a2790eb24c211ea0: function(arg0) {
398
+ const val = arg0;
399
+ const ret = typeof(val) === 'object' && val !== null;
400
+ return ret;
401
+ },
402
+ __wbg___wbindgen_is_string_e6f02f0ea5f20a32: function(arg0) {
403
+ const ret = typeof(arg0) === 'string';
404
+ return ret;
405
+ },
406
+ __wbg___wbindgen_is_undefined_6cff064c44e0d823: function(arg0) {
407
+ const ret = arg0 === undefined;
408
+ return ret;
409
+ },
410
+ __wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
411
+ throw new Error(getStringFromWasm0(arg0, arg1));
412
+ },
413
+ __wbg_call_35dba3c747ad7521: function() { return handleError(function (arg0, arg1, arg2) {
414
+ const ret = arg0.call(arg1, arg2);
415
+ return ret;
416
+ }, arguments); },
417
+ __wbg_crypto_38df2bab126b63dc: function(arg0) {
418
+ const ret = arg0.crypto;
419
+ return ret;
420
+ },
421
+ __wbg_error_757e9472f8410341: function(arg0, arg1) {
422
+ let deferred0_0;
423
+ let deferred0_1;
424
+ try {
425
+ deferred0_0 = arg0;
426
+ deferred0_1 = arg1;
427
+ console.error(getStringFromWasm0(arg0, arg1));
428
+ } finally {
429
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
430
+ }
431
+ },
432
+ __wbg_getRandomValues_c44a50d8cfdaebeb: function() { return handleError(function (arg0, arg1) {
433
+ arg0.getRandomValues(arg1);
434
+ }, arguments); },
435
+ __wbg_length_36bd29c6848c2144: function(arg0) {
436
+ const ret = arg0.length;
437
+ return ret;
438
+ },
439
+ __wbg_msCrypto_bd5a034af96bcba6: function(arg0) {
440
+ const ret = arg0.msCrypto;
441
+ return ret;
442
+ },
443
+ __wbg_new_227d7c05414eb861: function() {
444
+ const ret = new Error();
445
+ return ret;
446
+ },
447
+ __wbg_new_with_length_3ffc1c56427c525c: function(arg0) {
448
+ const ret = new Uint8Array(arg0 >>> 0);
449
+ return ret;
450
+ },
451
+ __wbg_node_84ea875411254db1: function(arg0) {
452
+ const ret = arg0.node;
453
+ return ret;
454
+ },
455
+ __wbg_process_44c7a14e11e9f69e: function(arg0) {
456
+ const ret = arg0.process;
457
+ return ret;
458
+ },
459
+ __wbg_prototypesetcall_de8e0d9553586985: function(arg0, arg1, arg2) {
460
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
461
+ },
462
+ __wbg_randomFillSync_6c25eac9869eb53c: function() { return handleError(function (arg0, arg1) {
463
+ arg0.randomFillSync(arg1);
464
+ }, arguments); },
465
+ __wbg_require_b4edbdcf3e2a1ef0: function() { return handleError(function () {
466
+ const ret = module.require;
467
+ return ret;
468
+ }, arguments); },
469
+ __wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
470
+ const ret = arg1.stack;
471
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
472
+ const len1 = WASM_VECTOR_LEN;
473
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
474
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
475
+ },
476
+ __wbg_static_accessor_GLOBAL_THIS_466428f93b4eaa76: function() {
477
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
478
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
479
+ },
480
+ __wbg_static_accessor_GLOBAL_c7aea38d4de089bc: function() {
481
+ const ret = typeof global === 'undefined' ? null : global;
482
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
483
+ },
484
+ __wbg_static_accessor_SELF_42d4fae05e59267a: function() {
485
+ const ret = typeof self === 'undefined' ? null : self;
486
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
487
+ },
488
+ __wbg_static_accessor_WINDOW_e0db14a0eba6a812: function() {
489
+ const ret = typeof window === 'undefined' ? null : window;
490
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
491
+ },
492
+ __wbg_subarray_a4cc58201c7359fd: function(arg0, arg1, arg2) {
493
+ const ret = arg0.subarray(arg1 >>> 0, arg2 >>> 0);
494
+ return ret;
495
+ },
496
+ __wbg_versions_276b2795b1c6a219: function(arg0) {
497
+ const ret = arg0.versions;
498
+ return ret;
499
+ },
500
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
501
+ // Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`.
502
+ const ret = getArrayU8FromWasm0(arg0, arg1);
503
+ return ret;
504
+ },
505
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
506
+ // Cast intrinsic for `Ref(String) -> Externref`.
507
+ const ret = getStringFromWasm0(arg0, arg1);
508
+ return ret;
509
+ },
510
+ __wbindgen_init_externref_table: function() {
511
+ const table = wasm.__wbindgen_externrefs;
512
+ const offset = table.grow(4);
513
+ table.set(0, undefined);
514
+ table.set(offset + 0, undefined);
515
+ table.set(offset + 1, null);
516
+ table.set(offset + 2, true);
517
+ table.set(offset + 3, false);
518
+ },
519
+ };
520
+ return {
521
+ __proto__: null,
522
+ "./axiam_opaque_bg.js": import0,
523
+ };
524
+ }
525
+
526
+ const OpaqueKsfFinalization = (typeof FinalizationRegistry === 'undefined')
527
+ ? { register: () => {}, unregister: () => {} }
528
+ : new FinalizationRegistry(ptr => wasm.__wbg_opaqueksf_free(ptr, 1));
529
+ const OpaqueLoginFinalization = (typeof FinalizationRegistry === 'undefined')
530
+ ? { register: () => {}, unregister: () => {} }
531
+ : new FinalizationRegistry(ptr => wasm.__wbg_opaquelogin_free(ptr, 1));
532
+ const OpaqueLoginResultFinalization = (typeof FinalizationRegistry === 'undefined')
533
+ ? { register: () => {}, unregister: () => {} }
534
+ : new FinalizationRegistry(ptr => wasm.__wbg_opaqueloginresult_free(ptr, 1));
535
+ const OpaqueRegistrationFinalization = (typeof FinalizationRegistry === 'undefined')
536
+ ? { register: () => {}, unregister: () => {} }
537
+ : new FinalizationRegistry(ptr => wasm.__wbg_opaqueregistration_free(ptr, 1));
538
+ const OpaqueRegistrationResultFinalization = (typeof FinalizationRegistry === 'undefined')
539
+ ? { register: () => {}, unregister: () => {} }
540
+ : new FinalizationRegistry(ptr => wasm.__wbg_opaqueregistrationresult_free(ptr, 1));
541
+
542
+ function addToExternrefTable0(obj) {
543
+ const idx = wasm.__externref_table_alloc();
544
+ wasm.__wbindgen_externrefs.set(idx, obj);
545
+ return idx;
546
+ }
547
+
548
+ function _assertClass(instance, klass) {
549
+ if (!(instance instanceof klass)) {
550
+ throw new Error(`expected instance of ${klass.name}`);
551
+ }
552
+ }
553
+
554
+ function getArrayU8FromWasm0(ptr, len) {
555
+ ptr = ptr >>> 0;
556
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
557
+ }
558
+
559
+ let cachedDataViewMemory0 = null;
560
+ function getDataViewMemory0() {
561
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
562
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
563
+ }
564
+ return cachedDataViewMemory0;
565
+ }
566
+
567
+ function getStringFromWasm0(ptr, len) {
568
+ return decodeText(ptr >>> 0, len);
569
+ }
570
+
571
+ let cachedUint8ArrayMemory0 = null;
572
+ function getUint8ArrayMemory0() {
573
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
574
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
575
+ }
576
+ return cachedUint8ArrayMemory0;
577
+ }
578
+
579
+ function handleError(f, args) {
580
+ try {
581
+ return f.apply(this, args);
582
+ } catch (e) {
583
+ const idx = addToExternrefTable0(e);
584
+ wasm.__wbindgen_exn_store(idx);
585
+ }
586
+ }
587
+
588
+ function isLikeNone(x) {
589
+ return x === undefined || x === null;
590
+ }
591
+
592
+ function passStringToWasm0(arg, malloc, realloc) {
593
+ if (realloc === undefined) {
594
+ const buf = cachedTextEncoder.encode(arg);
595
+ const ptr = malloc(buf.length, 1) >>> 0;
596
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
597
+ WASM_VECTOR_LEN = buf.length;
598
+ return ptr;
599
+ }
600
+
601
+ let len = arg.length;
602
+ let ptr = malloc(len, 1) >>> 0;
603
+
604
+ const mem = getUint8ArrayMemory0();
605
+
606
+ let offset = 0;
607
+
608
+ for (; offset < len; offset++) {
609
+ const code = arg.charCodeAt(offset);
610
+ if (code > 0x7F) break;
611
+ mem[ptr + offset] = code;
612
+ }
613
+ if (offset !== len) {
614
+ if (offset !== 0) {
615
+ arg = arg.slice(offset);
616
+ }
617
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
618
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
619
+ const ret = cachedTextEncoder.encodeInto(arg, view);
620
+
621
+ offset += ret.written;
622
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
623
+ }
624
+
625
+ WASM_VECTOR_LEN = offset;
626
+ return ptr;
627
+ }
628
+
629
+ function takeFromExternrefTable0(idx) {
630
+ const value = wasm.__wbindgen_externrefs.get(idx);
631
+ wasm.__externref_table_dealloc(idx);
632
+ return value;
633
+ }
634
+
635
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
636
+ cachedTextDecoder.decode();
637
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
638
+ let numBytesDecoded = 0;
639
+ function decodeText(ptr, len) {
640
+ numBytesDecoded += len;
641
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
642
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
643
+ cachedTextDecoder.decode();
644
+ numBytesDecoded = len;
645
+ }
646
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
647
+ }
648
+
649
+ const cachedTextEncoder = new TextEncoder();
650
+
651
+ if (!('encodeInto' in cachedTextEncoder)) {
652
+ cachedTextEncoder.encodeInto = function (arg, view) {
653
+ const buf = cachedTextEncoder.encode(arg);
654
+ view.set(buf);
655
+ return {
656
+ read: arg.length,
657
+ written: buf.length
658
+ };
659
+ };
660
+ }
661
+
662
+ let WASM_VECTOR_LEN = 0;
663
+
664
+ let wasmModule, wasmInstance, wasm;
665
+ function __wbg_finalize_init(instance, module) {
666
+ wasmInstance = instance;
667
+ wasm = instance.exports;
668
+ wasmModule = module;
669
+ cachedDataViewMemory0 = null;
670
+ cachedUint8ArrayMemory0 = null;
671
+ wasm.__wbindgen_start();
672
+ return wasm;
673
+ }
674
+
675
+ async function __wbg_load(module, imports) {
676
+ if (typeof Response === 'function' && module instanceof Response) {
677
+ if (!module.ok) {
678
+ throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
679
+ }
680
+
681
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
682
+ try {
683
+ return await WebAssembly.instantiateStreaming(module, imports);
684
+ } catch (e) {
685
+ const validResponse = expectedResponseType(module.type);
686
+
687
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
688
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
689
+
690
+ } else { throw e; }
691
+ }
692
+ }
693
+
694
+ const bytes = await module.arrayBuffer();
695
+ return await WebAssembly.instantiate(bytes, imports);
696
+ } else {
697
+ const instance = await WebAssembly.instantiate(module, imports);
698
+
699
+ if (instance instanceof WebAssembly.Instance) {
700
+ return { instance, module };
701
+ } else {
702
+ return instance;
703
+ }
704
+ }
705
+
706
+ function expectedResponseType(type) {
707
+ switch (type) {
708
+ case 'basic': case 'cors': case 'default': return true;
709
+ }
710
+ return false;
711
+ }
712
+ }
713
+
714
+ function initSync(module) {
715
+ if (wasm !== undefined) return wasm;
716
+
717
+
718
+ if (module !== undefined) {
719
+ if (Object.getPrototypeOf(module) === Object.prototype) {
720
+ ({module} = module)
721
+ } else {
722
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
723
+ }
724
+ }
725
+
726
+ const imports = __wbg_get_imports();
727
+ if (!(module instanceof WebAssembly.Module)) {
728
+ module = new WebAssembly.Module(module);
729
+ }
730
+ const instance = new WebAssembly.Instance(module, imports);
731
+ return __wbg_finalize_init(instance, module);
732
+ }
733
+
734
+ async function __wbg_init(module_or_path) {
735
+ if (wasm !== undefined) return wasm;
736
+
737
+
738
+ if (module_or_path !== undefined) {
739
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
740
+ ({module_or_path} = module_or_path)
741
+ } else {
742
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
743
+ }
744
+ }
745
+
746
+ if (module_or_path === undefined) {
747
+ module_or_path = new URL('axiam_opaque_bg.wasm', import.meta.url);
748
+ }
749
+ const imports = __wbg_get_imports();
750
+
751
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
752
+ module_or_path = fetch(module_or_path);
753
+ }
754
+
755
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
756
+
757
+ return __wbg_finalize_init(instance, module);
758
+ }
759
+
760
+ export { initSync, __wbg_init as default };
Binary file
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@axiam/opaque-wasm",
3
+ "type": "module",
4
+ "description": "WebAssembly build of AXIAM's OPAQUE (RFC 9807) client",
5
+ "version": "1.0.0-alpha32",
6
+ "license": "Apache-2.0",
7
+ "files": [
8
+ "axiam_opaque_bg.wasm",
9
+ "axiam_opaque.js",
10
+ "axiam_opaque.d.ts"
11
+ ],
12
+ "main": "axiam_opaque.js",
13
+ "types": "axiam_opaque.d.ts",
14
+ "sideEffects": [
15
+ "./snippets/*"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/ilpanich/axiam"
20
+ }
21
+ }