@quantovainc/qcore 0.1.5 → 0.1.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantovainc/qcore",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Quantova's post quantum client core for JavaScript. Signs with ML-DSA-65 and builds Q1 addresses.",
5
5
  "scripts": {
6
6
  "build": "wasm-pack build --target bundler --out-dir pkg && wasm-pack build --target nodejs --out-dir pkg-node",
@@ -44,7 +44,9 @@
44
44
  "default": "./index.js"
45
45
  },
46
46
  "./pkg": "./pkg/qcore_js.js",
47
+ "./pkg/*": "./pkg/*",
47
48
  "./pkg-node": "./pkg-node/qcore_js.js",
49
+ "./pkg-node/*": "./pkg-node/*",
48
50
  "./package.json": "./package.json"
49
51
  },
50
52
  "license": "(Apache-2.0 OR MIT)",
package/pkg/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qcore-js",
3
3
  "type": "module",
4
4
  "description": "The JavaScript binding for the Quantova client core, generated over QCore with wasm-bindgen. The core does the key derivation, the post quantum signing, and the wire, the page does the fetch.",
5
- "version": "0.1.5",
5
+ "version": "0.1.7",
6
6
  "license": "Apache-2.0 OR MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qcore-js",
3
3
  "description": "The JavaScript binding for the Quantova client core, generated over QCore with wasm-bindgen. The core does the key derivation, the post quantum signing, and the wire, the page does the fetch.",
4
- "version": "0.1.5",
4
+ "version": "0.1.7",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "repository": {
7
7
  "type": "git",
package/shared.js CHANGED
@@ -141,14 +141,6 @@ function generateSeed() {
141
141
  }
142
142
 
143
143
  function makeClient(core) {
144
- // The signature binds the chain the gateway says it serves, computed from the reported network
145
- // name with the same hash the node uses, so a transaction is valid only on that network and a
146
- // renamed network is followed without a code change.
147
- function signingChainId(info) {
148
- const name = info && info.chain_id;
149
- if (!name) throw new Error('the gateway did not report a chain id to bind the signature to');
150
- return BigInt(core.chainIdFromName(name));
151
- }
152
144
  return class Client {
153
145
  constructor(target, options) {
154
146
  const opts = options || {};
@@ -180,6 +172,21 @@ function makeClient(core) {
180
172
  }
181
173
  }
182
174
 
175
+ // The signature binds the chain the gateway says it serves, computed from the reported network
176
+ // name with the same hash the node uses, so a transaction is valid only on that network and a
177
+ // renamed network is followed without a code change. When this Client was configured with a
178
+ // known chain id, the reported name must match it: a hostile gateway must not be able to bind a
179
+ // signature to a network the caller did not choose and then replay it there.
180
+ _signingChainId(info) {
181
+ const name = info && info.chain_id;
182
+ if (!name) throw new Error('the gateway did not report a chain id to bind the signature to');
183
+ const configured = this.network && this.network.chainId;
184
+ if (configured && name !== configured) {
185
+ throw new Error(`the gateway reports chain ${name} but this client is configured for ${configured}; refusing to sign a transaction that would be valid on a network you did not choose`);
186
+ }
187
+ return BigInt(core.chainIdFromName(name));
188
+ }
189
+
183
190
  async _call(method, body) {
184
191
  const controller = new AbortController();
185
192
  const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
@@ -189,6 +196,11 @@ function makeClient(core) {
189
196
  headers: { 'Content-Type': 'application/json' },
190
197
  body: body || '{}',
191
198
  signal: controller.signal,
199
+ // Never follow a redirect. The base passed the transport guard, but fetch follows a 30x
200
+ // automatically, and a gateway that answers with a redirect to http on a public host would
201
+ // downgrade the very hop the guard protects. An RPC endpoint has no reason to redirect, so
202
+ // a redirect is refused rather than silently followed to an unchecked target.
203
+ redirect: 'error',
192
204
  });
193
205
  const text = await readBounded(res);
194
206
  let data;
@@ -218,7 +230,7 @@ function makeClient(core) {
218
230
  const ceiling = feeCeiling(maxFeeQuon);
219
231
  const info = await this.nodeInfo();
220
232
  this._guardMainnet();
221
- const chainId = signingChainId(info);
233
+ const chainId = this._signingChainId(info);
222
234
  const fee = info && info.fee && info.fee.transfer_quon;
223
235
  if (fee == null) throw new Error('the gateway did not report a transfer fee');
224
236
  if (BigInt(fee) > ceiling) {
@@ -238,7 +250,7 @@ function makeClient(core) {
238
250
  const ceiling = feeCeiling(maxFeeQuon);
239
251
  const info = await this.nodeInfo();
240
252
  this._guardMainnet();
241
- const chainId = signingChainId(info);
253
+ const chainId = this._signingChainId(info);
242
254
  const fee = info && info.fee && info.fee.transfer_quon;
243
255
  if (fee == null) throw new Error('the gateway did not report a transfer fee');
244
256
  if (BigInt(fee) > ceiling) {
@@ -257,7 +269,7 @@ function makeClient(core) {
257
269
  const ceiling = feeCeiling(maxFeeQuon);
258
270
  const info = await this.nodeInfo();
259
271
  this._guardMainnet();
260
- const chainId = signingChainId(info);
272
+ const chainId = this._signingChainId(info);
261
273
  const fee = info && info.fee && info.fee.transfer_quon;
262
274
  if (fee == null) throw new Error('the gateway did not report a transfer fee');
263
275
  if (BigInt(fee) > ceiling) {
@@ -288,7 +300,7 @@ function makeClient(core) {
288
300
  const ceiling = feeCeiling(maxFeeQuon);
289
301
  const info = await this.nodeInfo();
290
302
  this._guardMainnet();
291
- const chainId = signingChainId(info);
303
+ const chainId = this._signingChainId(info);
292
304
  const fee = info && info.fee && info.fee.transfer_quon;
293
305
  if (fee == null) throw new Error('the gateway did not report a transfer fee');
294
306
  if (BigInt(fee) > ceiling) {