0xMiden / 0xMiden/web-sdk

Worker callback bridge: non-Error throws are silently treated as success, and the 30s ceiling is not configurable

Đang mở
#316 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
1
Fork
21
Merge trung bình
12 giờ 14 phút
Pull request đã merge (30 ngày)
41

Mô tả

Two defects in the worker's external-keystore callback bridge. Both are pre-existing and affect every worker-forwarded method, not one call site. Splitting them out of #313, which made batching a forwarded method and so widened the set of affected calls.

### 1. A throw whose value has no truthy `.message` loses its reason

The main-thread bridge serializes a failed callback as `error.message`:

```js
// crates/web-client/js/index.js — EXECUTE_CALLBACK handler
} catch (error) {
this.worker.postMessage({
callbackError: error.message,
callbackRequestId: requestId,
});
}
```

The worker then treats a falsy `callbackError` as success:

```js
// crates/web-client/js/workers/web-client-methods-worker.js — self.onmessage
if (!callbackError) {
resolve(callbackResult);
} else {
reject(new Error(callbackError));
}
```

A callback that throws a value with no truthy `.message` — `throw "user rejected"`, or a wallet-style `throw { code: 4001 }`, or an `Error` with an empty message — yields `callbackError === undefined`, and the worker resolves with `undefined`. A thrown object that *does* carry a message (including a plain `{ message: "rejected" }`) propagates correctly; a thrown `null`/`undefined` is worse still, since reading `.message` throws inside the handler, no response is posted at all, and the call hangs until the 30s timeout in defect 2.

The signature does **not** then succeed: `web_keystore_callbacks.rs` rejects the resolved value because it is not a `Uint8Array`, so the call fails with

```
sign callback must return a Uint8Array
```

That is the whole defect — not a forged approval, but a **misclassification that destroys the real reason**. The user rejected; the developer sees a return-type complaint that points at their callback's signature instead of at the rejection, with no `code`, no `name`, no `cause`. For a wallet integration that is the difference between "user declined" and an apparent SDK bug.

Fix: send an explicit success/failure discriminator instead of inferring failure from the truthiness of a message string, and serialize enough of the thrown value to preserve `code` / `name` / `cause`.

### 2. The 30-second per-callback ceiling is fixed

```js
const CALLBACK_TIMEOUT_MS = 30000;
```

Applied to `getKey`, `insertKey`, and `sign`. A signature that needs physical confirmation — a hardware wallet, a lock-aware keystore, any human-in-the-loop approval — can exceed 30 seconds, and the call fails with `Callback timed out`.

Batching sharpens this. Signing happens inside `BatchBuilder::push`, and this wrapper treats a failed push as fatal, so `submit()` is never reached: **one slow approval fails the whole batch**, where ten single submits would have lost only one.

Fix: make the ceiling configurable (a `ClientOptions` field), and consider no timeout by default for `sign`, where the wait is expected to be human-paced.

### Why not fixed in #313

Both defects are in the shared bridge used by all worker-forwarded methods. A fix scoped to batching would leave the other ~40 methods broken while adding a third execution path to reason about — the same reasoning that split #315 out.

### Related

- #313 — made batching a forwarded method
- #315 — worker lifecycle: a dead worker wedges the client

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

The issue points to two files: crates/web-client/js/index.js (EXECUTE_CALLBACK handler) and crates/web-client/js/workers/web-client-methods-worker.js (self.onmessage). Start by examining the callback bridge logic in these files to understand how errors are serialized and timeouts are enforced. The fix involves changing the error-handling protocol to preserve error details and making the timeout configurable via ClientOptions. Testing will require simulating callback failures and long-running approvals.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
javascript, rust, typescript, wasm
Lĩnh vực
backend, security, tooling
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
65/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.