Bandwidth + bootstrap hardening on top of v0.7.2. Wire-compatible with
v0.7.0/v0.7.1/v0.7.2; no protocol changes.
EDM port scanner DISABLED
- hole_punch_with_scanning() now does only single quick punch + parallel
punch over 30s window. The EDM port-scanner branch is gone from the
live path because per-probe endpoint.connect() amplifies catastrophically:
iroh accumulates every connect() target into a per-endpoint paths set
and probes them all under QUIC NAT-traversal in the background. A
100-probes/sec / 5-min scan inserted ~30k paths; iroh probed all of
them. Observed at 22MB/s outbound from one client — DoS-grade.
- Scanner body preserved as edm_port_scan_disabled_v0_7_3() with all
supporting helpers (PortWalkIter, scanner_semaphore, role-based
scanner/puncher split, found_tx/found_rx channel pattern,
deadline + tokio::select! orchestration) marked #[allow(dead_code)].
Refactor target: replace per-probe endpoint.connect() with raw
socket.send_to() so probes don't enter iroh's path store.
Bootstrap probing batched
- New probe_anchors_batched() helper: 3 anchors in flight at a time,
2s stagger between batch dispatches, 10s per-anchor timeout, no abort
on success. First success unblocks the bootstrap flow; remaining
probes continue in background and fill peer connections naturally.
- Phase 2 (bootstrap fallback) still only fires when every discovered
anchor failed — preserves load-distribution intent. Replaces the
sequential 50s+ timeout cascade users observed with old data dirs.
Stale-anchor self-pruning
- New storage.get_known_anchor_last_seen() and storage.delete_known_anchor().
- maybe_prune_stale_anchor(): when a probe fails AND last_seen_ms > 3 days,
delete the entry from known_anchors immediately. Recoverable anchors
(failed once, succeeded recently) are preserved. Self-healing for old
data dirs whose discovered anchors point to keypairs that rotated
months ago.
Android close button kills NodeService
- New NodeService.stopFromNative() Kotlin static method called via JNI
from android_wifi::stop_node_service(). exit_app invokes it on Android
before app.exit(0). Previously the button ended the Activity but the
foreground service kept networking running.
Cosmetic
- Power-icon SVG (inline) replaces ⏻ so Android webviews lacking
U+23FB don't render a missing-image tofu box.
Docs
- design.html section 11 rewritten for portmapper (UPnP+NAT-PMP+PCP,
v0.7.2) including per-platform contract and bidirectional anchor
watcher.
- design.html section 10 marks session relay as opt-in (v0.7.2) and EDM
scanner as disabled-pending-refactor (v0.7.3).
- download.html carries v0.7.3 release notes.
- MEMORY.md updated; older v0.7.0/v0.7.1 status sections condensed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Network/reachability improvements + a relay-privacy fix. Wire-compatible
with v0.7.0/v0.7.1; no protocol changes.
- Replace hand-rolled UPnP (igd-next) with the portmapper crate. All three
protocols (UPnP-IGD / NAT-PMP / PCP) run in parallel, auto-renew
internally. PCP adds IPv6 firewall pinholes and works on iOS without
the multicast entitlement. Pulled in transitively via iroh already, no
net dep growth.
- Android: UPnP/PCP/NAT-PMP attempted on WiFi/Ethernet with a
WifiManager.MulticastLock acquired for the lifetime of the mapping.
Cellular skipped early (no UPnP/PCP gateway, avoid 3s discovery waste).
- TCP port-mapping gate removed for mobile — phones with permissive NAT
can now serve HTTP for direct browser fetches.
- Anchor reachability watcher (bidirectional): clears is_anchor after
>5min of no port mapping; restores it when the mapping comes back.
Network roams self-heal without restart. Mobile never auto-anchors.
- Session relay opt-in restored. relay.session_relay_enabled setting
defaults OFF (anchors included — servers shouldn't silently burn
bandwidth either). Gates both serving (can_accept_relay_pipe) and
using (auto-fallback in node.rs). UI toggle in Settings. Relay-style
signaling (RelayIntroduce / worm_lookup / N1-N3 shares) unaffected.
- URL Phase 1: share links now contain only the post ID
(itsgoin.net/p/<post>). Anchor handler already supported post-ID-only
URLs (author was optional); just dropped the author hex from the
generator. Older URLs with author hex continue to work.
- Quick app close button in header (with confirm) — useful for stopping
network activity between sessions on mobile.
- JNI null-pointer guards on ndk_context handles in android_wifi.rs.
MEMORY rule sharpened to distinguish session relay (byte pipe, opt-in)
from relay-style signaling/discovery (always on).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps:
- crates/{core,cli,tauri-app}/Cargo.toml: 0.6.2 → 0.7.0
- crates/tauri-app/tauri.conf.json: 0.6.2 → 0.7.0
- gen/android/app/tauri.properties: versionName 0.7.0, versionCode 7000
website/download.html: v0.7.0 promoted to top with FoF release notes;
v0.6.2 retained in archive section. Wire-additive notice + link to
design.html#fof for full architecture.
No -beta suffix this cycle: no users on prior version means no need
for the beta carve-out. Will resume beta convention when there are
real users to migrate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six phase commits landed for v0.6.2 (2b through 2g) plus three
pre-release fixes from the final audit pass:
- 2b: control-post flow (delete / visibility change) + retire BlobDeleteNotice
- 2c: remove audience primitive + retire PostPush / PostNotification /
AudienceRequest / AudienceResponse
- 2d: profile posts signed by the posting identity
- 2e: rich comments with ref_post_id + signed preview
- 2f: groups as a distinct primitive alongside circles
- 2g: GroupKeyDistribute → encrypted post (last persona-signed
direct push gone)
- audit fix: reject group-key distribution posts where the claimed
admin doesn't match the post author
- audit fix: cap concurrent port-scan hole punches at one (the
10 Mbps-on-VPN storm)
- audit fix: dedup concurrent outgoing connects to the same peer
Wire-breaking fork from v0.6.1. Retired message types 0x42
(PostNotification), 0x43 (PostPush), 0x44 (AudienceRequest), 0x45
(AudienceResponse), 0x95 (BlobDeleteNotice), 0xA0 (GroupKeyDistribute)
are not optional.
121/121 core tests pass.
Phases 1-5 of the Identity Architecture rollout are on master; Phase 6
(rotating DM IDs) is deferred. This bumps the protocol-breaking
release: v0.5 and v0.6 cannot interoperate.
Packaging:
- Cargo + tauri.conf: 0.5.3 -> 0.6.0
- deploy.sh: drop -beta filename suffix
- download.html: single v0.6.0 section with fork notice at the top;
changelog entry summarising the five phases and the schema migration;
Phase 6's rotating-DM-ID status noted as deferred
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge-with-key: decrypt exported posts using original identity seed, re-create
under current identity with prior_author in BlobHeader for provenance tracking.
Download page restructured with stable (v0.4.4) + beta (v0.5.0-beta) sections.
Version bumped across all crates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>