@winbit32/wallet-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/cosign/bytes.d.ts +10 -0
- package/dist/cosign/bytes.d.ts.map +1 -0
- package/dist/cosign/bytes.js +37 -0
- package/dist/cosign/bytes.js.map +1 -0
- package/dist/cosign/config.d.ts +58 -0
- package/dist/cosign/config.d.ts.map +1 -0
- package/dist/cosign/config.js +54 -0
- package/dist/cosign/config.js.map +1 -0
- package/dist/cosign/cosignSend.d.ts +104 -0
- package/dist/cosign/cosignSend.d.ts.map +1 -0
- package/dist/cosign/cosignSend.js +157 -0
- package/dist/cosign/cosignSend.js.map +1 -0
- package/dist/cosign/index.d.ts +33 -0
- package/dist/cosign/index.d.ts.map +1 -0
- package/dist/cosign/index.js +49 -0
- package/dist/cosign/index.js.map +1 -0
- package/dist/cosign/initiator.d.ts +121 -0
- package/dist/cosign/initiator.d.ts.map +1 -0
- package/dist/cosign/initiator.js +270 -0
- package/dist/cosign/initiator.js.map +1 -0
- package/dist/cosign/orchardFrost.d.ts +140 -0
- package/dist/cosign/orchardFrost.d.ts.map +1 -0
- package/dist/cosign/orchardFrost.js +227 -0
- package/dist/cosign/orchardFrost.js.map +1 -0
- package/dist/cosign/relay.d.ts +100 -0
- package/dist/cosign/relay.d.ts.map +1 -0
- package/dist/cosign/relay.js +359 -0
- package/dist/cosign/relay.js.map +1 -0
- package/dist/cosign/seed.d.ts +32 -0
- package/dist/cosign/seed.d.ts.map +1 -0
- package/dist/cosign/seed.js +69 -0
- package/dist/cosign/seed.js.map +1 -0
- package/dist/cosign/transports.d.ts +127 -0
- package/dist/cosign/transports.d.ts.map +1 -0
- package/dist/cosign/transports.js +426 -0
- package/dist/cosign/transports.js.map +1 -0
- package/dist/cosign/vaultShare.d.ts +65 -0
- package/dist/cosign/vaultShare.d.ts.map +1 -0
- package/dist/cosign/vaultShare.js +157 -0
- package/dist/cosign/vaultShare.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/monero/types.d.ts +75 -0
- package/dist/monero/types.d.ts.map +1 -0
- package/dist/monero/types.js +9 -0
- package/dist/monero/types.js.map +1 -0
- package/dist/scanner/baseUrl.d.ts +24 -0
- package/dist/scanner/baseUrl.d.ts.map +1 -0
- package/dist/scanner/baseUrl.js +35 -0
- package/dist/scanner/baseUrl.js.map +1 -0
- package/dist/scanner/moneroScannerClient.d.ts +97 -0
- package/dist/scanner/moneroScannerClient.d.ts.map +1 -0
- package/dist/scanner/moneroScannerClient.js +125 -0
- package/dist/scanner/moneroScannerClient.js.map +1 -0
- package/dist/scanner/zcashScannerClient.d.ts +116 -0
- package/dist/scanner/zcashScannerClient.d.ts.map +1 -0
- package/dist/scanner/zcashScannerClient.js +150 -0
- package/dist/scanner/zcashScannerClient.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Pluggable transport layer for the WB32COSIGN MPC relay.
|
|
4
|
+
*
|
|
5
|
+
* A framework-agnostic port of WINBIT32's `cosignTransports`, trimmed to the
|
|
6
|
+
* transports an online initiator needs and with `fetch` injected (rather
|
|
7
|
+
* than a global) so the module stays host-portable and testable. Works in
|
|
8
|
+
* browsers and Node ≥ 18 (BroadcastChannel, Web Streams and WebCrypto are
|
|
9
|
+
* global there; WebRTC is browser-only and skipped automatically).
|
|
10
|
+
*
|
|
11
|
+
* Each transport moves an already-encrypted opaque body between two roles
|
|
12
|
+
* (`init` / `cosign`); the relay/MPC layer above is responsible for crypto.
|
|
13
|
+
*
|
|
14
|
+
* Included:
|
|
15
|
+
* - BroadcastChannelTransport — same-origin / same-device (zero config).
|
|
16
|
+
* - HttpRelayTransport — cross-device via any WB32COSIGN relay
|
|
17
|
+
* (Secresea's API mounts one at /api/cosign).
|
|
18
|
+
* - WebRTCTransport — peer-to-peer data channel, signalled over the
|
|
19
|
+
* relay; low-latency once the P2P link is up.
|
|
20
|
+
* - MultiTransport — fan-out send, merge receive.
|
|
21
|
+
*
|
|
22
|
+
* Deferred (airgap copy-paste only; not required online): ManualTransport.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.createDefaultTransports = exports.isWebRtcSupported = exports.WebRTCTransport = exports.MultiTransport = exports.HttpRelayTransport = exports.BroadcastChannelTransport = void 0;
|
|
26
|
+
// ── BroadcastChannel (same-origin, zero config) ──────────────────────
|
|
27
|
+
class BroadcastChannelTransport {
|
|
28
|
+
constructor(sessionId) {
|
|
29
|
+
this.name = 'BroadcastChannel (local)';
|
|
30
|
+
this.inbox = new Map();
|
|
31
|
+
this.channel = new BroadcastChannel(`wb32cosign-${sessionId}`);
|
|
32
|
+
this.channel.onmessage = (ev) => {
|
|
33
|
+
const { to, body } = ev.data || {};
|
|
34
|
+
if (!to || !body)
|
|
35
|
+
return;
|
|
36
|
+
const queue = this.inbox.get(to) || [];
|
|
37
|
+
queue.push(body);
|
|
38
|
+
this.inbox.set(to, queue);
|
|
39
|
+
};
|
|
40
|
+
// Node's BroadcastChannel keeps the event loop alive; the ceremony's
|
|
41
|
+
// polling drives all work, so the channel must not hold the process
|
|
42
|
+
// open. No-op in browsers (no unref there).
|
|
43
|
+
this.channel.unref?.();
|
|
44
|
+
}
|
|
45
|
+
async send(from, to, encryptedBody) {
|
|
46
|
+
this.channel.postMessage({ from, to, body: encryptedBody });
|
|
47
|
+
}
|
|
48
|
+
async receive(myRole) {
|
|
49
|
+
const queue = this.inbox.get(myRole) || [];
|
|
50
|
+
if (queue.length === 0)
|
|
51
|
+
return [];
|
|
52
|
+
this.inbox.set(myRole, []);
|
|
53
|
+
return queue;
|
|
54
|
+
}
|
|
55
|
+
close() {
|
|
56
|
+
this.channel.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.BroadcastChannelTransport = BroadcastChannelTransport;
|
|
60
|
+
// ── HTTP relay (cross-device) ────────────────────────────────────────
|
|
61
|
+
const RELAY_START_RETRIES = 2;
|
|
62
|
+
const RATE_LIMIT_INITIAL_DELAY_MS = 2000;
|
|
63
|
+
const RATE_LIMIT_MAX_DELAY_MS = 30000;
|
|
64
|
+
/** Parse an integer `Retry-After` (seconds), clamped so a bad server can't stall us. */
|
|
65
|
+
const parseRetryAfterSeconds = (header) => {
|
|
66
|
+
if (!header)
|
|
67
|
+
return null;
|
|
68
|
+
const n = parseInt(header.trim(), 10);
|
|
69
|
+
if (!Number.isFinite(n) || n < 0)
|
|
70
|
+
return null;
|
|
71
|
+
return Math.min(n, RATE_LIMIT_MAX_DELAY_MS / 1000);
|
|
72
|
+
};
|
|
73
|
+
/** Exponential "do not call before" window shared across one relay origin. */
|
|
74
|
+
class RateLimitBackoff {
|
|
75
|
+
constructor() {
|
|
76
|
+
this.notBeforeMs = 0;
|
|
77
|
+
this.nextDelayMs = RATE_LIMIT_INITIAL_DELAY_MS;
|
|
78
|
+
}
|
|
79
|
+
delayBeforeNext() {
|
|
80
|
+
const remaining = this.notBeforeMs - Date.now();
|
|
81
|
+
return remaining > 0 ? remaining : 0;
|
|
82
|
+
}
|
|
83
|
+
noteRateLimited(retryAfterSeconds) {
|
|
84
|
+
const explicitMs = retryAfterSeconds !== null ? retryAfterSeconds * 1000 : this.nextDelayMs;
|
|
85
|
+
this.notBeforeMs = Date.now() + explicitMs;
|
|
86
|
+
this.nextDelayMs = Math.min(this.nextDelayMs * 2, RATE_LIMIT_MAX_DELAY_MS);
|
|
87
|
+
}
|
|
88
|
+
noteOk() {
|
|
89
|
+
this.notBeforeMs = 0;
|
|
90
|
+
this.nextDelayMs = RATE_LIMIT_INITIAL_DELAY_MS;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const sleepForBackoff = async (backoff) => {
|
|
94
|
+
const wait = backoff.delayBeforeNext();
|
|
95
|
+
if (wait > 0)
|
|
96
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
97
|
+
};
|
|
98
|
+
class HttpRelayTransport {
|
|
99
|
+
constructor(relayUrl, sessionId, fetchImpl) {
|
|
100
|
+
this.started = false;
|
|
101
|
+
this.backoff = new RateLimitBackoff();
|
|
102
|
+
this.relayUrl = relayUrl.replace(/\/+$/, '');
|
|
103
|
+
this.sessionId = sessionId;
|
|
104
|
+
this.fetchImpl = fetchImpl;
|
|
105
|
+
this.name = `HTTP relay (${this.relayUrl.replace(/^https?:\/\//, '').split('/')[0] || 'same-origin'})`;
|
|
106
|
+
}
|
|
107
|
+
async ensureSession() {
|
|
108
|
+
if (this.started)
|
|
109
|
+
return;
|
|
110
|
+
for (let attempt = 0; attempt <= RELAY_START_RETRIES; attempt++) {
|
|
111
|
+
await sleepForBackoff(this.backoff);
|
|
112
|
+
try {
|
|
113
|
+
const resp = await this.fetchImpl(`${this.relayUrl}/${this.sessionId}`, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
116
|
+
body: JSON.stringify([]),
|
|
117
|
+
});
|
|
118
|
+
if (resp.ok || resp.status === 201 || resp.status === 409) {
|
|
119
|
+
this.started = true;
|
|
120
|
+
this.backoff.noteOk();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (resp.status === 429) {
|
|
124
|
+
this.backoff.noteRateLimited(parseRetryAfterSeconds(resp.headers.get('Retry-After')));
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
console.warn(`[cosign/relay] ensureSession attempt ${attempt}:`, err?.message);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.started = true;
|
|
133
|
+
}
|
|
134
|
+
async send(from, to, encryptedBody) {
|
|
135
|
+
await this.ensureSession();
|
|
136
|
+
await sleepForBackoff(this.backoff);
|
|
137
|
+
const response = await this.fetchImpl(`${this.relayUrl}/message/${this.sessionId}`, {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
headers: { 'Content-Type': 'application/json' },
|
|
140
|
+
body: JSON.stringify({ session_id: this.sessionId, from, to: [to], body: encryptedBody }),
|
|
141
|
+
});
|
|
142
|
+
if (response.status === 429) {
|
|
143
|
+
this.backoff.noteRateLimited(parseRetryAfterSeconds(response.headers.get('Retry-After')));
|
|
144
|
+
return; // soft failure — MPC layer retries on its next round-trip
|
|
145
|
+
}
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const text = await response.text().catch(() => '');
|
|
148
|
+
throw new Error(`Relay send failed: ${response.status} ${text}`);
|
|
149
|
+
}
|
|
150
|
+
this.backoff.noteOk();
|
|
151
|
+
}
|
|
152
|
+
async receive(myRole) {
|
|
153
|
+
await this.ensureSession();
|
|
154
|
+
await sleepForBackoff(this.backoff);
|
|
155
|
+
const response = await this.fetchImpl(`${this.relayUrl}/message/${this.sessionId}/${encodeURIComponent(myRole)}`, { method: 'GET' });
|
|
156
|
+
if (response.status === 429) {
|
|
157
|
+
this.backoff.noteRateLimited(parseRetryAfterSeconds(response.headers.get('Retry-After')));
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
if (response.status === 404)
|
|
162
|
+
return [];
|
|
163
|
+
throw new Error(`Relay receive failed: ${response.status}`);
|
|
164
|
+
}
|
|
165
|
+
this.backoff.noteOk();
|
|
166
|
+
return response.json();
|
|
167
|
+
}
|
|
168
|
+
close() {
|
|
169
|
+
/* nothing to clean up */
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.HttpRelayTransport = HttpRelayTransport;
|
|
173
|
+
// ── Multi-transport (fan-out send, merge receive) ────────────────────
|
|
174
|
+
class MultiTransport {
|
|
175
|
+
constructor(transports) {
|
|
176
|
+
this.transports = transports;
|
|
177
|
+
this.name = transports.map((t) => t.name).join(' + ');
|
|
178
|
+
}
|
|
179
|
+
async send(from, to, encryptedBody) {
|
|
180
|
+
await Promise.allSettled(this.transports.map((t) => t.send(from, to, encryptedBody)));
|
|
181
|
+
}
|
|
182
|
+
async receive(myRole) {
|
|
183
|
+
const settled = await Promise.allSettled(this.transports.map((t) => t.receive(myRole)));
|
|
184
|
+
const all = [];
|
|
185
|
+
for (const r of settled)
|
|
186
|
+
if (r.status === 'fulfilled')
|
|
187
|
+
all.push(...r.value);
|
|
188
|
+
return all;
|
|
189
|
+
}
|
|
190
|
+
close() {
|
|
191
|
+
for (const t of this.transports)
|
|
192
|
+
t.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.MultiTransport = MultiTransport;
|
|
196
|
+
const SIGNAL_POLL_MS = 800;
|
|
197
|
+
const ICE_SERVERS = [
|
|
198
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
199
|
+
{ urls: 'stun:stun1.l.google.com:19302' },
|
|
200
|
+
];
|
|
201
|
+
/**
|
|
202
|
+
* Direct peer-to-peer transport over an `RTCDataChannel`. The offer/answer/ICE
|
|
203
|
+
* handshake is signalled through the same WB32COSIGN relay (distinct
|
|
204
|
+
* `signal-init`/`signal-cosign` roles) so no extra server is needed. `send()`
|
|
205
|
+
* is fail-fast — it silently drops while the channel isn't open — so this is
|
|
206
|
+
* safe to combine with {@link HttpRelayTransport} inside a {@link MultiTransport}:
|
|
207
|
+
* the relay is the always-on fabric, WebRTC opportunistically short-circuits it.
|
|
208
|
+
*
|
|
209
|
+
* Ported from WINBIT32's transport with `fetch` injected (Secresea keeps the
|
|
210
|
+
* module host-portable). Only meaningful in a browser with `RTCPeerConnection`;
|
|
211
|
+
* callers must guard creation in non-DOM environments.
|
|
212
|
+
*/
|
|
213
|
+
class WebRTCTransport {
|
|
214
|
+
constructor(sessionId, relayUrl, fetchImpl, myRole, opts) {
|
|
215
|
+
this.name = 'WebRTC (peer-to-peer)';
|
|
216
|
+
this.dc = null;
|
|
217
|
+
this.inbox = new Map();
|
|
218
|
+
this.closed = false;
|
|
219
|
+
this.signalPollTimer = null;
|
|
220
|
+
this.iceCandidateQueue = [];
|
|
221
|
+
this.remoteDescSet = false;
|
|
222
|
+
this.signalBackoff = new RateLimitBackoff();
|
|
223
|
+
this.sessionId = sessionId;
|
|
224
|
+
this.relayUrl = relayUrl.replace(/\/+$/, '');
|
|
225
|
+
this.fetchImpl = fetchImpl;
|
|
226
|
+
this.myRole = myRole;
|
|
227
|
+
this.peerRole = myRole === 'init' ? 'cosign' : 'init';
|
|
228
|
+
this.onOpen = opts?.onOpen;
|
|
229
|
+
this.pc = new RTCPeerConnection({ iceServers: ICE_SERVERS });
|
|
230
|
+
this.pc.onicecandidate = (ev) => {
|
|
231
|
+
if (ev.candidate) {
|
|
232
|
+
void this.postSignal({ type: 'candidate', candidate: ev.candidate.toJSON() });
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
if (myRole === 'init') {
|
|
236
|
+
this.dc = this.pc.createDataChannel('mpc', { ordered: true });
|
|
237
|
+
this.setupDataChannel(this.dc);
|
|
238
|
+
void this.startOffer();
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.pc.ondatachannel = (ev) => {
|
|
242
|
+
this.dc = ev.channel;
|
|
243
|
+
this.setupDataChannel(this.dc);
|
|
244
|
+
};
|
|
245
|
+
this.pollSignals();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
setupDataChannel(dc) {
|
|
249
|
+
dc.onopen = () => {
|
|
250
|
+
if (this.signalPollTimer) {
|
|
251
|
+
clearInterval(this.signalPollTimer);
|
|
252
|
+
this.signalPollTimer = null;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
this.onOpen?.();
|
|
256
|
+
}
|
|
257
|
+
catch { /* listener errors shouldn't break the channel */ }
|
|
258
|
+
};
|
|
259
|
+
dc.onmessage = (ev) => {
|
|
260
|
+
try {
|
|
261
|
+
const { to, body } = JSON.parse(ev.data) || {};
|
|
262
|
+
if (to && body) {
|
|
263
|
+
const queue = this.inbox.get(to) || [];
|
|
264
|
+
queue.push(body);
|
|
265
|
+
this.inbox.set(to, queue);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch { /* skip malformed */ }
|
|
269
|
+
};
|
|
270
|
+
dc.onclose = () => { this.closed = true; };
|
|
271
|
+
dc.onerror = (err) => { console.warn(`[cosign/webrtc] data channel error (${this.myRole}):`, err); };
|
|
272
|
+
}
|
|
273
|
+
async startOffer() {
|
|
274
|
+
const offer = await this.pc.createOffer();
|
|
275
|
+
await this.pc.setLocalDescription(offer);
|
|
276
|
+
await this.postSignal({ type: 'offer', sdp: offer.sdp });
|
|
277
|
+
this.pollSignals();
|
|
278
|
+
}
|
|
279
|
+
async postSignal(envelope) {
|
|
280
|
+
try {
|
|
281
|
+
await this.fetchImpl(`${this.relayUrl}/message/${this.sessionId}`, {
|
|
282
|
+
method: 'POST',
|
|
283
|
+
headers: { 'Content-Type': 'application/json' },
|
|
284
|
+
body: JSON.stringify({
|
|
285
|
+
session_id: this.sessionId,
|
|
286
|
+
from: `signal-${this.myRole}`,
|
|
287
|
+
to: [`signal-${this.peerRole}`],
|
|
288
|
+
body: JSON.stringify(envelope),
|
|
289
|
+
}),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
console.warn('[cosign/webrtc] signal post failed:', err?.message);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
pollSignals() {
|
|
297
|
+
if (this.signalPollTimer)
|
|
298
|
+
return;
|
|
299
|
+
this.signalPollTimer = setInterval(() => void this.fetchSignals(), SIGNAL_POLL_MS);
|
|
300
|
+
void this.fetchSignals();
|
|
301
|
+
}
|
|
302
|
+
async fetchSignals() {
|
|
303
|
+
if (this.closed) {
|
|
304
|
+
if (this.signalPollTimer) {
|
|
305
|
+
clearInterval(this.signalPollTimer);
|
|
306
|
+
this.signalPollTimer = null;
|
|
307
|
+
}
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// Honour any active 429 cooldown so an un-establishable P2P link can't
|
|
311
|
+
// hammer the relay's signal endpoint.
|
|
312
|
+
if (this.signalBackoff.delayBeforeNext() > 0)
|
|
313
|
+
return;
|
|
314
|
+
try {
|
|
315
|
+
const resp = await this.fetchImpl(`${this.relayUrl}/message/${this.sessionId}/signal-${this.myRole}`, { method: 'GET' });
|
|
316
|
+
if (resp.status === 429) {
|
|
317
|
+
this.signalBackoff.noteRateLimited(parseRetryAfterSeconds(resp.headers.get('Retry-After')));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (!resp.ok)
|
|
321
|
+
return;
|
|
322
|
+
this.signalBackoff.noteOk();
|
|
323
|
+
const messages = await resp.json();
|
|
324
|
+
for (const raw of messages) {
|
|
325
|
+
await this.handleSignal(JSON.parse(raw));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch { /* network error — retry next tick */ }
|
|
329
|
+
}
|
|
330
|
+
async handleSignal(sig) {
|
|
331
|
+
if (sig.type === 'offer' && this.myRole !== 'init') {
|
|
332
|
+
await this.pc.setRemoteDescription({ type: 'offer', sdp: sig.sdp });
|
|
333
|
+
this.remoteDescSet = true;
|
|
334
|
+
for (const c of this.iceCandidateQueue)
|
|
335
|
+
await this.pc.addIceCandidate(c);
|
|
336
|
+
this.iceCandidateQueue = [];
|
|
337
|
+
const answer = await this.pc.createAnswer();
|
|
338
|
+
await this.pc.setLocalDescription(answer);
|
|
339
|
+
await this.postSignal({ type: 'answer', sdp: answer.sdp });
|
|
340
|
+
}
|
|
341
|
+
else if (sig.type === 'answer' && this.myRole === 'init') {
|
|
342
|
+
await this.pc.setRemoteDescription({ type: 'answer', sdp: sig.sdp });
|
|
343
|
+
this.remoteDescSet = true;
|
|
344
|
+
for (const c of this.iceCandidateQueue)
|
|
345
|
+
await this.pc.addIceCandidate(c);
|
|
346
|
+
this.iceCandidateQueue = [];
|
|
347
|
+
}
|
|
348
|
+
else if (sig.type === 'candidate' && sig.candidate) {
|
|
349
|
+
if (this.remoteDescSet)
|
|
350
|
+
await this.pc.addIceCandidate(sig.candidate);
|
|
351
|
+
else
|
|
352
|
+
this.iceCandidateQueue.push(sig.candidate);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/** True once the data channel has reached 'open'. */
|
|
356
|
+
isOpen() {
|
|
357
|
+
return !!this.dc && this.dc.readyState === 'open';
|
|
358
|
+
}
|
|
359
|
+
async send(from, to, encryptedBody) {
|
|
360
|
+
// Fail-fast: never block on channel readiness so this is safe to fan out
|
|
361
|
+
// alongside the HTTP relay; the relay (or a resend) delivers if P2P isn't up.
|
|
362
|
+
if (!this.dc || this.dc.readyState !== 'open')
|
|
363
|
+
return;
|
|
364
|
+
try {
|
|
365
|
+
this.dc.send(JSON.stringify({ from, to, body: encryptedBody }));
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
console.warn('[cosign/webrtc] send failed:', err?.message);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
async receive(myRole) {
|
|
372
|
+
const queue = this.inbox.get(myRole) || [];
|
|
373
|
+
if (queue.length === 0)
|
|
374
|
+
return [];
|
|
375
|
+
this.inbox.set(myRole, []);
|
|
376
|
+
return queue;
|
|
377
|
+
}
|
|
378
|
+
close() {
|
|
379
|
+
this.closed = true;
|
|
380
|
+
if (this.signalPollTimer) {
|
|
381
|
+
clearInterval(this.signalPollTimer);
|
|
382
|
+
this.signalPollTimer = null;
|
|
383
|
+
}
|
|
384
|
+
if (this.dc) {
|
|
385
|
+
try {
|
|
386
|
+
this.dc.close();
|
|
387
|
+
}
|
|
388
|
+
catch { /* */ }
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
this.pc.close();
|
|
392
|
+
}
|
|
393
|
+
catch { /* */ }
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
exports.WebRTCTransport = WebRTCTransport;
|
|
397
|
+
/** WebRTC is only usable where the browser exposes `RTCPeerConnection`. */
|
|
398
|
+
const isWebRtcSupported = () => typeof RTCPeerConnection !== 'undefined';
|
|
399
|
+
exports.isWebRtcSupported = isWebRtcSupported;
|
|
400
|
+
/**
|
|
401
|
+
* Build the standard transport stack: BroadcastChannel (same device), an
|
|
402
|
+
* opportunistic WebRTC peer-to-peer leg (low latency once open) and an HTTP
|
|
403
|
+
* relay leg (always-on fallback) when a relay URL is supplied. BroadcastChannel
|
|
404
|
+
* short-circuits when both parties share an origin; WebRTC is skipped silently
|
|
405
|
+
* where `RTCPeerConnection` is unavailable (SSR/tests) or `myRole` is unknown.
|
|
406
|
+
*/
|
|
407
|
+
const createDefaultTransports = (opts) => {
|
|
408
|
+
// Validate before allocating any transport so a config error can't leak
|
|
409
|
+
// an open BroadcastChannel (which would hold a Node process alive).
|
|
410
|
+
if (opts.relayBaseUrl && !opts.fetchImpl) {
|
|
411
|
+
throw new Error('createDefaultTransports: fetchImpl is required when relayBaseUrl is set');
|
|
412
|
+
}
|
|
413
|
+
const bc = new BroadcastChannelTransport(opts.sessionId);
|
|
414
|
+
if (!opts.relayBaseUrl || !opts.fetchImpl)
|
|
415
|
+
return bc;
|
|
416
|
+
const fetchImpl = opts.fetchImpl;
|
|
417
|
+
const relay = new HttpRelayTransport(opts.relayBaseUrl, opts.sessionId, fetchImpl);
|
|
418
|
+
const legs = [bc];
|
|
419
|
+
if (opts.myRole && (0, exports.isWebRtcSupported)()) {
|
|
420
|
+
legs.push(new WebRTCTransport(opts.sessionId, opts.relayBaseUrl, fetchImpl, opts.myRole, { onOpen: opts.onWebRtcOpen }));
|
|
421
|
+
}
|
|
422
|
+
legs.push(relay);
|
|
423
|
+
return new MultiTransport(legs);
|
|
424
|
+
};
|
|
425
|
+
exports.createDefaultTransports = createDefaultTransports;
|
|
426
|
+
//# sourceMappingURL=transports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transports.js","sourceRoot":"","sources":["../../src/cosign/transports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Loader for a single WINBIT32 vault co-signing share (`.wult`).
|
|
3
|
+
*
|
|
4
|
+
* Load ONE Orchard FROST share, then co-sign a shielded transaction with a
|
|
5
|
+
* WINBIT32 cosigner ("cosign.exe") on another device over the WB32COSIGN
|
|
6
|
+
* relay the NFPT API hosts at `/api/cosign`. Works in browsers and Node ≥ 18
|
|
7
|
+
* (atob/btoa + WebCrypto are global in both).
|
|
8
|
+
*
|
|
9
|
+
* The on-disk `.wult` format is owned by WINBIT32's `vaultWrapperFormat.js`.
|
|
10
|
+
* This module is a faithful, byte-compatible port of the *load* path so a
|
|
11
|
+
* share exported from WINBIT32 opens here unchanged:
|
|
12
|
+
*
|
|
13
|
+
* {
|
|
14
|
+
* "type": "winbit32-vault-v2",
|
|
15
|
+
* "version": 2,
|
|
16
|
+
* "vaultData": "<base64 Vultisig SDK protobuf export>",
|
|
17
|
+
* "encrypted": <bool>,
|
|
18
|
+
* "crossChainIdentity"?: { "hexChainCode", "publicKeyEcdsa" },
|
|
19
|
+
* "frost": { "orchard"?: <JSON | "salt.iv.ct">, "sapling"?: ... }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* When `encrypted` is true each FROST payload is PBKDF2-SHA-256 (600k iters) →
|
|
23
|
+
* AES-GCM-256, packed as `base64(salt).base64(iv).base64(ciphertext)`. These
|
|
24
|
+
* parameters MUST match WINBIT32 exactly, hence the constants below are not
|
|
25
|
+
* configurable.
|
|
26
|
+
*
|
|
27
|
+
* Scope note: native Vultisig `.vult` files (Orchard via the SDK's
|
|
28
|
+
* `chainKeyShares`) need the Vultisig SDK + frozto WASM to unpack and are
|
|
29
|
+
* handled in a later phase; this loader covers the `.wult` wrapper only.
|
|
30
|
+
*/
|
|
31
|
+
export declare const VAULT_V2_TYPE = "winbit32-vault-v2";
|
|
32
|
+
/** Opaque Orchard FROST key bundle (shape owned by the orchard FROST WASM). */
|
|
33
|
+
export type OrchardFrostBundle = Record<string, unknown>;
|
|
34
|
+
export interface CrossChainIdentity {
|
|
35
|
+
hexChainCode: string;
|
|
36
|
+
publicKeyEcdsa: string;
|
|
37
|
+
}
|
|
38
|
+
export interface LoadedVaultShare {
|
|
39
|
+
/** base64 Vultisig SDK protobuf export (transparent/EVM shares). */
|
|
40
|
+
sdkVaultString: string;
|
|
41
|
+
/** Decrypted Orchard FROST bundle, or null if the file carries none. */
|
|
42
|
+
orchardFrost: OrchardFrostBundle | null;
|
|
43
|
+
/** Opaque base64 Sapling FROST bundle, or null. */
|
|
44
|
+
saplingBundleBase64: string | null;
|
|
45
|
+
/** Chain code + ECDSA pubkey for deterministic Zcash/UA derivation. */
|
|
46
|
+
crossChainIdentity: CrossChainIdentity | null;
|
|
47
|
+
/** Whether the file required (and was opened with) a password. */
|
|
48
|
+
encrypted: boolean;
|
|
49
|
+
}
|
|
50
|
+
/** Cheap structural sniff for a `.wult` v2 wrapper (never throws). */
|
|
51
|
+
export declare const isWrappedVault: (content: unknown) => boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Load a `.wult` share, decrypting its FROST payloads when a password is set.
|
|
54
|
+
* Throws if the content isn't a v2 wrapper or the password is wrong.
|
|
55
|
+
*
|
|
56
|
+
* Individual payload decryption failures (e.g. a corrupt Sapling blob) leave
|
|
57
|
+
* that field null rather than aborting the whole load — matching WINBIT32 — so
|
|
58
|
+
* a usable Orchard share still opens.
|
|
59
|
+
*/
|
|
60
|
+
export declare const unwrapVaultShare: (content: string, password?: string) => Promise<LoadedVaultShare>;
|
|
61
|
+
export declare const __test_internals: {
|
|
62
|
+
frostEncrypt: (jsonStr: string, password: string) => Promise<string>;
|
|
63
|
+
frostDecrypt: (encoded: string, password: string) => Promise<string>;
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=vaultShare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vaultShare.d.ts","sourceRoot":"","sources":["../../src/cosign/vaultShare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,eAAO,MAAM,aAAa,sBAAsB,CAAC;AAGjD,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,mDAAmD;IACnD,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,uEAAuE;IACvE,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC9C,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;CACnB;AAyED,sEAAsE;AACtE,eAAO,MAAM,cAAc,YAAa,OAAO,KAAG,OAOjD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,YAAmB,MAAM,aAAa,MAAM,KAAG,QAAQ,gBAAgB,CA8CnG,CAAC;AAGF,eAAO,MAAM,gBAAgB;4BA3GQ,MAAM,YAAY,MAAM,KAAG,QAAQ,MAAM,CAAC;4BAiB1C,MAAM,YAAY,MAAM,KAAG,QAAQ,MAAM,CAAC;CA0FjB,CAAC"}
|