Ship ShadowBroker v0.9.83 with live Infonet gate messaging and DM protocols.

Gate hashchain replication, Tor/SOCKS transport hardening, terminal session teardown, v0.9.83 UI/changelog, and release digest pins for seamless updater verification.
This commit is contained in:
BigBodyCobain
2026-06-15 15:37:29 -06:00
parent 8fcb01276c
commit 5ede669a12
35 changed files with 589 additions and 263 deletions
@@ -249,6 +249,13 @@ export async function startTorHiddenService(): Promise<TorHiddenServiceSnapshot>
});
}
export async function stopTorHiddenService(): Promise<TorHiddenServiceSnapshot> {
return controlPlaneJson<TorHiddenServiceSnapshot>('/api/settings/tor/stop', {
method: 'POST',
requireAdminSession: false,
});
}
export interface InfonetSwarmJoinSnapshot {
ok?: boolean;
detail?: string;
@@ -51,6 +51,30 @@ const WORMHOLE_TRANSPORT_TIER_ORDER: Record<string, number> = {
private_strong: 3,
};
const wormholeInteractivePrepInflight = new Map<string, Promise<PreparedWormholeInteractiveLane>>();
let wormholePrepGeneration = 0;
export class WormholePrepAbortedError extends Error {
constructor() {
super('wormhole_prep_aborted');
this.name = 'WormholePrepAbortedError';
}
}
export function isWormholePrepAbortedError(error: unknown): boolean {
return error instanceof WormholePrepAbortedError
|| (error instanceof Error && error.message === 'wormhole_prep_aborted');
}
export function abortWormholeInteractivePrep(): void {
wormholePrepGeneration += 1;
wormholeInteractivePrepInflight.clear();
}
function assertWormholePrepActive(generation: number): void {
if (generation !== wormholePrepGeneration) {
throw new WormholePrepAbortedError();
}
}
export interface WormholeIdentity {
bootstrapped: boolean;
@@ -875,13 +899,16 @@ export async function prepareWormholeInteractiveLane(
return existingInflight;
}
const prepTask = (async (): Promise<PreparedWormholeInteractiveLane> => {
const generation = wormholePrepGeneration;
const timeoutMs = Math.max(
GATE_LIFECYCLE_PREP_POLL_MS,
Number(options.timeoutMs || GATE_LIFECYCLE_PREP_TIMEOUT_MS),
);
assertWormholePrepActive(generation);
let runtime = await fetchWormholeState(true).catch(() => null);
let settings = await fetchWormholeSettings(true).catch(() => null);
if (!runtime?.ready) {
assertWormholePrepActive(generation);
if (settings?.enabled || runtime?.configured) {
runtime = await connectWormhole({ requireAdminSession: false }).catch((error) => {
throw new Error(
@@ -908,9 +935,11 @@ export async function prepareWormholeInteractiveLane(
Date.now() < deadline &&
(!runtime?.ready || !wormholeTransportTierSatisfied(transportTierFromRuntime(runtime), minimumTransportTier))
) {
assertWormholePrepActive(generation);
await sleep(GATE_LIFECYCLE_PREP_POLL_MS);
runtime = await fetchWormholeState(true).catch(() => null);
}
assertWormholePrepActive(generation);
const resolvedTransportTier = transportTierFromRuntime(runtime);
if (!runtime?.ready || !wormholeTransportTierSatisfied(resolvedTransportTier, minimumTransportTier)) {
throw new Error('Wormhole is still warming up in the background.');